feat: extra vertalingen
This commit is contained in:
		
							parent
							
								
									149e4e80fc
								
							
						
					
					
						commit
						c4f178aa52
					
				
					 6 changed files with 320 additions and 280 deletions
				
			
		|  | @ -165,5 +165,21 @@ | ||||||
|     "pathContainsNonExistingLearningObjects": "Mindestens eines der in diesem Pfad referenzierten Lernobjekte existiert nicht.", |     "pathContainsNonExistingLearningObjects": "Mindestens eines der in diesem Pfad referenzierten Lernobjekte existiert nicht.", | ||||||
|     "targetAgesMandatory": "Zielalter müssen angegeben werden.", |     "targetAgesMandatory": "Zielalter müssen angegeben werden.", | ||||||
|     "hintRemoveIfUnconditionalTransition": "(entfernen, wenn dies ein bedingungsloser Übergang sein soll)", |     "hintRemoveIfUnconditionalTransition": "(entfernen, wenn dies ein bedingungsloser Übergang sein soll)", | ||||||
|     "hintKeywordsSeparatedBySpaces": "Schlüsselwörter durch Leerzeichen getrennt" |     "hintKeywordsSeparatedBySpaces": "Schlüsselwörter durch Leerzeichen getrennt", | ||||||
|  |     "title-required": "Titel darf nicht leer sein.", | ||||||
|  |     "class-required": "Du musst eine Klasse auswählen.", | ||||||
|  |     "deadline-invalid": "Ungültiges Datum oder Uhrzeit.", | ||||||
|  |     "deadline-past": "Die Frist muss in der Zukunft liegen.", | ||||||
|  |     "lp-required": "Du musst einen Lernpfad auswählen.", | ||||||
|  |     "lp-invalid": "Der ausgewählte Lernpfad existiert nicht.", | ||||||
|  |     "currently-no-groups": "Es gibt keine Gruppen für diese Aufgabe.", | ||||||
|  |     "random-grouping": "Gruppen zufällig erstellen", | ||||||
|  |     "drag-and-drop": "Gruppen manuell erstellen", | ||||||
|  |     "generate-groups": "erzeugen", | ||||||
|  |     "auto-generate-groups": "Gruppen gleicher Größe erstellen", | ||||||
|  |     "preview": "Vorschau", | ||||||
|  |     "current-groups": "Aktuelle Gruppen", | ||||||
|  |     "group-size-label": "Gruppengröße", | ||||||
|  |     "save": "Speichern", | ||||||
|  |     "unassigned": "Nicht zugewiesen" | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -168,7 +168,7 @@ | ||||||
|     "hintRemoveIfUnconditionalTransition": "(remove this if this should be an unconditional transition)", |     "hintRemoveIfUnconditionalTransition": "(remove this if this should be an unconditional transition)", | ||||||
|     "hintKeywordsSeparatedBySpaces": "Keywords separated by spaces", |     "hintKeywordsSeparatedBySpaces": "Keywords separated by spaces", | ||||||
|     "title-required": "Title cannot be empty.", |     "title-required": "Title cannot be empty.", | ||||||
|     "class-required": "You must select at least one class.", |     "class-required": "You must select a class.", | ||||||
|     "deadline-invalid": "Invalid date or time.", |     "deadline-invalid": "Invalid date or time.", | ||||||
|     "deadline-past": "The deadline must be in the future.", |     "deadline-past": "The deadline must be in the future.", | ||||||
|     "lp-required": "You must select a learning path.", |     "lp-required": "You must select a learning path.", | ||||||
|  |  | ||||||
|  | @ -88,7 +88,7 @@ | ||||||
|     "deny": "refuser", |     "deny": "refuser", | ||||||
|     "sent": "envoyé", |     "sent": "envoyé", | ||||||
|     "failed": "échoué", |     "failed": "échoué", | ||||||
|     "wrong": "quelque chose n'a pas fonctionné", |     "wrong": "Il y a une erreur", | ||||||
|     "created": "créé", |     "created": "créé", | ||||||
|     "callbackLoading": "Vous serez connecté...", |     "callbackLoading": "Vous serez connecté...", | ||||||
|     "loginUnexpectedError": "La connexion a échoué", |     "loginUnexpectedError": "La connexion a échoué", | ||||||
|  | @ -98,7 +98,7 @@ | ||||||
|     "groupSubmissions": "Soumissions de ce groupe", |     "groupSubmissions": "Soumissions de ce groupe", | ||||||
|     "taskCompleted": "Tâche terminée.", |     "taskCompleted": "Tâche terminée.", | ||||||
|     "submittedBy": "Soumis par", |     "submittedBy": "Soumis par", | ||||||
|     "timestamp": "Horodatage", |     "timestamp": "Date et heure", | ||||||
|     "loadSubmission": "Charger", |     "loadSubmission": "Charger", | ||||||
|     "noSubmissionsYet": "Pas encore de soumissions.", |     "noSubmissionsYet": "Pas encore de soumissions.", | ||||||
|     "viewAsGroup": "Voir la progression du groupe...", |     "viewAsGroup": "Voir la progression du groupe...", | ||||||
|  | @ -166,5 +166,21 @@ | ||||||
|     "pathContainsNonExistingLearningObjects": "Au moins un des objets d’apprentissage référencés dans ce chemin n’existe pas.", |     "pathContainsNonExistingLearningObjects": "Au moins un des objets d’apprentissage référencés dans ce chemin n’existe pas.", | ||||||
|     "targetAgesMandatory": "Les âges cibles doivent être spécifiés.", |     "targetAgesMandatory": "Les âges cibles doivent être spécifiés.", | ||||||
|     "hintRemoveIfUnconditionalTransition": "(supprimer ceci s’il s’agit d’une transition inconditionnelle)", |     "hintRemoveIfUnconditionalTransition": "(supprimer ceci s’il s’agit d’une transition inconditionnelle)", | ||||||
|     "hintKeywordsSeparatedBySpaces": "Mots-clés séparés par des espaces" |     "hintKeywordsSeparatedBySpaces": "Mots-clés séparés par des espaces", | ||||||
|  |     "title-required": "Le titre ne peut pas être vide.", | ||||||
|  |     "class-required": "Vous devez sélectionner une classe.", | ||||||
|  |     "deadline-invalid": "Date ou heure invalide.", | ||||||
|  |     "deadline-past": "La date limite doit être dans le futur.", | ||||||
|  |     "lp-required": "Vous devez sélectionner un parcours d'apprentissage.", | ||||||
|  |     "lp-invalid": "Le parcours d'apprentissage sélectionné n'existe pas.", | ||||||
|  |     "currently-no-groups": "Il n’y a pas de groupes pour cette tâche.", | ||||||
|  |     "random-grouping": "Créer des groupes aléatoirement", | ||||||
|  |     "drag-and-drop": "Créer des groupes manuellement", | ||||||
|  |     "generate-groups": "générer", | ||||||
|  |     "auto-generate-groups": "Créer des groupes de taille égale", | ||||||
|  |     "preview": "Aperçu", | ||||||
|  |     "current-groups": "Groupes actuels", | ||||||
|  |     "group-size-label": "Taille des groupes", | ||||||
|  |     "save": "Enregistrer", | ||||||
|  |     "unassigned": "Non assigné" | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -165,5 +165,21 @@ | ||||||
|     "pathContainsNonExistingLearningObjects": "Ten minste één van de leerobjecten in dit pad bestaat niet.", |     "pathContainsNonExistingLearningObjects": "Ten minste één van de leerobjecten in dit pad bestaat niet.", | ||||||
|     "targetAgesMandatory": "Doelleeftijden moeten worden opgegeven.", |     "targetAgesMandatory": "Doelleeftijden moeten worden opgegeven.", | ||||||
|     "hintRemoveIfUnconditionalTransition": "(verwijder dit voor onvoorwaardelijke overgangen)", |     "hintRemoveIfUnconditionalTransition": "(verwijder dit voor onvoorwaardelijke overgangen)", | ||||||
|     "hintKeywordsSeparatedBySpaces": "Trefwoorden gescheiden door spaties" |     "hintKeywordsSeparatedBySpaces": "Trefwoorden gescheiden door spaties", | ||||||
|  |     "title-required": "Titel mag niet leeg zijn.", | ||||||
|  |     "class-required": "Je moet een klas selecteren.", | ||||||
|  |     "deadline-invalid": "Ongeldige datum of tijd.", | ||||||
|  |     "deadline-past": "De deadline moet in de toekomst liggen.", | ||||||
|  |     "lp-required": "Je moet een leerpad selecteren.", | ||||||
|  |     "lp-invalid": "Het geselecteerde leerpad bestaat niet.", | ||||||
|  |     "currently-no-groups": "Er zijn geen groepen voor deze opdracht.", | ||||||
|  |     "random-grouping": "Groepeer willekeurig", | ||||||
|  |     "drag-and-drop": "Stel groepen handmatig samen", | ||||||
|  |     "generate-groups": "genereren", | ||||||
|  |     "auto-generate-groups": "Maak groepen van gelijke grootte", | ||||||
|  |     "preview": "Voorbeeld", | ||||||
|  |     "current-groups": "Huidige groepen", | ||||||
|  |     "group-size-label": "Grootte van groepen", | ||||||
|  |     "save": "Opslaan", | ||||||
|  |     "unassigned": "Niet toegewezen" | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,50 +1,46 @@ | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import {ref, computed, watchEffect} from "vue"; |     import { ref, computed, watchEffect } from "vue"; | ||||||
| import auth from "@/services/auth/auth-service.ts"; |     import auth from "@/services/auth/auth-service.ts"; | ||||||
| import {useI18n} from "vue-i18n"; |     import { useI18n } from "vue-i18n"; | ||||||
| import UsingQueryResult from "@/components/UsingQueryResult.vue"; |     import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||||
| import type {AssignmentsResponse} from "@/controllers/assignments.ts"; |     import { asyncComputed } from "@vueuse/core"; | ||||||
| import {asyncComputed} from "@vueuse/core"; |     import { | ||||||
| import { |  | ||||||
|         useStudentAssignmentsQuery, |         useStudentAssignmentsQuery, | ||||||
|         useStudentGroupsQuery, |         useStudentGroupsQuery, | ||||||
|     useStudentsByUsernamesQuery |         useStudentsByUsernamesQuery, | ||||||
| } from "@/queries/students.ts"; |     } from "@/queries/students.ts"; | ||||||
| import {useGetLearningPathQuery} from "@/queries/learning-paths.ts"; |     import { useGetLearningPathQuery } from "@/queries/learning-paths.ts"; | ||||||
| import type {Language} from "@/data-objects/language.ts"; |     import type { Language } from "@/data-objects/language.ts"; | ||||||
| import {calculateProgress} from "@/utils/assignment-utils.ts"; |     import { calculateProgress } from "@/utils/assignment-utils.ts"; | ||||||
| import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts"; |     import type { LearningPath } from "@/data-objects/learning-paths/learning-path.ts"; | ||||||
| 
 | 
 | ||||||
