feat(frontend): progress van assignment wordt getoond
This commit is contained in:
		
							parent
							
								
									20cf276faf
								
							
						
					
					
						commit
						5b17bad368
					
				
					 4 changed files with 113 additions and 34 deletions
				
			
		|  | @ -12,13 +12,21 @@ import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||||
| import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts"; | import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts"; | ||||||
| import type {ClassesResponse} from "@/controllers/classes.ts"; | import type {ClassesResponse} from "@/controllers/classes.ts"; | ||||||
| import type {AssignmentDTO} from "@dwengo-1/common/interfaces/assignment"; | import type {AssignmentDTO} from "@dwengo-1/common/interfaces/assignment"; | ||||||
| import {AssignmentController} from "@/controllers/assignments.ts"; |  | ||||||
| import {useCreateAssignmentMutation} from "@/queries/assignments.ts"; | import {useCreateAssignmentMutation} from "@/queries/assignments.ts"; | ||||||
|  | import {useRoute} from "vue-router"; | ||||||
| 
 | 
 | ||||||
| /*** | /*** | ||||||
|  TODO: when clicking the assign button from lp page pass the lp-object in a state: |  TODO: when clicking the assign button from lp page pass the lp-hruid in a query like this: | ||||||
|  |  router.push({ | ||||||
|  |      path: "/assignment/create, | ||||||
|  |          query: { | ||||||
|  |          ...route.query, | ||||||
|  |          lp: hruid, | ||||||
|  |         }, | ||||||
|  |      }); | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | const route = useRoute(); | ||||||
| const router = useRouter(); | const router = useRouter(); | ||||||
| const {t, locale} = useI18n(); | const {t, locale} = useI18n(); | ||||||
| const role = ref(auth.authState.activeRole); | const role = ref(auth.authState.activeRole); | ||||||
|  | @ -48,10 +56,10 @@ const classesQueryResults = useTeacherClassesQuery(username, true); | ||||||
| const selectedClass = ref(undefined); | const selectedClass = ref(undefined); | ||||||
| 
 | 
 | ||||||
| const assignmentTitle = ref(''); | const assignmentTitle = ref(''); | ||||||
| const selectedLearningPath = ref<LearningPath | null>(window.history.state?.learningPath ?? null); | const selectedLearningPath = ref(route.query.lp || undefined); | ||||||
| 
 | 
 | ||||||
| // Disable combobox when learningPath prop is passed | // Disable combobox when learningPath prop is passed | ||||||
| const lpIsSelected = window.history.state?.learningPath !== undefined; | const lpIsSelected = route.query.lp !== undefined; | ||||||
| const deadline = ref(null); | const deadline = ref(null); | ||||||
| const description = ref(''); | const description = ref(''); | ||||||
| const groups = ref<string[][]>([]); | const groups = ref<string[][]>([]); | ||||||
|  |  | ||||||
|  | @ -8,6 +8,8 @@ import type {AssignmentResponse} from "@/controllers/assignments.ts"; | ||||||
| import {asyncComputed} from "@vueuse/core"; | import {asyncComputed} from "@vueuse/core"; | ||||||
| import {useStudentsByUsernamesQuery} from "@/queries/students.ts"; | import {useStudentsByUsernamesQuery} from "@/queries/students.ts"; | ||||||
| import {useGroupsQuery} from "@/queries/groups.ts"; | import {useGroupsQuery} from "@/queries/groups.ts"; | ||||||
|  | import {useGetLearningPathQuery} from "@/queries/learning-paths.ts"; | ||||||
|  | import type {Language} from "@/data-objects/language.ts"; | ||||||
| 
 | 
 | ||||||
| const props = defineProps<{ | const props = defineProps<{ | ||||||
|     classId: string |     classId: string | ||||||
|  | @ -25,16 +27,16 @@ const username = asyncComputed(async () => { | ||||||
| const assignmentQueryResult = useAssignmentQuery(() => props.classId, props.assignmentId); | const assignmentQueryResult = useAssignmentQuery(() => props.classId, props.assignmentId); | ||||||
| const submitted = ref(false);//TODO: update by fetching submissions and check if group submitted | const submitted = ref(false);//TODO: update by fetching submissions and check if group submitted | ||||||
| 
 | 
 | ||||||
|  | const lpQueryResult = useGetLearningPathQuery( | ||||||
|  |     computed(() => assignmentQueryResult.data.value?.assignment?.learningPath ?? ""), | ||||||
|  |     computed(() => language.value as Language) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
| const groupsQueryResult = useGroupsQuery(props.classId, props.assignmentId, true); | const groupsQueryResult = useGroupsQuery(props.classId, props.assignmentId, true); | ||||||
| const group = computed(() => | const group = computed(() => | ||||||
|     groupsQueryResult?.data.value?.groups.find(group => |     groupsQueryResult?.data.value?.groups.find(group => | ||||||
|         group.members?.some(m => m.username === username.value) |         group.members?.some(m => m.username === username.value) | ||||||
|     ) |     ) | ||||||
|     /** For testing |  | ||||||
|      return {assignment: 1, |  | ||||||
|      groupNumber: 1, |  | ||||||
|      members: ["testleerling1"]} |  | ||||||
|      */ |  | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| // Assuming group.value.members is a list of usernames TODO: case when it's StudentDTO's | // Assuming group.value.members is a list of usernames TODO: case when it's StudentDTO's | ||||||
|  | @ -70,13 +72,18 @@ const studentQueries = useStudentsByUsernamesQuery(() => group.value?.members as | ||||||
|                 </div> |                 </div> | ||||||
|                 <v-card-title class="text-h4">{{ data.assignment.title }}</v-card-title> |                 <v-card-title class="text-h4">{{ data.assignment.title }}</v-card-title> | ||||||
|                 <v-card-subtitle class="subtitle-section"> |                 <v-card-subtitle class="subtitle-section"> | ||||||
|                     <v-btn |                     <using-query-result | ||||||
|                         :to="`/learningPath/${language}/${data.assignment.learningPath}`" |                         :query-result="lpQueryResult" | ||||||
|  |                         v-slot="{ data: lpData }" | ||||||
|  |                     > | ||||||
|  |                         <v-btn v-if="lpData" | ||||||
|  |                                :to="`/learningPath/${lpData.hruid}/${language}/${lpData.startNode.learningobjectHruid}`" | ||||||
|                                variant="tonal" |                                variant="tonal" | ||||||
|                                color="primary" |                                color="primary" | ||||||
|                         > |                         > | ||||||
|                             {{ t("learning-path") }} |                             {{ t("learning-path") }} | ||||||
|                         </v-btn> |                         </v-btn> | ||||||
|  |                     </using-query-result> | ||||||
|                 </v-card-subtitle> |                 </v-card-subtitle> | ||||||
| 
 | 
 | ||||||
|                 <v-card-text class="description"> |                 <v-card-text class="description"> | ||||||
|  |  | ||||||
|  | @ -1,13 +1,15 @@ | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import {computed, defineProps, ref} from "vue"; | import {computed, defineProps, reactive, type Ref, ref, watchEffect} from "vue"; | ||||||
| import {useI18n} from "vue-i18n"; | import {useI18n} from "vue-i18n"; | ||||||
| import {AssignmentController, type AssignmentResponse} from "@/controllers/assignments.ts"; | import {useAssignmentQuery, useDeleteAssignmentMutation} from "@/queries/assignments.ts"; | ||||||
| import {useAssignmentQuery} from "@/queries/assignments.ts"; |  | ||||||
| import UsingQueryResult from "@/components/UsingQueryResult.vue"; | import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||||
| import {useGroupsQuery} from "@/queries/groups.ts"; | import {useGroupsQuery} from "@/queries/groups.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 type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts"; | import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts"; | ||||||
|  | import type {GroupDTO} from "@dwengo-1/common/interfaces/group"; | ||||||
|  | import router from "@/router"; | ||||||
|  | import type {AssignmentResponse} from "@/controllers/assignments.ts"; | ||||||
| 
 | 
 | ||||||
| const props = defineProps<{ | const props = defineProps<{ | ||||||
|     classId: string |     classId: string | ||||||
|  | @ -16,23 +18,74 @@ const props = defineProps<{ | ||||||
| 
 | 
 | ||||||
| const {t, locale} = useI18n(); | const {t, locale} = useI18n(); | ||||||
| const language = computed(() => locale.value); | const language = computed(() => locale.value); | ||||||
| const controller = new AssignmentController(props.classId); | const groups = ref(); | ||||||
|  | const learningPath = ref(); | ||||||
|  | 
 | ||||||
|  | function useGroupsWithProgress( | ||||||
|  |     groups: Ref<GroupDTO[]>, | ||||||
|  |     hruid: Ref<string>, | ||||||
|  |     language: Ref<string> | ||||||
|  | ): { groupProgressMap: Record<string, number> } { | ||||||
|  |     const groupProgressMap: Record<string, number> = reactive({}); | ||||||
|  | 
 | ||||||
|  |     watchEffect(() => { | ||||||
|  |         // Clear existing entries to avoid stale data | ||||||
|  |         for (const key in groupProgressMap) { | ||||||
|  |             delete groupProgressMap[key]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const lang = language.value as Language; | ||||||
|  | 
 | ||||||
|  |         groups.value.forEach((group) => { | ||||||
|  |             const groupKey = group.groupNumber.toString(); | ||||||
|  | 
 | ||||||
|  |             const query = useGetLearningPathQuery(hruid.value, lang, { | ||||||
|  |                 forGroup: groupKey, | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             const data = query.data.value; | ||||||
|  | 
 | ||||||
|  |             groupProgressMap[groupKey] = data ? calculateProgress(data) : 0; | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return { | ||||||
|  |         groupProgressMap, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function calculateProgress(lp: LearningPath): number { | ||||||
|  |     return ((lp.amountOfNodes - lp.amountOfNodesLeft) / lp.amountOfNodes) * 100; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| const assignmentQueryResult = useAssignmentQuery(() => props.classId, props.assignmentId); | const assignmentQueryResult = useAssignmentQuery(() => props.classId, props.assignmentId); | ||||||
| const groupsQueryResult = useGroupsQuery(props.classId, props.assignmentId, true); | learningPath.value = assignmentQueryResult.data.value?.assignment?.learningPath; | ||||||
| 
 | // Get learning path object | ||||||
| const lpQueryResult = useGetLearningPathQuery( | const lpQueryResult = useGetLearningPathQuery( | ||||||
|     computed(() => assignmentQueryResult.data.value?.assignment?.learningPath ?? ""), |     computed(() => assignmentQueryResult.data.value?.assignment?.learningPath ?? ""), | ||||||
|     computed(() => language.value as Language) |     computed(() => language.value as Language) | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  | // Get all the groups withing the assignment | ||||||
|  | const groupsQueryResult = useGroupsQuery(props.classId, props.assignmentId, true); | ||||||
|  | groups.value = groupsQueryResult.data.value?.groups; | ||||||
|  | 
 | ||||||
|  | /* Crashes right now cause api data has inexistent hruid TODO: uncomment later | ||||||
|  | Const {groupProgressMap} = useGroupsWithProgress( | ||||||
|  |     groups, | ||||||
|  |     learningPath, | ||||||
|  |     language | ||||||
|  | ); | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| const allGroups = computed(() => { | const allGroups = computed(() => { | ||||||
|     const groups = groupsQueryResult.data.value?.groups; |     const groups = groupsQueryResult.data.value?.groups; | ||||||
|     if (!groups) return []; |     if (!groups) return []; | ||||||
| 
 | 
 | ||||||
|     return groups.map(group => ({ |     return groups.map(group => ({ | ||||||
|         name: `${t('group')} ${group.groupNumber}`, |         name: `${t('group')} ${group.groupNumber}`, | ||||||
|         progress: 0, |         progress: 0,//GroupProgressMap[group.groupNumber], | ||||||
|         members: group.members, |         members: group.members, | ||||||
|         submitted: false,//TODO: fetch from submission |         submitted: false,//TODO: fetch from submission | ||||||
|     })); |     })); | ||||||
|  | @ -53,8 +106,15 @@ const headers = ref([ | ||||||
| ]); | ]); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| async function deleteAssignment(): Promise<void> { | const {mutate, isSuccess} = useDeleteAssignmentMutation(); | ||||||
|     await controller.deleteAssignment(props.assignmentId); | 
 | ||||||
|  | async function deleteAssignment(num: number, clsId: string): Promise<void> { | ||||||
|  |     mutate({ | ||||||
|  |         cid: clsId, | ||||||
|  |         an: num | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     if (isSuccess) await router.push("/user/assignments"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| </script> | </script> | ||||||
|  | @ -80,7 +140,7 @@ async function deleteAssignment(): Promise<void> { | ||||||
|                         icon |                         icon | ||||||
|                         variant="text" |                         variant="text" | ||||||
|                         class="top-right-btn" |                         class="top-right-btn" | ||||||
|                         @click="deleteAssignment" |                         @click="deleteAssignment(data.assignment.id, data.assignment.within)" | ||||||
|                     > |                     > | ||||||
|                         <v-icon>mdi-delete</v-icon> |                         <v-icon>mdi-delete</v-icon> | ||||||
|                     </v-btn> |                     </v-btn> | ||||||
|  | @ -92,7 +152,7 @@ async function deleteAssignment(): Promise<void> { | ||||||
|                         v-slot="{ data: lpData }" |                         v-slot="{ data: lpData }" | ||||||
|                     > |                     > | ||||||
|                         <v-btn v-if="lpData" |                         <v-btn v-if="lpData" | ||||||
|                                :to="`/learningPath/${language}/${lpData.hruid}/${lpData.startNode.learningobjectHruid}`" |                                :to="`/learningPath/${lpData.hruid}/${language}/${lpData.startNode.learningobjectHruid}`" | ||||||
|                                variant="tonal" |                                variant="tonal" | ||||||
|                                color="primary" |                                color="primary" | ||||||
|                         > |                         > | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ import {useStudentClassesQuery} from "@/queries/students.ts"; | ||||||
| import {ClassController} from "@/controllers/classes.ts"; | import {ClassController} from "@/controllers/classes.ts"; | ||||||
| import type {ClassDTO} from "@dwengo-1/common/interfaces/class"; | import type {ClassDTO} from "@dwengo-1/common/interfaces/class"; | ||||||
| import {asyncComputed} from "@vueuse/core"; | import {asyncComputed} from "@vueuse/core"; | ||||||
| import {AssignmentController} from "@/controllers/assignments.ts"; | import {useDeleteAssignmentMutation} from "@/queries/assignments.ts"; | ||||||
| 
 | 
 | ||||||
| const {t} = useI18n(); | const {t} = useI18n(); | ||||||
| const router = useRouter(); | const router = useRouter(); | ||||||
|  | @ -62,11 +62,15 @@ async function goToAssignmentDetails(id: number, clsId: string): Promise<void> { | ||||||
|     await router.push(`/assignment/${clsId}/${id}`); |     await router.push(`/assignment/${clsId}/${id}`); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const {mutate, isSuccess} = useDeleteAssignmentMutation(); | ||||||
| 
 | 
 | ||||||
| async function goToDeleteAssignment(id: number, clsId: string): Promise<void> { | async function goToDeleteAssignment(num: number, clsId: string): Promise<void> { | ||||||
|     //TODO: replace with query |     mutate({ | ||||||
|     const controller = new AssignmentController(clsId); |         cid: clsId, | ||||||
|     await controller.deleteAssignment(id); |         an: num | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     if (isSuccess) await router.push("/user/assignment"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| onMounted(async () => { | onMounted(async () => { | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Joyelle Ndagijimana
						Joyelle Ndagijimana