Skip to content

Commit 6ed4ccc

Browse files
authored
Merge branch 'dev' into SCRUM-304-backend-handle-user-deletion
2 parents 7d99e8b + a8d286d commit 6ed4ccc

25 files changed

Lines changed: 89273 additions & 241 deletions

File tree

Frontend/.env.example

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
2-
NUXT_CLERK_SECRET_KEY=
1+
NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY= #Reach out to admin for the Secret Key
2+
NUXT_CLERK_SECRET_KEY= #Reach out to admin for the Secret Key
33
NEST_API_URL=http://localhost:8080/
4-
ALLOWED_EMAIL_DOMAINS=example.com,another-domain.edu
4+
ALLOWED_EMAIL_DOMAINS=fhstp.ac.at

Frontend/README.md

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,64 @@
1+
# Superwise Frontend
2+
3+
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.
4+
5+
16
## Tech stack
2-
- **Nuxt** framwork for Vue
7+
- **Nuxt** framework for Vue
38
- **Vitest** for testing
4-
- **I8ln** for localisation
5-
- **Pinia** for state managment
9+
- **I18n** for localisation
10+
- **Pinia** for state management
611
- **DaisyUI** for css designs
712

13+
## Features
14+
15+
- **Authentication:** Secure sign-in and sign-out using Clerk.
16+
- **Role-based Dashboards:** Separate dashboards for students and supervisors.
17+
- **Supervision Requests:** Students can send, withdraw, and track supervision requests; supervisors can accept, reject, and manage them.
18+
- **Profile Management:** Users can edit their profiles and manage tags/interests.
19+
- **Onboarding:** Guided onboarding flows for both students and supervisors.
20+
- **Responsive Design:** Optimized for both desktop and mobile devices.
21+
- **Localization:** Multi-language support using Vue I18n.
22+
- **State Management:** Uses Pinia for global state and store management.
23+
- **API Integration:** Communicates with the backend via RESTful API endpoints.
24+
25+
## Project Structure
26+
27+
- `pages/` — Main application pages (student, supervisor, onboarding, etc.)
28+
- `components/` — Reusable Vue components (cards, modals, navigation, etc.)
29+
- `stores/` — Pinia stores for state management
30+
- `plugins/` — Nuxt plugins (e.g., Clerk, FontAwesome)
31+
- `middleware/` — Route guards and global middleware
32+
- `server/` — Nuxt backend API routes and server logic
33+
- `assets/` — Static assets (images, styles)
34+
- `locales/` — Localization files
35+
36+
## Getting Started
37+
838
## Installation and running
939

10-
1. Clone the repository
11-
2. Change into the frontend directory
40+
1. **Clone the repository to local directory**
41+
2. **ensure you are in the Frontend directory**
1242

1343
```bash
14-
cd FeMatchMaker
44+
cd Frontend
1545
```
1646

17-
3. Install dependencies:
47+
3. **Install dependencies**:
48+
1849
```bash
1950
npm install
2051
```
21-
4. Run the application
22-
```bash
23-
npm run dev
24-
```
2552

26-
## Testing with PWA
27-
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
53+
4. **Environment Variables:**
54+
55+
Copy the `.env.example` to an `.env` file in the root directory and ensure all the environment variables are set correctly. Refer to the README file in the root directory of this repository if you are unsure about the environment variables.
56+
57+
5. **Run the application**
2858
```bash
29-
npm run generate-preview
59+
npm run dev
3060
```
3161