| const props = defineProps<{ |     const props = defineProps<{ | ||||||
|         classId: string; |         classId: string; | ||||||
|         assignmentId: number; |         assignmentId: number; | ||||||
| }>(); |     }>(); | ||||||
| 
 | 
 | ||||||
| const {t} = useI18n(); |     const { t } = useI18n(); | ||||||
| const lang = ref(); |     const lang = ref(); | ||||||
| const learningPath = ref(); |     const learningPath = ref(); | ||||||
| // Get the user's username/id |     // Get the user's username/id | ||||||
| const username = asyncComputed(async () => { |     const username = asyncComputed(async () => { | ||||||
|         const user = await auth.loadUser(); |         const user = await auth.loadUser(); | ||||||
|         return user?.profile?.preferred_username ?? undefined; |         return user?.profile?.preferred_username ?? undefined; | ||||||
| }); |     }); | ||||||
| 
 | 
 | ||||||
| const assignmentsQueryResult = useStudentAssignmentsQuery(username, true); |     const assignmentsQueryResult = useStudentAssignmentsQuery(username, true); | ||||||
| 
 | 
 | ||||||
| const assignment = computed(() => { |     const assignment = computed(() => { | ||||||
|         const assignments = assignmentsQueryResult.data.value?.assignments; |         const assignments = assignmentsQueryResult.data.value?.assignments; | ||||||
|         if (!assignments) return undefined; |         if (!assignments) return undefined; | ||||||
| 
 | 
 | ||||||
|     return assignments.find( |         return assignments.find((a) => a.id === props.assignmentId && a.within === props.classId); | ||||||
|         (a) => a.id === props.assignmentId && a.within === props.classId |     }); | ||||||
|     ); |  | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
|  |     learningPath.value = assignment.value?.learningPath; | ||||||
| 
 | 
 | ||||||
| learningPath.value = assignment.value?.learningPath; |     const groupsQueryResult = useStudentGroupsQuery(username, true); | ||||||
| 
 |     const group = computed(() => { | ||||||
| const groupsQueryResult = useStudentGroupsQuery(username, true); |  | ||||||
| const group = computed(() => { |  | ||||||
|         const groups = groupsQueryResult.data.value?.groups; |         const groups = groupsQueryResult.data.value?.groups; | ||||||
| 
 | 
 | ||||||
|         if (!groups) return undefined; |         if (!groups) return undefined; | ||||||
|  | @ -58,14 +54,14 @@ const group = computed(() => { | ||||||
|                 groupNo: index + 1, // Renumbered index |                 groupNo: index + 1, // Renumbered index | ||||||
|             })) |             })) | ||||||
|             .find((group) => group.members?.some((m) => m.username === username.value)); |             .find((group) => group.members?.some((m) => m.username === username.value)); | ||||||
| }); |     }); | ||||||
| 
 | 
 | ||||||
