Skip to content

Commit 4f3c6a3

Browse files
FelixTeutschjb-cc
andauthored
feat(Frontend): add add admin logic (SCRUM-306) (#200)
Co-authored-by: jb-cc <115902941+jb-cc@users.noreply.github.com>
1 parent aafcc97 commit 4f3c6a3

9 files changed

Lines changed: 325 additions & 66 deletions

File tree

Frontend/components/AdminHeader/AdminHeader.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const router = useRouter();
77
const colorMode = useColorMode();
88
99
interface Props {
10-
variant?: "default" | "upload" | "download" | "delete" | "text";
10+
variant?: "default" | "upload" | "download" | "delete" | "text" | "warning";
1111
headerText: string;
1212
rightButton?: string;
1313
rightIcon?: string;
@@ -25,13 +25,15 @@ const headerBG = computed(() => ({
2525
'bg-info': props.variant === 'upload',
2626
'bg-success': props.variant === 'download',
2727
'bg-error': props.variant === 'delete',
28+
'bg-warning': props.variant === 'warning',
2829
}));
2930
3031
const colorText = computed(() => ({
3132
'text-base-content': props.variant === 'default' || props.variant === 'text',
3233
'text-info-content': props.variant === 'upload',
3334
'text-success-content': props.variant === 'download',
3435
'text-error-content': props.variant === 'delete',
36+
'text-warning-content': props.variant === 'warning',
3537
}));
3638
3739
const goBack = () => {

Frontend/components/SupervisorStudentList/ValidatedMailInput.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts" setup>
2-
import {FontAwesomeIcon} from "@fortawesome/vue-fontawesome";
3-
import {ref, watchEffect} from 'vue';
2+
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
3+
import { ref, watchEffect } from 'vue';
44
55
interface ValidatedMailInput {
66
placeholder: string;
@@ -56,6 +56,7 @@ function handleBlur(event: FocusEvent): void {
5656
@blur="handleBlur"
5757
@input="handleInput"
5858
>
59+
5960
<span class="text-body opacity-75 pr-4">
6061
@{{ props.domain }}
6162
</span>

Frontend/components/Toast/Toast.vue

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,87 @@
11
<script lang="ts" setup>
2-
import {FontAwesomeIcon} from "@fortawesome/vue-fontawesome";
3-
import {computed, onBeforeUnmount, onMounted, ref} from 'vue';
2+
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
3+
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
44
55
const props = defineProps({
6-
type: {
7-
type: String,
8-
default: "success",
9-
validator: (value) => ["success", "error", "exception"].includes(value as string),
10-
},
11-
message: {
12-
type: String,
13-
default: "Chat request has been sent",
14-
},
15-
duration: {
16-
type: Number,
17-
default: 3000,
18-
},
19-
buttonText: {
20-
type: String,
21-
default: "close",
22-
}
6+
type: {
7+
type: String,
8+
default: "success",
9+
validator: (value) => [ "success", "error", "exception" ].includes(value as string),
10+
},
11+
message: {
12+
type: String,
13+
default: "Chat request has been sent",
14+
},
15+
duration: {
16+
type: Number,
17+
default: 3000,
18+
},
19+
buttonText: {
20+
type: String,
21+
default: "close",
22+
}
2323
});
2424
25-
const emit = defineEmits(['buttonClick', 'close']);
25+
const emit = defineEmits([ 'buttonClick', 'close' ]);
2626
2727
// Internal visibility state
2828
const visible = ref(true);
2929
3030
// Helper function to get the correct alert class based on type - now as computed property
3131
const alertClass = computed(() => ({
32-
'alert-success': props.type === 'success' || props.type === undefined,
33-
'alert-error': props.type === 'error' || props.type === 'exception',
32+
'alert-success': props.type === 'success' || props.type === undefined,
33+
'alert-error': props.type === 'error' || props.type === 'exception',
3434
}));
3535
3636
3737
// Get the actual icon name as a string
3838
const iconName = computed(() => {
39-
if (props.type === 'error') return 'ban';
40-
if (props.type === 'exception') return 'triangle-exclamation';
41-
return 'check'; // default for success
39+
if (props.type === 'error') return 'ban';
40+
if (props.type === 'exception') return 'triangle-exclamation';
41+
return 'check'; // default for success
4242
});
4343
4444
// Auto-close toast after duration by changing internal visibility
4545
let timeoutId: ReturnType<typeof setTimeout> | null = null;
4646
onMounted(() => {
47-
if (props.duration > 0) {
48-
timeoutId = setTimeout(() => {
49-
emit('close');
50-
visible.value = false;
51-
}, props.duration);
52-
}
47+
if (props.duration > 0) {
48+
timeoutId = setTimeout(() => {
49+
emit('close');
50+
visible.value = false;
51+
}, props.duration);
52+
}
5353
});
5454
5555
onBeforeUnmount(() => {
56-
if (timeoutId !== null) {
57-
clearTimeout(timeoutId);
58-
}
56+
if (timeoutId !== null) {
57+
clearTimeout(timeoutId);
58+
}
5959
});
6060
// Just emit the event, don't change visibility
6161
const handleButtonClick = () => {
62-
emit('buttonClick');
62+
emit('buttonClick');
6363
};
6464
</script>
6565

6666
<template>
67+
<div
68+
v-if="visible"
69+
class="fixed bottom-18 left-0 right-0 flex justify-center z-50 px-8"
70+
>
6771
<div
68-
v-if="visible"
69-
class="fixed bottom-18 left-0 right-0 flex justify-center z-50 px-12"
70-
>
71-
<div
72-
:class="alertClass"
73-
class="alert w-full shadow-lg flex alert-soft"
74-
role="alert">
75-
<FontAwesomeIcon :icon="iconName" class="text-xl"/>
76-
<span class="w-full">{{ message }}</span>
77-
<CustomButton
78-
:text="buttonText"
79-
:color="props.type === 'success' ? 'success' : 'error'"
80-
variant="outline"
81-
@click="handleButtonClick"
82-
/>
83-
</div>
72+
:class="alertClass"
73+
class="alert w-full !shadow-lg flex alert-soft"
74+
role="alert">
75+
<FontAwesomeIcon :icon="iconName" class="text-xl"/>
76+
<span class="w-full">{{ message }}</span>
77+
<CustomButton
78+
:color="props.type === 'success' ? 'success' : 'error'"
79+
:text="buttonText"
80+
variant="outline"
81+
@click="handleButtonClick"
82+
/>
8483
</div>
84+
</div>
8585
</template>
8686

8787
<style scoped>

Frontend/components/inputField/InputField.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ const props = defineProps({
3535
type: Boolean,
3636
default: false,
3737
},
38+
required: {
39+
type: Boolean,
40+
default: false,
41+
}
3842
});
3943
const isClearIcon = computed(() => props.rightIcon === "xmark");
4044
@@ -78,7 +82,7 @@ function handleRightIconClick() {
7882
v-if="props.label.length > 0"
7983
class="fieldset-legend text-sm font-semibold mb-1 opacity-50 my-0 py-1"
8084
>
81-
{{ label }}
85+
{{ label + (required ? '*' : '') }}
8286
</legend>
8387

8488
<div class="input-container">

Frontend/i18n/locales/de-DE.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
11
{
2+
"add-admin": {
3+
"add-admin": "Admin hinzufügen",
4+
"inputMissing": "Bitte fülle alle felder aus!",
5+
"modal": {
6+
"text": "Bist du dir sicher das du {firstName} {lastName} mit der mail Adresse {mail} admin machen willst?"
7+
},
8+
"text": "Durch das Hinzufügen eines weiteren admins bekommt diese person die gleiche lese, schreibe und lösch rechte wie du! Füge nur jemand als Admin dazu, falls das wirklich gewollt ist! Diese aktion kann nicht rückgängig gemacht werden!",
9+
"title": "Füge einen Admin hinzu",
10+
"toast": {
11+
"error": {
12+
"400": "Falsche Mail Domain, fehlendes Feld, oder nutzer bereits registriert.",
13+
"403": "Nur bereits existierende Admins dürfen einen neuen admin account erstellen",
14+
"409": "Es existiert bereits ein nutzer mit dieser Mail!",
15+
"generic": "Es ist ein fehler aufgetreten. Bitte versuche es später erneut..."
16+
},
17+
"message": "Ein neuer Admin wurde hinzugefügt!"
18+
}
19+
},
220
"admin": {
321
"availableSpots": "Verfügbare Plätze",
422
"downloadDescription": "Laden Sie die bestätigten Betreuer-Studenten-Paare herunter",
@@ -15,6 +33,7 @@
1533
"waitingStudents": "warten derzeit auf die Genehmigung der Betreuung"
1634
},
1735
"appHeader": {
36+
"addAdmin": "Admin Hinzufügen",
1837
"admin": {
1938
"deleteData": "Delete Data",
2039
"downloadData": "Daten Herunterladen",
@@ -169,6 +188,7 @@
169188
"generic": {
170189
"404-not-found": "404 - Nicht gefunden",
171190
"acceptedRequestTo": "Akzeptierte Anfrage an",
191+
"addAdmin": "Neuen Admin Hinzufügen",
172192
"admin": "Admin",
173193
"cancel": "Abbrechen",
174194
"chatRequest": "Chat-Anfrage",

Frontend/i18n/locales/en-GB.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
11
{
2+
"add-admin": {
3+
"add-admin": "Add Admin",
4+
"inputMissing": "Please make sure that all fields are filled out!",
5+
"modal": {
6+
"text": "Are you sure you want to make {firstName} {lastName} with the mail {mail} admin?"
7+
},
8+
"text": "By adding another admin, you are allowing them to have the same read, write and delete access as you! Make sure you only do this if wanted. This action can not be undone!",
9+
"title": "Add an admin",
10+
"toast": {
11+
"error": {
12+
"400": "Invalid email domain, missing required fields, or user already exists",
13+
"403": "Only existing admins can create new admin accounts",
14+
"409": "User with this email already exists",
15+
"generic": "An error has occured. Try again later..."
16+
},
17+
"message": "A new admin has been added"
18+
}
19+
},
220
"admin": {
321
"availableSpots": "Available spots",
422
"downloadDescription": "Download the confirmed Supervisor - Student pairs",
@@ -15,6 +33,7 @@
1533
"waitingStudents": "are currently waiting for supervision approval"
1634
},
1735
"appHeader": {
36+
"addAdmin": "Add Admin",
1837
"admin": {
1938
"deleteData": "Delete Data",
2039
"downloadData": "Download Data",
@@ -169,6 +188,7 @@
169188
"generic": {
170189
"404-not-found": "404 - Not Found",
171190
"acceptedRequestTo": "Accepted request to",
191+
"addAdmin": "Add new Admin",
172192
"admin": "Admin",
173193
"cancel": "Cancel",
174194
"chatRequest": "Chat request",

Frontend/layouts/GenericBackLayout.vue

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,24 @@ const headerText = computed(() => {
2222
download: t("appHeader.admin.downloadData"),
2323
upload: t("appHeader.admin.uploadData"),
2424
delete: t("appHeader.admin.deleteData"),
25-
'new-cycle': t("appHeader.admin.newCycle"),
25+
"new-cycle": t("appHeader.admin.newCycle"),
26+
"add-admin": t("appHeader.addAdmin"),
2627
}[currentPage] || t("nav.defaultHeader")
2728
);
2829
});
2930
3031
const getVariant = computed(
31-
(): "default" | "upload" | "download" | "delete" | "text" | undefined => {
32-
const breadCrumbs: string[] = route.path.substring(1).split("/");
33-
const currentPage = breadCrumbs.pop() || "";
34-
if (breadCrumbs[0].includes("admin")) {
35-
const variant = {
36-
download: "download",
37-
upload: "upload",
38-
delete: "delete",
39-
'new-cycle': "delete"
40-
}[currentPage] as "download" | "upload" | "delete" | undefined;
32+
(): "default" | "upload" | "download" | "delete" | "warning" |"text" | undefined => {
33+
const breadCrumbs: string[] = route.path.substring(1).split("/");
34+
const currentPage = breadCrumbs.pop() || "";
35+
if (breadCrumbs[0].includes("admin")) {
36+
const variant = {
37+
download: "download",
38+
upload: "upload",
39+
delete: "delete",
40+
"new-cycle": "delete",
41+
"add-admin": "warning",
42+
}[currentPage] as "download" | "upload" | "delete" | "warning" | undefined;
4143
4244
return variant || "default";
4345
}

0 commit comments

Comments
 (0)