32-
3362
## Testing
3463
To Run all the test in the application, run the command
3564
```bash

Frontend/components/ActionCard/ActionCard.vue

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,53 @@
22
import CustomButton from "../CustomButton/CustomButton.vue";
33
44
const props = defineProps({
5-
buttonText: {
6-
type: String,
7-
default: "Click Me",
8-
},
9-
cardType: {
10-
type: String,
11-
default: 'ghost',
12-
validator: (value) => !value || ["ghost", "primary"].includes(value),
13-
},
14-
headerText: {
15-
type: String,
16-
default: ''
17-
},
5+
buttonText: {
6+
type: String,
7+
default: "Click Me",
8+
},
9+
cardType: {
10+
type: String,
11+
default: 'ghost',
12+
validator: (value) => !value || ["ghost", "primary"].includes(value),
13+
},
14+
headerText: {
15+
type: String,
16+
default: ''
17+
},
1818
});
1919
2020
const emit = defineEmits(['actionButtonClicked']);
21+
2122
function emitActionEvent() {
2223
emit('actionButtonClicked');
2324
}
2425
</script>
2526

2627
<template>
27-
<div>
28-
<p v-if="props.headerText" class="mb-2 ml-4 text-lg font-bold">
29-
{{ props.headerText }}
30-
</p>
31-
<div class="card shadow-xl border border-base-300">
32-
<slot/>
33-
<!-- Action button at the bottom -->
34-
<div class="px-16 py-4 border-t border-base-300">
35-
<CustomButton
36-
v-if="props.cardType === 'ghost'"
37-
:text="props.buttonText"
38-
block
39-
color="default"
40-
variant="ghost"
41-
@click="emitActionEvent"
42-
/>
43-
<CustomButton
44-
v-else
45-
:text="props.buttonText"
46-
block
47-
color="primary"
48-
@click="emitActionEvent"
49-
/>
50-
</div>
51-
</div>
28+
<div>
29+
<p v-if="props.headerText" class="mb-2 ml-4 text-lg font-bold">
30+
{{ props.headerText }}
31+
</p>
32+
<div class="card shadow-xl border border-base-300">
33+
<slot/>
34+
<!-- Action button at the bottom -->
35+
<div class="px-8 py-4 border-t border-base-300">
36+
<CustomButton
37+
v-if="props.cardType === 'ghost'"
38+
:text="props.buttonText"
39+
block
40+
color="default"
41+
variant="ghost"
42+
@click="emitActionEvent"
43+
/>
44+
<CustomButton
45+
v-else
46+
:text="props.buttonText"
47+
block
48+
color="primary"
49+
@click="emitActionEvent"
50+
/>
51+
</div>
5252
</div>
53+
</div>
5354
</template>

Frontend/components/ConfirmationModal/ConfirmationModal.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ const handleConfirm = () => {
8686
{{ props.headline }}
8787
</h3>
8888
<div class="mx-4 mt-1">
89-
<FontAwesomeIcon :icon="props.icon"/>
89+
<FontAwesomeIcon :icon="props.icon" @click="props.icon=='xmark'? closeModal() : null"/>
9090
</div>
9191
</div>
9292

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script lang="ts" setup>
2+
3+
interface ProgressProps {
4+
progress: number;
5+
text: string;
6+
}
7+
8+
const props = defineProps<ProgressProps>();
9+
10+
</script>
11+
12+
<template>
13+
<div class="w-full h-fit flex flex-row p-6 gap-6 items-center border-b border-b-base-300">
14+
<div>
15+
<div
16+
:style="'--value:'+props.progress+';'" aria-valuenow="70"
17+
class="radial-progress bg-success text-success-content border-success border-4"
18+
role="progressbar"
19+
>
20+
{{ props.progress }}%
21+
</div>
22+
</div>
23+
<p class="text-body opacity-75">
24+
{{ props.text }}
25+
</p>
26+
</div>
27+
</template>
28+
29+
<style scoped>
30+
31+
</style>

Frontend/components/SupervisorCard/SupervisorCard.vue

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ const props = defineProps({
1919
},
2020
image: {
2121
type: String,
22-
required: true,
22+
required: false,
23+
default: '',
2324
},
2425
firstName: {
2526
type: String,
@@ -57,11 +58,11 @@ const props = defineProps({
5758
type: Number,
5859
default: 0,
5960
},
60-
dontShowStatistics: {
61+
dontShowStatistics: {
6162
type: Boolean,
6263
default: false,
6364
required: false,
64-
}
65+
}
6566
});
6667
6768
const limitedTags = computed(() =>
@@ -82,14 +83,6 @@ const cardSizeClasses = computed(() => ({
8283
'card-xl': props.fullWidth && props.size === 'xl',
8384
}));
8485
85-
const imageSizeClasses = computed(() => ({
86-
'size-8': props.size === 'xs',
87-
'size-10': props.size === 'sm',
88-
'size-12': props.size === 'md',
89-
'size-14': props.size === 'lg',
90-
'size-16': props.size === 'xl',
91-
}));
92-
9386
// Regular tag size based on card size
9487
const regularTagSize = computed(() => {
9588
switch (props.size) {
@@ -152,14 +145,13 @@ const descriptionClasses = computed(() => ({
152145
:class="cardSizeClasses" class="card bg-base-100 shadow-lg border border-base-300">
153146
<div class="card-body">
154147
<h2 class="card-title font-bold">
155-
<div class="mask mask-squircle">
156-
<img
157-
:alt="t('supervisorCard.profilePictureAlt',{firstName: props.firstName,lastName: props.lastName})"
158-
:class="imageSizeClasses"
159-
:src="props.image || getPlaceholderImage(props.firstName,props.lastName)"
160-
class="rounded-box"
161-
>
162-
</div>
148+
<Avatar
149+
:alt="t('supervisorCard.profilePictureAlt',{firstName: props.firstName,lastName: props.lastName})"
150+
:first-name="props.firstName"
151+
:last-name="props.lastName"
152+
:size="props.size"
153+
:src="props.image"
154+
/>
163155
<p class="text-large capitalize">
164156
{{ props.firstName }} {{ props.lastName }}
165157
</p>

Frontend/i18n/locales/de-DE.json

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@
1919
},
2020
"admin": {
2121
"availableSpots": "Verfügbare Plätze",
22+
"deleteUser": {
23+
"deleteButton": "Benutzer Löschen",
24+
"deleting": "Lösche...",
25+
"description": "Dies setzt das Benutzerkonto vollständig auf den nicht registrierten Zustand zurück, wobei die E-Mail-Adresse für eine erneute Registrierung erhalten bleibt.",
26+
"generalError": "Ein Fehler ist beim Zurücksetzen des Benutzers aufgetreten",
27+
"noUsersFound": "Keine Benutzer gefunden für",
28+
"permissionError": "Berechtigung verweigert - Admin-Benutzer können nicht zurückgesetzt werden",
29+
"searchInstruction": "Tippen Sie, um nach Benutzern zu suchen...",
30+
"searchPlaceholder": "Benutzer nach Name, E-Mail oder Rolle suchen...",
31+
"selectUserError": "Bitte wählen Sie einen Benutzer zum Löschen aus",
32+
"selectedUser": "Ausgewählter Benutzer:",
33+
"title": "Benutzer Löschen",
34+
"userNotFoundError": "Benutzer nicht gefunden"
35+
},
2236
"downloadDescription": "Laden Sie die bestätigten Betreuer-Studenten-Paare herunter",
2337
"downloadFileName": "lade confirmed_supervisions.csv herunter",
2438
"downloadTitle": "Bestätigte Betreuungen herunterladen",
@@ -151,6 +165,10 @@
151165
"supervising": "Sie betreuen {firstName}"
152166
},
153167
"dashboard": {
168+
"progress": {
169+
"button": "Profil vervollständigen...",
170+
"text": "Dein Profil ist fast vollständig! Füge die letzten dinge hinzu für die beste SuperWise erfahrung!"
171+
},
154172
"student": {
155173
"downloadConfirmation": "Bestätigung herunterladen",
156174
"findSupervisor": "Finde jetzt deinen Betreuer!",
@@ -220,6 +238,8 @@
220238
"loading": "Lädt",
221239
"logoAlt": "Logo",
222240
"mail": "E-Mail",
241+
"manageRequest": "Anfrage verwalten",
242+
"addStudent": "Als Betreute*r hinzufügen",
223243
"noVideoSupport": "Dein Browser unterstützt kein HTML-Video... ich denke, es ist Zeit für ein Upgrade deines Geräts!",
224244
"pendingRequestTo": "Ausstehende Anfrage an",
225245
"profile": "Profil",
@@ -279,7 +299,18 @@
279299
"supervisionInfo": "Wenn du eine Anfrage zur Betreuung einer Abschlussarbeit sendest, wird diese an die ausgewählten Betreuenden weitergeleitet. Sie können dann entscheiden, ob sie die Anfrage annehmen oder ablehnen möchten. Wenn sie die Anfrage annehmen, wird eine Bestätigung erstellt, die du herunterladen kannst.",
280300
"withdrawSupervisionConfirm": "Anfrage zurückziehen",
281301
"withdrawSupervisionDescription": "Möchten Sie die Betreuungsanfrage von {name} zurückziehen? Nach dem Zurückziehen kann der Betreuer diese Anfrage nicht mehr sehen.",
282-
"withdrawSupervisionHeadline": "Betreuungsanfrage zurückziehen"
302+
"withdrawSupervisionHeadline": "Betreuungsanfrage zurückziehen",
303+
"handleRequest": {
304+
"accept": "Anfrage annehmen",
305+
"dismiss": "Anfrage ablehnen",
306+
"description": "{firstName} {lastName} hat eine ausstehende Anfrage zur Betreuung. Möchten Sie diese Anfrage annehmen oder ablehnen?",
307+
"headline": "Ausstehende Betreuungsanfrage"
308+
},
309+
"supervisee": {
310+
"accept": "Als Betreuer hinzufügen",
311+
"headline": "Student als Betreuer hinzufügen",
312+
"description": "Das Hinzufügen eines Studenten als Betreuer überspringt den Bestätigungsprozess und fügt ihn direkt zu deinen betreuten Studenten hinzu. Möchtest du fortfahren?"
313+
}
283314
},
284315
"multiStepForm": {
285316
"description": {
@@ -383,7 +414,8 @@
383414
},
384415
"noResults": "Keine Suchergebnisse...",
385416
"placeholderForStudents": "Betreuer suchen...",
386-
"placeholderForSupervisors": "Studenten suchen..."
417+
"placeholderForSupervisors": "Studenten suchen...",
418+
"placeholderForAdmins": "Benutzer suchen..."
387419
},
388420
"searchBar": {
389421
"noResults": "Keine Ergebnisse gefunden"
@@ -475,6 +507,10 @@
475507
},
476508
"toast": {
477509
"withdrawRequestFailed": "Fehler beim Zurückziehen der Betreuungsanfrage",
478-
"withdrawnRequest": "Sie haben die Betreuungsanfrage zurückgezogen"
510+
"withdrawnRequest": "Sie haben die Betreuungsanfrage zurückgezogen",
511+
"withdrawnStudentRequest": "Die Anfrage des Studierenden wurde abgelehnt",
512+
"acceptedStudentRequest": "Die Anfrage des Studierenden wurde angenommen",
513+
"somethingWentWrong": "Etwas ist schief gelaufen, bitte versuchen Sie es später noch einmal",
514+
"addedStudentAsSupervisee": "Student wurde als Betreuer hinzugefügt"
479515
}
480516
}

0 commit comments

Comments
 (0)