feat(frontend): Leerkrachten kunnen indieningen van verschillende groepen bekijken
This commit is contained in:
		
							parent
							
								
									e98fd8db3a
								
							
						
					
					
						commit
						90b5cd9d3a
					
				
					 5 changed files with 81 additions and 6 deletions
				
			
		|  | @ -84,5 +84,7 @@ | ||||||
|     "submittedBy": "Submitted by", |     "submittedBy": "Submitted by", | ||||||
|     "timestamp": "Timestamp", |     "timestamp": "Timestamp", | ||||||
|     "loadSubmission": "Load", |     "loadSubmission": "Load", | ||||||
|     "noSubmissionsYet": "No submissions yet." |     "noSubmissionsYet": "No submissions yet.", | ||||||
|  |     "viewAsGroup": "View progress of group...", | ||||||
|  |     "group": "group" | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,3 @@ | ||||||
| import type { ClassesResponse } from "@/controllers/classes"; |  | ||||||
| import { GroupController, type GroupResponse, type GroupsResponse } from "@/controllers/groups"; | import { GroupController, type GroupResponse, type GroupsResponse } from "@/controllers/groups"; | ||||||
| import type { QuestionsResponse } from "@/controllers/questions"; | import type { QuestionsResponse } from "@/controllers/questions"; | ||||||
| import type { SubmissionsResponse } from "@/controllers/submissions"; | import type { SubmissionsResponse } from "@/controllers/submissions"; | ||||||
|  | @ -12,7 +11,6 @@ import { | ||||||
|     type UseQueryReturnType, |     type UseQueryReturnType, | ||||||
| } from "@tanstack/vue-query"; | } from "@tanstack/vue-query"; | ||||||
| import { computed, toValue, type MaybeRefOrGetter } from "vue"; | import { computed, toValue, type MaybeRefOrGetter } from "vue"; | ||||||
| import { invalidateAllAssignmentKeys } from "./assignments"; |  | ||||||
| import { invalidateAllSubmissionKeys } from "./submissions"; | import { invalidateAllSubmissionKeys } from "./submissions"; | ||||||
| 
 | 
 | ||||||
