feat: nieuwe lijstview voor assignment
This commit is contained in:
		
							parent
							
								
									c03669eda7
								
							
						
					
					
						commit
						7e4e179121
					
				
					 1 changed files with 178 additions and 156 deletions
				
			
		|  | @ -1,110 +1,136 @@ | |||
| <script setup lang="ts"> | ||||
|     import { ref, computed, onMounted, watch } from "vue"; | ||||
|     import { useI18n } from "vue-i18n"; | ||||
|     import { useRouter } from "vue-router"; | ||||
|     import auth from "@/services/auth/auth-service.ts"; | ||||
|     import { useTeacherClassesQuery } from "@/queries/teachers.ts"; | ||||
|     import { useStudentClassesQuery } from "@/queries/students.ts"; | ||||
|     import { ClassController } from "@/controllers/classes.ts"; | ||||
|     import type { ClassDTO } from "@dwengo-1/common/interfaces/class"; | ||||
|     import { asyncComputed } from "@vueuse/core"; | ||||
|     import { useDeleteAssignmentMutation } from "@/queries/assignments.ts"; | ||||
| import { ref, computed, onMounted, watch } from "vue"; | ||||
| import { useI18n } from "vue-i18n"; | ||||
| import { useRouter } from "vue-router"; | ||||
| import authState from "@/services/auth/auth-service.ts"; | ||||
| import auth from "@/services/auth/auth-service.ts"; | ||||
| import { useTeacherAssignmentsQuery, useTeacherClassesQuery } from "@/queries/teachers.ts"; | ||||
| import { useStudentAssignmentsQuery, useStudentClassesQuery } from "@/queries/students.ts"; | ||||
| import { ClassController } from "@/controllers/classes.ts"; | ||||
| import type { ClassDTO } from "@dwengo-1/common/interfaces/class"; | ||||
| import { asyncComputed } from "@vueuse/core"; | ||||
| import { useDeleteAssignmentMutation } from "@/queries/assignments.ts"; | ||||
| import type { AssignmentsResponse } from "@/controllers/assignments"; | ||||
| import type { AssignmentDTO } from "@dwengo-1/common/interfaces/assignment"; | ||||
| import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||
| 
 | ||||
|     const { t } = useI18n(); | ||||
|     const router = useRouter(); | ||||
| const { t } = useI18n(); | ||||
| const router = useRouter(); | ||||
| 
 | ||||
|     const role = ref(auth.authState.activeRole); | ||||
|     const username = ref<string>(""); | ||||
| const role = ref(auth.authState.activeRole); | ||||
| const username = ref<string | undefined>(undefined); | ||||
| const isLoading = ref(false); | ||||
| const isError = ref(false); | ||||
| const errorMessage = ref<string>(""); | ||||
| 
 | ||||
|     const isTeacher = computed(() => role.value === "teacher"); | ||||
| 
 | ||||
|     // Fetch and store all the teacher's classes | ||||
|     let classesQueryResults = undefined; | ||||
| 
 | ||||