| watchEffect(() => { |     watchEffect(() => { | ||||||
|         learningPath.value = assignment.value?.learningPath; |         learningPath.value = assignment.value?.learningPath; | ||||||
|         lang.value = assignment.value?.language as Language; |         lang.value = assignment.value?.language as Language; | ||||||
| }); |     }); | ||||||
| 
 | 
 | ||||||
| const learningPathParams = computed(() => { |     const learningPathParams = computed(() => { | ||||||
|         if (!group.value || !learningPath.value || !lang.value) return undefined; |         if (!group.value || !learningPath.value || !lang.value) return undefined; | ||||||
| 
 | 
 | ||||||
|         return { |         return { | ||||||
|  | @ -73,29 +69,27 @@ const learningPathParams = computed(() => { | ||||||
|             assignmentNo: props.assignmentId, |             assignmentNo: props.assignmentId, | ||||||
|             classId: props.classId, |             classId: props.classId, | ||||||
|         }; |         }; | ||||||
| }); |     }); | ||||||
| 
 | 
 | ||||||
| const lpQueryResult = useGetLearningPathQuery( |     const lpQueryResult = useGetLearningPathQuery( | ||||||
|         () => learningPath.value, |         () => learningPath.value, | ||||||
|         () => lang.value, |         () => lang.value, | ||||||
|         () => learningPathParams.value, |         () => learningPathParams.value, | ||||||
| ); |     ); | ||||||
| 
 | 
 | ||||||
| const progressColor = computed(() => { |     const progressColor = computed(() => { | ||||||
|         const progress = calculateProgress(lpQueryResult.data.value as LearningPath); |         const progress = calculateProgress(lpQueryResult.data.value as LearningPath); | ||||||
|         if (progress >= 100) return "success"; |         if (progress >= 100) return "success"; | ||||||
|         if (progress >= 50) return "warning"; |         if (progress >= 50) return "warning"; | ||||||
|         return "error"; |         return "error"; | ||||||
| }); |     }); | ||||||
| 
 | 
 | ||||||
| const studentQueries = useStudentsByUsernamesQuery(() => (group.value?.members as string[]) ?? undefined); |     const studentQueries = useStudentsByUsernamesQuery(() => (group.value?.members as string[]) ?? undefined); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|     <div class="container"> |     <div class="container"> | ||||||
|         <using-query-result |         <using-query-result :query-result="assignmentsQueryResult"> | ||||||
|             :query-result="assignmentsQueryResult" |  | ||||||
|         > |  | ||||||
|             <v-card |             <v-card | ||||||
|                 v-if="assignment" |                 v-if="assignment" | ||||||
|                 class="assignment-card" |                 class="assignment-card" | ||||||
|  | @ -110,9 +104,7 @@ const studentQueries = useStudentsByUsernamesQuery(() => (group.value?.members a | ||||||
|                         <v-icon>mdi-arrow-left</v-icon> |                         <v-icon>mdi-arrow-left</v-icon> | ||||||
|                     </v-btn> |                     </v-btn> | ||||||
|                 </div> |                 </div> | ||||||
|                 <v-card-title class="text-h4 assignmentTopTitle" |                 <v-card-title class="text-h4 assignmentTopTitle">{{ assignment.title }} </v-card-title> | ||||||
|                 >{{ assignment.title }} |  | ||||||
|                 </v-card-title> |  | ||||||
| 
 | 
 | ||||||
|                 <v-card-subtitle class="subtitle-section"> |                 <v-card-subtitle class="subtitle-section"> | ||||||
|                     <using-query-result |                     <using-query-result | ||||||
|  | @ -190,9 +182,9 @@ const studentQueries = useStudentsByUsernamesQuery(() => (group.value?.members a | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <style scoped> | <style scoped> | ||||||
| @import "@/assets/assignment.css"; |     @import "@/assets/assignment.css"; | ||||||
| 
 | 
 | ||||||
| .progress-bar { |     .progress-bar { | ||||||
|         width: 40%; |         width: 40%; | ||||||
| } |     } | ||||||
| </style> | </style> | ||||||
|  |  | ||||||
|  | @ -1,26 +1,26 @@ | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import {ref, computed, onMounted, watch} from "vue"; |     import { ref, computed, onMounted, watch } from "vue"; | ||||||
| import {useI18n} from "vue-i18n"; |     import { useI18n } from "vue-i18n"; | ||||||
| import {useRouter} from "vue-router"; |     import { useRouter } from "vue-router"; | ||||||
| import authState from "@/services/auth/auth-service.ts"; |     import authState from "@/services/auth/auth-service.ts"; | ||||||
| import auth from "@/services/auth/auth-service.ts"; |     import auth from "@/services/auth/auth-service.ts"; | ||||||
| import {useTeacherAssignmentsQuery, useTeacherClassesQuery} from "@/queries/teachers.ts"; |     import { useTeacherAssignmentsQuery, useTeacherClassesQuery } from "@/queries/teachers.ts"; | ||||||
| import {useStudentAssignmentsQuery, useStudentClassesQuery} from "@/queries/students.ts"; |     import { useStudentAssignmentsQuery, useStudentClassesQuery } from "@/queries/students.ts"; | ||||||
| import {useDeleteAssignmentMutation} from "@/queries/assignments.ts"; |     import { useDeleteAssignmentMutation } from "@/queries/assignments.ts"; | ||||||
| import UsingQueryResult from "@/components/UsingQueryResult.vue"; |     import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||||
| 
 | 
 | ||||||
| const {t, locale} = useI18n(); |     const { t, locale } = useI18n(); | ||||||
| const router = useRouter(); |     const router = useRouter(); | ||||||
| 
 | 
 | ||||||
| const role = ref(auth.authState.activeRole); |     const role = ref(auth.authState.activeRole); | ||||||
| const isTeacher = computed(() => role.value === "teacher"); |     const isTeacher = computed(() => role.value === "teacher"); | ||||||
| const username = ref<string | undefined>(undefined); |     const username = ref<string | undefined>(undefined); | ||||||
| const isLoading = ref(false); |     const isLoading = ref(false); | ||||||
| const isError = ref(false); |     const isError = ref(false); | ||||||
| const errorMessage = ref<string>(""); |     const errorMessage = ref<string>(""); | ||||||
| 
 | 
 | ||||||
| // Load current user before rendering the page |     // Load current user before rendering the page | ||||||
| onMounted(async () => { |     onMounted(async () => { | ||||||
|         isLoading.value = true; |         isLoading.value = true; | ||||||
|         try { |         try { | ||||||
|             const userObject = await authState.loadUser(); |             const userObject = await authState.loadUser(); | ||||||
|  | @ -31,17 +31,17 @@ onMounted(async () => { | ||||||
|         } finally { |         } finally { | ||||||
|             isLoading.value = false; |             isLoading.value = false; | ||||||
|         } |         } | ||||||
| }); |     }); | ||||||
| 
 | 
 | ||||||
| const classesQueryResult = isTeacher.value |     const classesQueryResult = isTeacher.value | ||||||
|         ? useTeacherClassesQuery(username, true) |         ? useTeacherClassesQuery(username, true) | ||||||
|         : useStudentClassesQuery(username, true); |         : useStudentClassesQuery(username, true); | ||||||
| 
 | 
 | ||||||
| const assignmentsQueryResult = isTeacher.value |     const assignmentsQueryResult = isTeacher.value | ||||||
|         ? useTeacherAssignmentsQuery(username, true) |         ? useTeacherAssignmentsQuery(username, true) | ||||||
|         : useStudentAssignmentsQuery(username, true); |         : useStudentAssignmentsQuery(username, true); | ||||||
| 
 | 
 | ||||||
| const allAssignments = computed(() => { |     const allAssignments = computed(() => { | ||||||
|         const assignments = assignmentsQueryResult.data.value?.assignments; |         const assignments = assignmentsQueryResult.data.value?.assignments; | ||||||
|         if (!assignments) return []; |         if (!assignments) return []; | ||||||
| 
 | 
 | ||||||
|  | @ -73,30 +73,29 @@ const allAssignments = computed(() => { | ||||||
| 
 | 
 | ||||||
|             return aTime - bTime; |             return aTime - bTime; | ||||||
|         }); |         }); | ||||||
| }); |     }); | ||||||
| 
 | 
 | ||||||
| 
 |     async function goToCreateAssignment(): Promise<void> { | ||||||
| async function goToCreateAssignment(): Promise<void> { |  | ||||||
|         await router.push("/assignment/create"); |         await router.push("/assignment/create"); | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| async function goToAssignmentDetails(id: number, clsId: string): Promise<void> { |     async function goToAssignmentDetails(id: number, clsId: string): Promise<void> { | ||||||
|         await router.push(`/assignment/${clsId}/${id}`); |         await router.push(`/assignment/${clsId}/${id}`); | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| const {mutate, data, isSuccess} = useDeleteAssignmentMutation(); |     const { mutate, data, isSuccess } = useDeleteAssignmentMutation(); | ||||||
| 
 | 
 | ||||||
| watch([isSuccess, data], async ([success, oldData]) => { |     watch([isSuccess, data], async ([success, oldData]) => { | ||||||
|         if (success && oldData?.assignment) { |         if (success && oldData?.assignment) { | ||||||
|             window.location.reload(); |             window.location.reload(); | ||||||
|         } |         } | ||||||
| }); |     }); | ||||||
| 
 | 
 | ||||||
| async function goToDeleteAssignment(num: number, clsId: string): Promise<void> { |     async function goToDeleteAssignment(num: number, clsId: string): Promise<void> { | ||||||
|     mutate({cid: clsId, an: num}); |         mutate({ cid: clsId, an: num }); | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| function formatDate(date?: string | Date): string { |     function formatDate(date?: string | Date): string { | ||||||
|         if (!date) return "–"; |         if (!date) return "–"; | ||||||
|         const d = new Date(date); |         const d = new Date(date); | ||||||
| 
 | 
 | ||||||
|  | @ -111,9 +110,9 @@ function formatDate(date?: string | Date): string { | ||||||
|             hour: "numeric", |             hour: "numeric", | ||||||
|             minute: "2-digit", |             minute: "2-digit", | ||||||
|         }); |         }); | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| function getDeadlineClass(deadline?: string | Date): string { |     function getDeadlineClass(deadline?: string | Date): string { | ||||||
|         if (!deadline) return ""; |         if (!deadline) return ""; | ||||||
| 
 | 
 | ||||||
|         const date = new Date(deadline); |         const date = new Date(deadline); | ||||||
|  | @ -123,17 +122,17 @@ function getDeadlineClass(deadline?: string | Date): string { | ||||||
|         if (date.getTime() < now.getTime()) return "deadline-passed"; |         if (date.getTime() < now.getTime()) return "deadline-passed"; | ||||||
|         if (date.getTime() <= in24Hours.getTime()) return "deadline-in24hours"; |         if (date.getTime() <= in24Hours.getTime()) return "deadline-in24hours"; | ||||||
|         return "deadline-upcoming"; |         return "deadline-upcoming"; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| onMounted(async () => { |     onMounted(async () => { | ||||||
|         const user = await auth.loadUser(); |         const user = await auth.loadUser(); | ||||||
|         username.value = user?.profile?.preferred_username ?? ""; |         username.value = user?.profile?.preferred_username ?? ""; | ||||||
| }); |     }); | ||||||
| 
 | 
 | ||||||
| onMounted(async () => { |     onMounted(async () => { | ||||||
|         const user = await auth.loadUser(); |         const user = await auth.loadUser(); | ||||||
|         username.value = user?.profile?.preferred_username ?? ""; |         username.value = user?.profile?.preferred_username ?? ""; | ||||||
| }); |     }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|  | @ -210,87 +209,88 @@ onMounted(async () => { | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <style scoped> | <style scoped> | ||||||
| .assignments-container { |     .assignments-container { | ||||||
|         width: 100%; |         width: 100%; | ||||||
|         margin: 0 auto; |         margin: 0 auto; | ||||||
|         box-sizing: border-box; |         box-sizing: border-box; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .center-btn { |     .center-btn { | ||||||
|         display: block; |         display: block; | ||||||
|         margin: 0 auto 2rem auto; |         margin: 0 auto 2rem auto; | ||||||
|         font-weight: 600; |         font-weight: 600; | ||||||
|         background-color: #10ad61; |         background-color: #10ad61; | ||||||
|         color: white; |         color: white; | ||||||
|         transition: background-color 0.2s; |         transition: background-color 0.2s; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .center-btn:hover { |     .center-btn:hover { | ||||||
|         background-color: #0e6942; |         background-color: #0e6942; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .assignment-card { |     .assignment-card { | ||||||
|         padding: 1.25rem; |         padding: 1.25rem; | ||||||
|         border-radius: 16px; |         border-radius: 16px; | ||||||
|         box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); |         box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); | ||||||
|         background-color: white; |         background-color: white; | ||||||
|     transition: transform 0.2s, |         transition: | ||||||
|  |             transform 0.2s, | ||||||
|             box-shadow 0.2s; |             box-shadow 0.2s; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .assignment-card:hover { |     .assignment-card:hover { | ||||||
|         box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); |         box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .top-content { |     .top-content { | ||||||
|         margin-bottom: 1rem; |         margin-bottom: 1rem; | ||||||
|         word-break: break-word; |         word-break: break-word; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .assignment-title { |     .assignment-title { | ||||||
|         font-weight: 700; |         font-weight: 700; | ||||||
|         font-size: 1.4rem; |         font-size: 1.4rem; | ||||||
|         color: #0e6942; |         color: #0e6942; | ||||||
|         margin-bottom: 0.3rem; |         margin-bottom: 0.3rem; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .assignment-class, |     .assignment-class, | ||||||
| .assignment-deadline { |     .assignment-deadline { | ||||||
|         font-size: 0.95rem; |         font-size: 0.95rem; | ||||||
|         color: #444; |         color: #444; | ||||||
|         margin-bottom: 0.2rem; |         margin-bottom: 0.2rem; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .class-name { |     .class-name { | ||||||
|         font-weight: 600; |         font-weight: 600; | ||||||
|         color: #097180; |         color: #097180; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .assignment-deadline.deadline-passed { |     .assignment-deadline.deadline-passed { | ||||||
|         color: #d32f2f; |         color: #d32f2f; | ||||||
|         font-weight: bold; |         font-weight: bold; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .assignment-deadline.deadline-in24hours { |     .assignment-deadline.deadline-in24hours { | ||||||
|         color: #f57c00; |         color: #f57c00; | ||||||
|         font-weight: bold; |         font-weight: bold; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .spacer { |     .spacer { | ||||||
|         flex: 1; |         flex: 1; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .button-row { |     .button-row { | ||||||
|         display: flex; |         display: flex; | ||||||
|         justify-content: flex-end; |         justify-content: flex-end; | ||||||
|         gap: 0.75rem; |         gap: 0.75rem; | ||||||
|         flex-wrap: wrap; |         flex-wrap: wrap; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| .no-assignments { |     .no-assignments { | ||||||
|         text-align: center; |         text-align: center; | ||||||
|         font-size: 1.2rem; |         font-size: 1.2rem; | ||||||
|         color: #777; |         color: #777; | ||||||
|         padding: 3rem 0; |         padding: 3rem 0; | ||||||
| } |     } | ||||||
| </style> | </style> | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Joyelle Ndagijimana
						Joyelle Ndagijimana