Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Frontend/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
NUXT_CLERK_SECRET_KEY=
NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY= #Reach out to admin for the Secret Key
NUXT_CLERK_SECRET_KEY= #Reach out to admin for the Secret Key
NEST_API_URL=http://localhost:8080/
ALLOWED_EMAIL_DOMAINS=example.com,another-domain.edu
ALLOWED_EMAIL_DOMAINS=fhstp.ac.at
59 changes: 44 additions & 15 deletions Frontend/README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,64 @@
# Superwise Frontend

This is the frontend application for the Superwise project, built with Nuxt 3, Vue 3, Pinia, and TailwindCSS. It provides a modern, responsive interface for students and supervisors to manage supervision requests, profiles, and onboarding.


## Tech stack
- **Nuxt** framwork for Vue
- **Nuxt** framework for Vue
- **Vitest** for testing
- **I8ln** for localisation
- **Pinia** for state managment
- **I18n** for localisation
- **Pinia** for state management
- **DaisyUI** for css designs

## Features

- **Authentication:** Secure sign-in and sign-out using Clerk.
- **Role-based Dashboards:** Separate dashboards for students and supervisors.
- **Supervision Requests:** Students can send, withdraw, and track supervision requests; supervisors can accept, reject, and manage them.
- **Profile Management:** Users can edit their profiles and manage tags/interests.
- **Onboarding:** Guided onboarding flows for both students and supervisors.
- **Responsive Design:** Optimized for both desktop and mobile devices.
- **Localization:** Multi-language support using Vue I18n.
- **State Management:** Uses Pinia for global state and store management.
- **API Integration:** Communicates with the backend via RESTful API endpoints.

## Project Structure

- `pages/` — Main application pages (student, supervisor, onboarding, etc.)
- `components/` — Reusable Vue components (cards, modals, navigation, etc.)
- `stores/` — Pinia stores for state management
- `plugins/` — Nuxt plugins (e.g., Clerk, FontAwesome)
- `middleware/` — Route guards and global middleware
- `server/` — Nuxt backend API routes and server logic
- `assets/` — Static assets (images, styles)
- `locales/` — Localization files

## Getting Started

## Installation and running

1. Clone the repository
2. Change into the frontend directory
1. **Clone the repository to local directory**
2. **ensure you are in the Frontend directory**

```bash
cd FeMatchMaker
cd Frontend
```

3. Install dependencies:
3. **Install dependencies**:

```bash
npm install
```
4. Run the application
```bash
npm run dev
```

## Testing with PWA
The PWA module is not fully compataibile with hot module replacement due to caching and other "middle man" functionalities. As a result whenever testing with PWA run the following command to boot the applicaiton
4. **Environment Variables:**

Copy the `.env.example` to an `.env` file in the root directory and ensure all the environment variables are set correctly. You can reach out to the admin for the secret keys.

5. **Run the application**
```bash
npm run generate-preview
npm run dev
```


## Testing
To Run all the test in the application, run the command
```bash
Expand Down
77 changes: 39 additions & 38 deletions Frontend/components/ActionCard/ActionCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,53 @@
import CustomButton from "../CustomButton/CustomButton.vue";

const props = defineProps({
buttonText: {
type: String,
default: "Click Me",
},
cardType: {
type: String,
default: 'ghost',
validator: (value) => !value || ["ghost", "primary"].includes(value),
},
headerText: {
type: String,
default: ''
},
buttonText: {
type: String,
default: "Click Me",
},
cardType: {
type: String,
default: 'ghost',
validator: (value) => !value || ["ghost", "primary"].includes(value),
},
headerText: {
type: String,
default: ''
},
});

const emit = defineEmits(['actionButtonClicked']);

function emitActionEvent() {
emit('actionButtonClicked');
}
</script>

<template>
<div>
<p v-if="props.headerText" class="mb-2 ml-4 text-lg font-bold">
{{ props.headerText }}
</p>
<div class="card shadow-xl border border-base-300">
<slot/>
<!-- Action button at the bottom -->
<div class="px-16 py-4 border-t border-base-300">
<CustomButton
v-if="props.cardType === 'ghost'"
:text="props.buttonText"
block
color="default"
variant="ghost"
@click="emitActionEvent"
/>
<CustomButton
v-else
:text="props.buttonText"
block
color="primary"
@click="emitActionEvent"
/>
</div>
</div>
<div>
<p v-if="props.headerText" class="mb-2 ml-4 text-lg font-bold">
{{ props.headerText }}
</p>
<div class="card shadow-xl border border-base-300">
<slot/>
<!-- Action button at the bottom -->
<div class="px-8 py-4 border-t border-base-300">
<CustomButton
v-if="props.cardType === 'ghost'"
:text="props.buttonText"
block
color="default"
variant="ghost"
@click="emitActionEvent"
/>
<CustomButton
v-else
:text="props.buttonText"
block
color="primary"
@click="emitActionEvent"
/>
</div>
</div>
</div>
</template>
4 changes: 3 additions & 1 deletion Frontend/components/AdminHeader/AdminHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const router = useRouter();
const colorMode = useColorMode();

interface Props {
variant?: "default" | "upload" | "download" | "delete" | "text";
variant?: "default" | "upload" | "download" | "delete" | "text" | "warning";
headerText: string;
rightButton?: string;
rightIcon?: string;
Expand All @@ -25,13 +25,15 @@ const headerBG = computed(() => ({
'bg-info': props.variant === 'upload',
'bg-success': props.variant === 'download',
'bg-error': props.variant === 'delete',
'bg-warning': props.variant === 'warning',
}));

const colorText = computed(() => ({
'text-base-content': props.variant === 'default' || props.variant === 'text',
'text-info-content': props.variant === 'upload',
'text-success-content': props.variant === 'download',
'text-error-content': props.variant === 'delete',
'text-warning-content': props.variant === 'warning',
}));

const goBack = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const handleConfirm = () => {
{{ props.headline }}
</h3>
<div class="mx-4 mt-1">
<FontAwesomeIcon :icon="props.icon"/>
<FontAwesomeIcon :icon="props.icon" @click="props.icon=='xmark'? closeModal() : null"/>
</div>
</div>

Expand Down
31 changes: 31 additions & 0 deletions Frontend/components/Progress/Progress.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script lang="ts" setup>

interface ProgressProps {
progress: number;
text: string;
}

const props = defineProps<ProgressProps>();

</script>

<template>
<div class="w-full h-fit flex flex-row p-6 gap-6 items-center border-b border-b-base-300">
<div>
<div
:style="'--value:'+props.progress+';'" aria-valuenow="70"
class="radial-progress bg-success text-success-content border-success border-4"
role="progressbar"
>
{{ props.progress }}%
</div>
</div>
<p class="text-body opacity-75">
{{ props.text }}
</p>
</div>
</template>

<style scoped>

</style>
Loading