|     if (isTeacher.value) { | ||||
|         classesQueryResults = useTeacherClassesQuery(username, true); | ||||
|     } else { | ||||
|         classesQueryResults = useStudentClassesQuery(username, true); | ||||
| // Load current user before rendering the page | ||||
| onMounted(async () => { | ||||
|     isLoading.value = true; | ||||
|     try { | ||||
|         const userObject = await authState.loadUser(); | ||||
|         username.value = userObject!.profile.preferred_username; | ||||
|     } catch (error) { | ||||
|         isError.value = true; | ||||
|         errorMessage.value = error instanceof Error ? error.message : String(error); | ||||
|     } finally { | ||||
|         isLoading.value = false; | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
|     //TODO: remove later | ||||
|     const classController = new ClassController(); | ||||
| const isTeacher = computed(() => role.value === "teacher"); | ||||
| 
 | ||||
|     //TODO: replace by query that fetches all user's assignment | ||||
|     const assignments = asyncComputed(async () => { | ||||
|         const classes = classesQueryResults?.data?.value?.classes; | ||||
|         if (!classes) return []; | ||||
|         const result = await Promise.all( | ||||
|             (classes as ClassDTO[]).map(async (cls) => { | ||||
|                 const { assignments } = await classController.getAssignments(cls.id); | ||||
|                 return assignments.map((a) => ({ | ||||
|                     id: a.id, | ||||
|                     class: cls, | ||||
|                     title: a.title, | ||||
|                     description: a.description, | ||||
|                     learningPath: a.learningPath, | ||||
|                     language: a.language, | ||||
|                     groups: a.groups, | ||||
|                 })); | ||||
|             }), | ||||
|         ); | ||||
| const assignmentsQuery = isTeacher ? useTeacherAssignmentsQuery(username, true) : useStudentAssignmentsQuery(username, true); | ||||
| 
 | ||||
|         return result.flat(); | ||||
|     }, []); | ||||
| 
 | ||||
|     async function goToCreateAssignment(): Promise<void> { | ||||
| async function goToCreateAssignment(): Promise<void> { | ||||
|     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}`); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     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) { | ||||
|         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 }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     onMounted(async () => { | ||||
| onMounted(async () => { | ||||
|     const user = await auth.loadUser(); | ||||
|     username.value = user?.profile?.preferred_username ?? ""; | ||||
|     }); | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|     <div class="assignments-container"> | ||||
|     <main> | ||||
|         <h1>{{ t("assignments") }}</h1> | ||||
| 
 | ||||
|         <v-btn | ||||
|             v-if="isTeacher" | ||||
|             color="primary" | ||||
|             class="mb-4 center-btn" | ||||
|             @click="goToCreateAssignment" | ||||
|         > | ||||
|         <div class="loading-div" v-if="isLoading"> | ||||
|             <v-progress-circular indeterminate></v-progress-circular> | ||||
|         </div> | ||||
|         <div v-if="isError"> | ||||
|             <v-empty-state icon="mdi-alert-circle-outline" :text="errorMessage" | ||||
|                 :title="t('error_title')"></v-empty-state> | ||||
|         </div> | ||||
|         <div v-else> | ||||
|             <using-query-result :query-result="assignmentsQuery" | ||||
|                 v-slot="assignmentsResponse: { data: AssignmentsResponse }"> | ||||
|                 <v-btn v-if="isTeacher" color="primary" class="mb-4 center-btn" @click="goToCreateAssignment"> | ||||
|                     {{ t("new-assignment") }} | ||||
|                 </v-btn> | ||||
|                 <v-container> | ||||
|                     <v-table class="table"> | ||||
|                         <thead> | ||||
|                             <tr> | ||||
|                                 <th class="header">{{ t("assignments") }}</th> | ||||
|                                 <th class="header"> | ||||
|                                     {{ t("class") }} | ||||
|                                 </th> | ||||
|                                 <th class="header">{{ t("groups") }}</th> | ||||
|                             </tr> | ||||
|                         </thead> | ||||
|                         <tbody> | ||||
|                             <tr v-for="a in assignmentsResponse.data.assignments as AssignmentDTO[]" | ||||
|                                 :key="a.id + a.within"> | ||||
|                                 <td> | ||||
|                                     <v-btn :to="`/class/${a.within}`" variant="text"> | ||||
|                                         {{ a.title }} | ||||
|                                         <v-icon end> mdi-menu-right </v-icon> | ||||
|                                     </v-btn> | ||||
|                                 </td> | ||||
|                                 <td> | ||||
|                                     <span>{{ a.within }}</span> | ||||
|                                     <!-- <span v-if="!isMdAndDown">{{ c.id }}</span> | ||||
|                                     <span v-else style="cursor: pointer" @click="openCodeDialog(c.id)"><v-icon | ||||
|                                             icon="mdi-eye"></v-icon></span> --> | ||||
|                                 </td> | ||||
| 
 | ||||
|                                 <td>{{ a.groups.length }}</td> | ||||
|                             </tr> | ||||
|                         </tbody> | ||||
|                     </v-table> | ||||
|                 </v-container> | ||||
|             </using-query-result> | ||||
|         </div> | ||||
|             <div class="assignments-container"> | ||||
|                 <using-query-result :query-result="assignmentsQuery" | ||||
|                     v-slot="assignmentsResponse: { data: AssignmentsResponse }"> | ||||
|                     <v-container> | ||||
|                         <v-row> | ||||
|                 <v-col | ||||
|                     v-for="assignment in assignments" | ||||
|                     :key="assignment.id" | ||||
|                     cols="12" | ||||
|                 > | ||||
|                             <v-col v-for="assignment in assignmentsResponse.data.assignments as AssignmentDTO[]" | ||||
|                                 :key="assignment.id + assignment.within" cols="12"> | ||||
|                                 <v-card class="assignment-card"> | ||||
|                                     <div class="top-content"> | ||||
|                                         <div class="assignment-title">{{ assignment.title }}</div> | ||||
|                                         <div class="assignment-class"> | ||||
|                                             {{ t("class") }}: | ||||
|                                             <span class="class-name"> | ||||
|                                     {{ assignment.class.displayName }} | ||||
|                                                 {{ assignment.within }} | ||||
|                                             </span> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|  | @ -112,19 +138,12 @@ | |||
|                                     <div class="spacer"></div> | ||||
| 
 | ||||
|                                     <div class="button-row"> | ||||
|                             <v-btn | ||||
|                                 color="primary" | ||||
|                                 variant="text" | ||||
|                                 @click="goToAssignmentDetails(assignment.id, assignment.class.id)" | ||||
|                             > | ||||
|                                         <v-btn color="primary" variant="text" | ||||
|                                             @click="goToAssignmentDetails(assignment.id, assignment.within)"> | ||||
|                                             {{ t("view-assignment") }} | ||||
|                                         </v-btn> | ||||
|                             <v-btn | ||||
|                                 v-if="isTeacher" | ||||
|                                 color="red" | ||||
|                                 variant="text" | ||||
|                                 @click="goToDeleteAssignment(assignment.id, assignment.class.id)" | ||||
|                             > | ||||
|                                         <v-btn v-if="isTeacher" color="red" variant="text" | ||||
|                                             @click="goToDeleteAssignment(assignment.id, assignment.within)"> | ||||
|                                             {{ t("delete") }} | ||||
|                                         </v-btn> | ||||
|                                     </div> | ||||
|  | @ -132,57 +151,60 @@ | |||
|                             </v-col> | ||||
|                         </v-row> | ||||
|                     </v-container> | ||||
|                 </using-query-result> | ||||
|             </div> | ||||
|     </main> | ||||
| 
 | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
|     .assignments-container { | ||||
| .assignments-container { | ||||
|     width: 100%; | ||||
|     margin: 0 auto; | ||||
|     padding: 2% 4%; | ||||
|     box-sizing: border-box; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     .center-btn { | ||||
| .center-btn { | ||||
|     display: block; | ||||
|     margin-left: auto; | ||||
|     margin-right: auto; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     .assignment-card { | ||||
| .assignment-card { | ||||
|     padding: 1rem; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     .top-content { | ||||
| .top-content { | ||||
|     margin-bottom: 1rem; | ||||
|     word-break: break-word; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     .spacer { | ||||
| .spacer { | ||||
|     flex: 1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     .button-row { | ||||
| .button-row { | ||||
|     display: flex; | ||||
|     justify-content: flex-end; | ||||
|     gap: 0.5rem; | ||||
|     flex-wrap: wrap; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     .assignment-title { | ||||
| .assignment-title { | ||||
|     font-weight: bold; | ||||
|     font-size: 1.5rem; | ||||
|     margin-bottom: 0.1rem; | ||||
|     word-break: break-word; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     .assignment-class { | ||||
| .assignment-class { | ||||
|     color: #666; | ||||
|     font-size: 0.95rem; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     .class-name { | ||||
| .class-name { | ||||
|     font-weight: 500; | ||||
|     color: #333; | ||||
|     } | ||||
| } | ||||
| </style> | ||||
|  |  | |||
		Reference in a new issue
	
	 Adriaan Jacquet
						Adriaan Jacquet