| export function groupsQueryKey(classid: string, assignmentNumber: number, full: boolean) { | export function groupsQueryKey(classid: string, assignmentNumber: number, full: boolean) { | ||||||
|  | @ -132,7 +130,7 @@ export function useDeleteGroupMutation(): UseMutationReturnType< | ||||||
|             const gn = response.group.groupNumber; |             const gn = response.group.groupNumber; | ||||||
| 
 | 
 | ||||||
|             await invalidateAllGroupKeys(queryClient, cid, an, gn); |             await invalidateAllGroupKeys(queryClient, cid, an, gn); | ||||||
|             await invalidateAllSubmissionKeys(queryClient, cid, an, gn); |             await invalidateAllSubmissionKeys(queryClient, undefined, undefined, undefined, cid, an, gn); | ||||||
|         }, |         }, | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ export function useGetLearningPathQuery( | ||||||
|     forGroup?: MaybeRefOrGetter<{forGroup: number, assignmentNo: number, classId: string} | undefined>, |     forGroup?: MaybeRefOrGetter<{forGroup: number, assignmentNo: number, classId: string} | undefined>, | ||||||
| ): UseQueryReturnType<LearningPath, Error> { | ): UseQueryReturnType<LearningPath, Error> { | ||||||
|     return useQuery({ |     return useQuery({ | ||||||
|         queryKey: [LEARNING_PATH_KEY, "get", toValue(hruid), toValue(language), toValue(forGroup)], |         queryKey: [LEARNING_PATH_KEY, "get", hruid, language, forGroup], | ||||||
|         queryFn: async () => { |         queryFn: async () => { | ||||||
|             const [hruidVal, languageVal, forGroupVal] = [toValue(hruid), toValue(language), toValue(forGroup)]; |             const [hruidVal, languageVal, forGroupVal] = [toValue(hruid), toValue(language), toValue(forGroup)]; | ||||||
|             return learningPathController.getBy(hruidVal, languageVal, forGroupVal); |             return learningPathController.getBy(hruidVal, languageVal, forGroupVal); | ||||||
|  |  | ||||||
|  | @ -0,0 +1,55 @@ | ||||||
|  | <script setup lang="ts"> | ||||||
|  |     import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||||
|  |     import {useGroupsQuery} from "@/queries/groups.ts"; | ||||||
|  |     import type {GroupsResponse} from "@/controllers/groups.ts"; | ||||||
|  |     import {useI18n} from "vue-i18n"; | ||||||
|  |     import type {GroupDTO} from "@dwengo-1/common/interfaces/group"; | ||||||
|  | 
 | ||||||
|  |     const { t } = useI18n(); | ||||||
|  | 
 | ||||||
|  |     const props = defineProps<{ | ||||||
|  |         classId: string, | ||||||
|  |         assignmentNumber: number | ||||||
|  |     }>(); | ||||||
|  | 
 | ||||||
|  |     const model = defineModel<number | undefined>({default: undefined}); | ||||||
|  | 
 | ||||||
|  |     const groupsQuery = useGroupsQuery(props.classId, props.assignmentNumber, true); | ||||||
|  | 
 | ||||||
|  |     interface GroupSelectorOption { | ||||||
|  |         groupNumber: number | undefined, | ||||||
|  |         label: string | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function groupOptions(groups: GroupDTO[]): GroupSelectorOption[] { | ||||||
|  |         return [...groups] | ||||||
|  |             .sort((a, b) => a.groupNumber - b.groupNumber) | ||||||
|  |             .map((group, index) => ({ | ||||||
|  |                 groupNumber: group.groupNumber, | ||||||
|  |                 label: `${index + 1}` | ||||||
|  |             })); | ||||||
|  |     } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |     <using-query-result | ||||||
|  |         :query-result="groupsQuery" | ||||||
|  |         v-slot="{ data }: { data: GroupsResponse }" | ||||||
|  |     > | ||||||
|  |         <v-select | ||||||
|  |             :label="t('viewAsGroup')" | ||||||
|  |             :items="groupOptions(data.groups)" | ||||||
|  |             v-model="model" | ||||||
|  |             item-title="label" | ||||||
|  |             class="group-selector-cb" | ||||||
|  |             variant="outlined" | ||||||
|  |             clearable | ||||||
|  |         ></v-select> | ||||||
|  |     </using-query-result> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <style scoped> | ||||||
|  |     .group-selector-cb { | ||||||
|  |         margin-top: 10px; | ||||||
|  |     } | ||||||
|  | </style> | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
|     import type { LearningPath } from "@/data-objects/learning-paths/learning-path.ts"; |     import type { LearningPath } from "@/data-objects/learning-paths/learning-path.ts"; | ||||||
|     import { computed, type ComputedRef, ref } from "vue"; |     import { computed, type ComputedRef, ref } from "vue"; | ||||||
|     import type { LearningObject } from "@/data-objects/learning-objects/learning-object.ts"; |     import type { LearningObject } from "@/data-objects/learning-objects/learning-object.ts"; | ||||||
|     import { useRoute } from "vue-router"; |     import {useRoute, useRouter} from "vue-router"; | ||||||
|     import LearningObjectView from "@/views/learning-paths/learning-object/LearningObjectView.vue"; |     import LearningObjectView from "@/views/learning-paths/learning-object/LearningObjectView.vue"; | ||||||
|     import { useI18n } from "vue-i18n"; |     import { useI18n } from "vue-i18n"; | ||||||
|     import LearningPathSearchField from "@/components/LearningPathSearchField.vue"; |     import LearningPathSearchField from "@/components/LearningPathSearchField.vue"; | ||||||
|  | @ -12,7 +12,9 @@ | ||||||
|     import UsingQueryResult from "@/components/UsingQueryResult.vue"; |     import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||||
|     import authService from "@/services/auth/auth-service.ts"; |     import authService from "@/services/auth/auth-service.ts"; | ||||||
|     import { LearningPathNode } from "@/data-objects/learning-paths/learning-path-node.ts"; |     import { LearningPathNode } from "@/data-objects/learning-paths/learning-path-node.ts"; | ||||||
|  |     import LearningPathGroupSelector from "@/views/learning-paths/LearningPathGroupSelector.vue"; | ||||||
| 
 | 
 | ||||||
|  |     const router = useRouter(); | ||||||
|     const route = useRoute(); |     const route = useRoute(); | ||||||
|     const { t } = useI18n(); |     const { t } = useI18n(); | ||||||
| 
 | 
 | ||||||
|  | @ -103,6 +105,15 @@ | ||||||
|         } |         } | ||||||
|         return "notCompleted"; |         return "notCompleted"; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     const forGroupQueryParam = computed<number | undefined>({ | ||||||
|  |         get: () => route.query.forGroup, | ||||||
|  |         set: (value: number | undefined) => { | ||||||
|  |             let query = structuredClone(route.query); | ||||||
|  |             query.forGroup = value; | ||||||
|  |             router.push({ query }); | ||||||
|  |         } | ||||||
|  |     }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|  | @ -147,6 +158,15 @@ | ||||||
|                     </p> |                     </p> | ||||||
|                 </template> |                 </template> | ||||||
|             </v-list-item> |             </v-list-item> | ||||||
|  |             <v-list-item v-if="query.classId && query.assignmentNo && authService.authState.activeRole === 'teacher'"> | ||||||
|  |                 <template v-slot:default> | ||||||
|  |                     <learning-path-group-selector | ||||||
|  |                         :class-id="query.classId" | ||||||
|  |                         :assignment-number="parseInt(query.assignmentNo)" | ||||||
|  |                         v-model="forGroupQueryParam" | ||||||
|  |                     /> | ||||||
|  |                 </template> | ||||||
|  |             </v-list-item> | ||||||
|             <v-divider></v-divider> |             <v-divider></v-divider> | ||||||
|             <div v-if="props.learningObjectHruid"> |             <div v-if="props.learningObjectHruid"> | ||||||
|                 <using-query-result |                 <using-query-result | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Gerald Schmittinger
						Gerald Schmittinger