feat(frontend): eerste queries voor assignments
This commit is contained in:
		
							parent
							
								
									ce5e9cd342
								
							
						
					
					
						commit
						45cb020861
					
				
					 10 changed files with 560 additions and 218 deletions
				
			
		
							
								
								
									
										44
									
								
								frontend/src/assets/assignment.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								frontend/src/assets/assignment.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| .container { | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     padding: 2%; | ||||
|     min-height: 100vh; | ||||
| } | ||||
| 
 | ||||
| .assignment-card { | ||||
|     width: 85%; | ||||
|     padding: 2%; | ||||
|     border-radius: 12px; | ||||
| } | ||||
| 
 | ||||
| .description { | ||||
|     margin-top: 2%; | ||||
|     line-height: 1.6; | ||||
|     font-size: 1.1rem; | ||||
| } | ||||
| 
 | ||||
| .top-right-btn { | ||||
|     position: absolute; | ||||
|     right: 2%; | ||||
|     color: red; | ||||
| } | ||||
| 
 | ||||
| .group-section { | ||||
|     margin-top: 2rem; | ||||
| } | ||||
| 
 | ||||
| .group-section h3 { | ||||
|     margin-bottom: 0.5rem; | ||||
| } | ||||
| 
 | ||||
| .group-section ul { | ||||
|     padding-left: 1.2rem; | ||||
|     list-style-type: disc; | ||||
| } | ||||
| 
 | ||||
| .subtitle-section { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
| } | ||||
|  | @ -13,15 +13,10 @@ import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts" | |||
| import type {ClassesResponse} from "@/controllers/classes.ts"; | ||||
| import type {AssignmentDTO} from "@dwengo-1/common/interfaces/assignment"; | ||||
| import {AssignmentController} from "@/controllers/assignments.ts"; | ||||
| import type {GroupDTO} from "@dwengo-1/common/interfaces/group"; | ||||
| import {GroupController} from "@/controllers/groups.ts"; | ||||
| 
 | ||||
| /*** | ||||
|  TODO: when clicking the assign button from lp page pass the lp-object in a state: | ||||
|  */ | ||||
| const props = defineProps<{ | ||||
|     learningPath?: LearningPath | null;  // Optional learningPath prop | ||||
| }>(); | ||||
| 
 | ||||
| const router = useRouter(); | ||||
| const {t, locale} = useI18n(); | ||||
|  | @ -48,26 +43,7 @@ async function submitForm(assignmentTitle: string, | |||
| 
 | ||||
|     //TODO: replace with query function | ||||
|     const controller: AssignmentController = new AssignmentController(selectedClass); | ||||
|     const response = await controller.createAssignment(assignmentDTO); | ||||
|     // Create groups | ||||
|     for (let i = 0; i < groups.length; i++) { | ||||
|         const group: GroupDTO = { | ||||
|             assignment: response.id, | ||||
|             groupNumber: i, | ||||
|             members: groups[i] | ||||
|         }; | ||||
| 
 | ||||
|         console.log("Posting group:", group); | ||||
| 
 | ||||
|         const groupController: GroupController = new GroupController(selectedClass, response.id); | ||||
| 
 | ||||
|         try { | ||||
|             await groupController.createGroup(group); | ||||
|             console.log("Group successfully posted:", group); | ||||
|         } catch (err) { | ||||
|             console.error("Group POST failed:", err); | ||||
|         } | ||||
|     } | ||||
|     await controller.createAssignment(assignmentDTO); | ||||
| 
 | ||||
|     await router.push('/user/assignment'); | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| <script setup lang="ts"> | ||||
| import {ref, defineProps, defineEmits} from 'vue'; | ||||
| import {useI18n} from 'vue-i18n'; | ||||
| import {useClassStudentsQuery} from "@/queries/classes.ts"; | ||||
| import {useClassStudentsQuery} from "@/queries/classes-temp.ts"; | ||||
| import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||
| import type {StudentsResponse} from "@/controllers/students.ts"; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,17 +1,55 @@ | |||
| import {useMutation, useQueryClient, type UseMutationReturnType} from "@tanstack/vue-query"; | ||||
| import {AssignmentController, type AssignmentResponse} from "@/controllers/assignments.ts"; | ||||
| import type {AssignmentDTO} from "@dwengo-1/common/interfaces/assignment"; | ||||
| import {toValue} from "vue"; | ||||
| import {computed, type MaybeRefOrGetter, toValue} from "vue"; | ||||
| import {useQuery, type UseQueryReturnType} from "@tanstack/vue-query"; | ||||
| import {AssignmentController, type AssignmentResponse, type AssignmentsResponse} from "@/controllers/assignments.ts"; | ||||
| import type {SubmissionsResponse} from "@/controllers/submissions.ts"; | ||||
| 
 | ||||
| export function useCreateAssignmentMutation(classId: string): UseMutationReturnType<AssignmentResponse, Error, AssignmentDTO, unknown> { | ||||
|     const queryClient = useQueryClient(); | ||||
| export function useAssignmentsQuery(classId: MaybeRefOrGetter<string | undefined>, full: MaybeRefOrGetter<boolean> = true): UseQueryReturnType<AssignmentsResponse, Error> { | ||||
|     const resolvedClassId = toValue(classId) as string; | ||||
|     const resolvedFull = toValue(full); | ||||
| 
 | ||||
|     const assignmentController = new AssignmentController(toValue(classId)); | ||||
| 
 | ||||
|     return useMutation({ | ||||
|         mutationFn: async (data) => assignmentController.createAssignment(data), | ||||
|         onSuccess: async () => { | ||||
|             await queryClient.invalidateQueries({queryKey: ["assignments"]}); | ||||
|         }, | ||||
|     }); | ||||
|     const assignmentController = new AssignmentController(resolvedClassId); | ||||
|     return useQuery({ | ||||
|         queryKey: computed(() => [ | ||||
|             'assignments', | ||||
|             resolvedClassId, | ||||
|             resolvedFull, | ||||
|         ]), | ||||
|         queryFn: async () => assignmentController.getAll(resolvedFull), | ||||
|         enabled: () => Boolean(resolvedClassId) | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| export function useAssignmentQuery(classId: MaybeRefOrGetter<string | undefined>, num: MaybeRefOrGetter<number>): UseQueryReturnType<AssignmentResponse, Error> { | ||||
|     const resolvedClassId = toValue(classId) as string; | ||||
|     const resolvedNum = toValue(num); | ||||
| 
 | ||||
|     const assignmentController = new AssignmentController(resolvedClassId); | ||||
|     return useQuery({ | ||||
|         queryKey: computed(() => [ | ||||
|             'assignment', | ||||
|             resolvedClassId, | ||||
|             resolvedNum, | ||||
|         ]), | ||||
|         queryFn: async () => assignmentController.getByNumber(resolvedNum), | ||||
|         enabled: () => Boolean(resolvedClassId) | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| export function useSubmissionsQuery(classId: MaybeRefOrGetter<string | undefined>, assignmentNum: MaybeRefOrGetter<number>, full: MaybeRefOrGetter<boolean>): UseQueryReturnType<SubmissionsResponse, Error> { | ||||
|     const resolvedClassId = toValue(classId) as string; | ||||
|     const resolvedNum = toValue(assignmentNum); | ||||
|     const resolvedFull = toValue(full); | ||||
| 
 | ||||
|     const assignmentController = new AssignmentController(resolvedClassId); | ||||
|     return useQuery({ | ||||
|         queryKey: computed(() => [ | ||||
|             'submissions', | ||||
|             resolvedClassId, | ||||
|             resolvedNum, | ||||
|             resolvedFull | ||||
|         ]), | ||||
|         queryFn: async () => assignmentController.getSubmissions(resolvedNum, resolvedFull), | ||||
|         enabled: () => Boolean(resolvedClassId) | ||||
|     }) | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import {useQuery, type UseQueryReturnType} from "@tanstack/vue-query"; | ||||
| import {computed, type MaybeRefOrGetter, toValue} from "vue"; | ||||
| import type {StudentsResponse} from "@/controllers/students.ts"; | ||||
| import {getClassController} from "@/controllers/controllers.ts"; | ||||
| import {computed, type MaybeRefOrGetter, toValue} from "vue"; | ||||
| import {useQuery, type UseQueryReturnType} from "@tanstack/vue-query"; | ||||
| import type {StudentsResponse} from "@/controllers/students.ts"; | ||||
| 
 | ||||
| const classController = getClassController(); | ||||
| 
 | ||||
|  | @ -9,7 +9,7 @@ function classStudentsQueryKey(classId: string, full: boolean): [string, string, | |||
|     return ["class-students", classId, full]; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //TODO: delete and use the one in classes.ts
 | ||||
| export function useClassStudentsQuery( | ||||
|     classId: MaybeRefOrGetter<string | undefined>, | ||||
|     full: MaybeRefOrGetter<boolean> = true, | ||||
							
								
								
									
										200
									
								
								frontend/src/views/assignments/Assignment.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								frontend/src/views/assignments/Assignment.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,200 @@ | |||
| <script setup lang="ts"> | ||||
| import { useRoute } from "vue-router"; | ||||
| import {ref, computed} from "vue"; | ||||
| import {useI18n} from "vue-i18n"; | ||||
| import auth from "@/services/auth/auth-service.ts"; | ||||
| import {AssignmentController} from "@/controllers/assignments.ts"; | ||||
| import {asyncComputed} from "@vueuse/core"; | ||||
| 
 | ||||
| 
 | ||||
| const {t, locale} = useI18n(); | ||||
| const language = computed(() => locale.value); | ||||
| const route = useRoute(); | ||||
| const assignmentId = ref(Number(route.params.id)); | ||||
| const classId = window.history.state?.class_id; | ||||
| const controller = new AssignmentController(classId); | ||||
| 
 | ||||
| const role = auth.authState.activeRole; | ||||
| const isTeacher = computed(() => role === 'teacher'); | ||||
| 
 | ||||
| const assignment = asyncComputed(async () => { | ||||
|     return await controller.getByNumber(assignmentId.value) | ||||
| }, null); | ||||
| 
 | ||||
| 
 | ||||
| const submitted = ref(true);//TODO: update by fetching submissions and check group | ||||
| 
 | ||||
| const submitAssignment = async () => { | ||||
|     //TODO | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /*** | ||||
|  // Display group members | ||||
|  const myGroup = computed(() => { | ||||
|  if (!assignment.value || !assignment.value.groups) return null; | ||||
|  console.log(assignment.value.groups) | ||||
|  return assignment.value.groups.find(group => | ||||
|  group.members.some(m => m.username === myUsername) | ||||
|  ); | ||||
|  }); | ||||
|  */ | ||||
| 
 | ||||
| const deleteAssignment = async () => { | ||||
|     await controller.deleteAssignment(assignmentId.value); | ||||
| }; | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|     <div class="container"> | ||||
|         <v-card v-if="assignment" class="assignment-card"> | ||||
|             <div class="top-buttons"> | ||||
|                 <v-btn | ||||
|                     icon | ||||
|                     variant="text" | ||||
|                     class="back-btn" | ||||
|                     to="/user/assignment" | ||||
|                 > | ||||
|                     <v-icon>mdi-arrow-left</v-icon> | ||||
|                 </v-btn> | ||||
| 
 | ||||
|                 <v-btn | ||||
|                     v-if="isTeacher" | ||||
|                     icon | ||||
|                     variant="text" | ||||
|                     class="top-right-btn" | ||||
|                     @click="deleteAssignment" | ||||
|                 > | ||||
|                     <v-icon>mdi-delete</v-icon> | ||||
|                 </v-btn> | ||||
|                 <v-chip | ||||
|                     v-if="!isTeacher" | ||||
|                     class="ma-2 top-right-btn" | ||||
|                     label | ||||
|                     color="success" | ||||
|                 > | ||||
|                     {{ t("submitted") }} | ||||
|                 </v-chip> | ||||
|             </div> | ||||
|             <v-card-title class="text-h4">{{ assignment.title }}</v-card-title> | ||||
|             <v-card-subtitle class="subtitle-section"> | ||||
|                 <v-btn | ||||
|                     :to="`/learningPath/${language}/${assignment.learningPath}`" | ||||
|                     variant="tonal" | ||||
|                     color="primary" | ||||
|                 > | ||||
|                     {{ t("learning-path") }} | ||||
|                 </v-btn> | ||||
|             </v-card-subtitle> | ||||
| 
 | ||||
|             <v-card-text class="description"> | ||||
|                 {{ assignment.description }} | ||||
|             </v-card-text> | ||||
| 
 | ||||
|             <v-card-text class="group-section"> | ||||
|                 <h3>{{ t("group") }}</h3> | ||||
| 
 | ||||
|                 <!-- Student view | ||||
|                 <div v-if="!isTeacher"> | ||||
|                     <div v-if="myGroup"> | ||||
|                         <ul> | ||||
|                             <li v-for="student in myGroup.members" :key="student.username"> | ||||
|                                 {{ student.firstName + ' ' + student.lastName}} | ||||
|                             </li> | ||||
|                         </ul> | ||||
|                     </div> | ||||
|                 </div>--> | ||||
| 
 | ||||
|                 <!-- Teacher view | ||||
|                 <div v-if="isTeacher"> | ||||
|                     <v-expansion-panels> | ||||
|                         <v-expansion-panel | ||||
|                             v-for="(group, index) in assignment.groups" | ||||
|                             :key="group.id" | ||||
|                         > | ||||
|                             <v-expansion-panel-title> | ||||
|                                 {{ t("group") }} {{ index + 1 }} | ||||
|                             </v-expansion-panel-title> | ||||
|                             <v-expansion-panel-text> | ||||
|                                 <ul> | ||||
|                                     <li v-for="student in group.members" :key="student.username"> | ||||
|                                         {{ student.firstName + ' ' + student.lastName }} | ||||
|                                     </li> | ||||
|                                 </ul> | ||||
|                             </v-expansion-panel-text> | ||||
|                         </v-expansion-panel> | ||||
|                     </v-expansion-panels> | ||||
|                 </div>--> | ||||
|             </v-card-text > | ||||
|             <v-card-actions class="justify-end"> | ||||
|                 <v-btn | ||||
|                     v-if="!isTeacher" | ||||
|                     size="large" | ||||
|                     color="success" | ||||
|                     variant="flat" | ||||
|                     @click="submitAssignment" | ||||
|                 > | ||||
|                     {{ t("submit") }} | ||||
|                 </v-btn> | ||||
|                 <v-btn | ||||
|                     v-if="isTeacher" | ||||
|                     size="large" | ||||
|                     color="success" | ||||
|                     variant="text" | ||||
|                 > | ||||
|                     {{ t("view-submissions") }} | ||||
|                 </v-btn> | ||||
|             </v-card-actions> | ||||
| 
 | ||||
|         </v-card> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| .container { | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     padding: 2%; | ||||
|     min-height: 100vh; | ||||
| } | ||||
| 
 | ||||
| .assignment-card { | ||||
|     width: 85%; | ||||
|     padding: 2%; | ||||
|     border-radius: 12px; | ||||
| } | ||||
| 
 | ||||
| .description { | ||||
|     margin-top: 2%; | ||||
|     line-height: 1.6; | ||||
|     font-size: 1.1rem; | ||||
| } | ||||
| 
 | ||||
| .top-right-btn { | ||||
|     position: absolute; | ||||
|     right: 2%; | ||||
|     color: red; | ||||
| } | ||||
| 
 | ||||
| .group-section { | ||||
|     margin-top: 2rem; | ||||
| } | ||||
| 
 | ||||
| .group-section h3 { | ||||
|     margin-bottom: 0.5rem; | ||||
| } | ||||
| 
 | ||||
| .group-section ul { | ||||
|     padding-left: 1.2rem; | ||||
|     list-style-type: disc; | ||||
| } | ||||
| 
 | ||||
| .subtitle-section { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
| } | ||||
| </style> | ||||
| 
 | ||||
|  | @ -1,162 +1,20 @@ | |||
| <script setup lang="ts"> | ||||
|     import { useRoute } from "vue-router"; | ||||
|     import {ref, computed} from "vue"; | ||||
|     import {useI18n} from "vue-i18n"; | ||||
| 
 | ||||
| import auth from "@/services/auth/auth-service.ts"; | ||||
|     import {AssignmentController} from "@/controllers/assignments.ts"; | ||||
|     import {asyncComputed} from "@vueuse/core"; | ||||
| 
 | ||||
| 
 | ||||
|     const {t, locale} = useI18n(); | ||||
|     const language = computed(() => locale.value); | ||||
|     const route = useRoute(); | ||||
|     const assignmentId = ref(Number(route.params.id)); | ||||
|     const classId = window.history.state?.class_id; | ||||
|     const controller = new AssignmentController(classId); | ||||
| import {computed} from "vue"; | ||||
| import StudentAssignment from "@/views/assignments/StudentAssignment.vue"; | ||||
| import TeacherAssignment from "@/views/assignments/TeacherAssignment.vue"; | ||||
| 
 | ||||
| const role = auth.authState.activeRole; | ||||
| const isTeacher = computed(() => role === 'teacher'); | ||||
| 
 | ||||
|     const assignment = asyncComputed(async () => { | ||||
|         return await controller.getByNumber(assignmentId.value) | ||||
|     }, null); | ||||
| 
 | ||||
| 
 | ||||
|     /*** | ||||
|     // Display group members | ||||
|     const myGroup = computed(() => { | ||||
|         if (!assignment.value || !assignment.value.groups) return null; | ||||
|         console.log(assignment.value.groups) | ||||
|         return assignment.value.groups.find(group => | ||||
|             group.members.some(m => m.username === myUsername) | ||||
|         ); | ||||
|     }); | ||||
|         */ | ||||
| 
 | ||||
|     const deleteAssignment = async () => { | ||||
|         await controller.deleteAssignment(assignmentId.value); | ||||
|     }; | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|     <div class="container"> | ||||
|         <v-card v-if="assignment" class="assignment-card"> | ||||
|             <div class="top-buttons"> | ||||
|                 <v-btn | ||||
|                     icon | ||||
|                     variant="text" | ||||
|                     class="back-btn" | ||||
|                     to="/user/assignment" | ||||
|                 > | ||||
|                     <v-icon>mdi-arrow-left</v-icon> | ||||
|                 </v-btn> | ||||
| 
 | ||||
|                 <v-btn | ||||
|                     v-if="isTeacher" | ||||
|                     icon | ||||
|                     variant="text" | ||||
|                     class="delete-btn" | ||||
|                     @click="deleteAssignment" | ||||
|                 > | ||||
|                     <v-icon>mdi-delete</v-icon> | ||||
|                 </v-btn> | ||||
|             </div> | ||||
|             <v-card-title class="text-h4">{{ assignment.title }}</v-card-title> | ||||
|             <v-card-subtitle> | ||||
|                 <v-btn | ||||
|                     :to="`/learningPath/${language}/${assignment.learningPath}`" | ||||
|                     variant="tonal" | ||||
|                     color="primary" | ||||
|                 > | ||||
|                     {{ t("learning-path") }} | ||||
|                 </v-btn> | ||||
|             </v-card-subtitle> | ||||
| 
 | ||||
|             <v-card-text class="description"> | ||||
|                 {{ assignment.description }} | ||||
|             </v-card-text> | ||||
| 
 | ||||
|             <v-card-text class="group-section"> | ||||
|                 <h3>{{ t("group") }}</h3> | ||||
| 
 | ||||
|                 <!-- Student view | ||||
|                 <div v-if="!isTeacher"> | ||||
|                     <div v-if="myGroup"> | ||||
|                         <ul> | ||||
|                             <li v-for="student in myGroup.members" :key="student.username"> | ||||
|                                 {{ student.firstName + ' ' + student.lastName}} | ||||
|                             </li> | ||||
|                         </ul> | ||||
|                     </div> | ||||
|                 </div>--> | ||||
| 
 | ||||
|                 <!-- Teacher view | ||||
|                 <div v-if="isTeacher"> | ||||
|                     <v-expansion-panels> | ||||
|                         <v-expansion-panel | ||||
|                             v-for="(group, index) in assignment.groups" | ||||
|                             :key="group.id" | ||||
|                         > | ||||
|                             <v-expansion-panel-title> | ||||
|                                 {{ t("group") }} {{ index + 1 }} | ||||
|                             </v-expansion-panel-title> | ||||
|                             <v-expansion-panel-text> | ||||
|                                 <ul> | ||||
|                                     <li v-for="student in group.members" :key="student.username"> | ||||
|                                         {{ student.firstName + ' ' + student.lastName }} | ||||
|                                     </li> | ||||
|                                 </ul> | ||||
|                             </v-expansion-panel-text> | ||||
|                         </v-expansion-panel> | ||||
|                     </v-expansion-panels> | ||||
|                 </div>--> | ||||
|             </v-card-text> | ||||
| 
 | ||||
|         </v-card> | ||||
|     </div> | ||||
|     <StudentAssignment v-if="!isTeacher"></StudentAssignment> | ||||
|     <TeacherAssignment v-else></TeacherAssignment> | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| .container { | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     padding: 2%; | ||||
|     min-height: 100vh; | ||||
| } | ||||
| 
 | ||||
| .assignment-card { | ||||
|     width: 85%; | ||||
|     padding: 2%; | ||||
|     border-radius: 12px; | ||||
| } | ||||
| 
 | ||||
| .description { | ||||
|     margin-top: 2%; | ||||
|     line-height: 1.6; | ||||
|     font-size: 1.1rem; | ||||
| } | ||||
| 
 | ||||
| .delete-btn { | ||||
|     position: absolute; | ||||
|     right: 1%; | ||||
|     color: red; | ||||
| } | ||||
| 
 | ||||
| .group-section { | ||||
|     margin-top: 2rem; | ||||
| } | ||||
| 
 | ||||
| .group-section h3 { | ||||
|     margin-bottom: 0.5rem; | ||||
| } | ||||
| 
 | ||||
| .group-section ul { | ||||
|     padding-left: 1.2rem; | ||||
|     list-style-type: disc; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| </style> | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										110
									
								
								frontend/src/views/assignments/StudentAssignment.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								frontend/src/views/assignments/StudentAssignment.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,110 @@ | |||
| <script setup lang="ts"> | ||||
| import { useRoute } from "vue-router"; | ||||
| import {ref, computed} from "vue"; | ||||
| import {useI18n} from "vue-i18n"; | ||||
| import {AssignmentController} from "@/controllers/assignments.ts"; | ||||
| import {asyncComputed} from "@vueuse/core"; | ||||
| 
 | ||||
| 
 | ||||
| const {t, locale} = useI18n(); | ||||
| const language = computed(() => locale.value); | ||||
| const route = useRoute(); | ||||
| const assignmentId = ref(Number(route.params.id)); | ||||
| const classId = window.history.state?.class_id; | ||||
| const controller = new AssignmentController(classId); | ||||
| 
 | ||||
| const assignment = asyncComputed(async () => { | ||||
|     return await controller.getByNumber(assignmentId.value) | ||||
| }, null); | ||||
| 
 | ||||
| const submitted = ref(true);//TODO: update by fetching submissions and check group | ||||
| 
 | ||||
| const submitAssignment = async () => { | ||||
|     //TODO | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /*** | ||||
|  // Display group members | ||||
|  const myGroup = computed(() => { | ||||
|  if (!assignment.value || !assignment.value.groups) return null; | ||||
|  console.log(assignment.value.groups) | ||||
|  return assignment.value.groups.find(group => | ||||
|  group.members.some(m => m.username === myUsername) | ||||
|  ); | ||||
|  }); | ||||
|  */ | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|     <div class="container"> | ||||
|         <v-card v-if="assignment" class="assignment-card"> | ||||
|             <div class="top-buttons"> | ||||
|                 <v-btn | ||||
|                     icon | ||||
|                     variant="text" | ||||
|                     class="back-btn" | ||||
|                     to="/user/assignment" | ||||
|                 > | ||||
|                     <v-icon>mdi-arrow-left</v-icon> | ||||
|                 </v-btn> | ||||
| 
 | ||||
|                 <v-chip | ||||
|                     class="ma-2 top-right-btn" | ||||
|                     label | ||||
|                     color="success" | ||||
|                 > | ||||
|                     {{ t("submitted") }} | ||||
|                 </v-chip> | ||||
|             </div> | ||||
|             <v-card-title class="text-h4">{{ assignment.title }}</v-card-title> | ||||
|             <v-card-subtitle class="subtitle-section"> | ||||
|                 <v-btn | ||||
|                     :to="`/learningPath/${language}/${assignment.learningPath}`" | ||||
|                     variant="tonal" | ||||
|                     color="primary" | ||||
|                 > | ||||
|                     {{ t("learning-path") }} | ||||
|                 </v-btn> | ||||
|             </v-card-subtitle> | ||||
| 
 | ||||
|             <v-card-text class="description"> | ||||
|                 {{ assignment.description }} | ||||
|             </v-card-text> | ||||
| 
 | ||||
|             <v-card-text class="group-section"> | ||||
|                 <h3>{{ t("group") }}</h3> | ||||
| 
 | ||||
|                 <!-- Student view | ||||
|                 <div v-if="!isTeacher"> | ||||
|                     <div v-if="myGroup"> | ||||
|                         <ul> | ||||
|                             <li v-for="student in myGroup.members" :key="student.username"> | ||||
|                                 {{ student.firstName + ' ' + student.lastName}} | ||||
|                             </li> | ||||
|                         </ul> | ||||
|                     </div> | ||||
|                 </div>--> | ||||
| 
 | ||||
|             </v-card-text > | ||||
|             <v-card-actions class="justify-end"> | ||||
|                 <v-btn | ||||
|                     size="large" | ||||
|                     color="success" | ||||
|                     variant="flat" | ||||
|                     @click="submitAssignment" | ||||
|                 > | ||||
|                     {{ t("submit") }} | ||||
|                 </v-btn> | ||||
|             </v-card-actions> | ||||
| 
 | ||||
|         </v-card> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| @import "@/assets/assignment.css"; | ||||
| 
 | ||||
| </style> | ||||
| 
 | ||||
							
								
								
									
										118
									
								
								frontend/src/views/assignments/TeacherAssignment.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								frontend/src/views/assignments/TeacherAssignment.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,118 @@ | |||
| <script setup lang="ts"> | ||||
| import {useRoute} from "vue-router"; | ||||
| import {ref, computed} from "vue"; | ||||
| import {useI18n} from "vue-i18n"; | ||||
| import {AssignmentController, type AssignmentResponse} from "@/controllers/assignments.ts"; | ||||
| import {useAssignmentQuery} from "@/queries/assignments.ts"; | ||||
| import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||
| 
 | ||||
| 
 | ||||
| const {t, locale} = useI18n(); | ||||
| const language = computed(() => locale.value); | ||||
| const route = useRoute(); | ||||
| const assignmentId = ref(Number(route.params.id)); | ||||
| const classId = window.history.state?.class_id; | ||||
| const controller = new AssignmentController(classId); | ||||
| 
 | ||||
| const assignmentQueryResult = useAssignmentQuery(() => classId, assignmentId); | ||||
| 
 | ||||
| /*** | ||||
|  // Display group members | ||||
|  const myGroup = computed(() => { | ||||
|  if (!assignment.value || !assignment.value.groups) return null; | ||||
|  console.log(assignment.value.groups) | ||||
|  return assignment.value.groups.find(group => | ||||
|  group.members.some(m => m.username === myUsername) | ||||
|  ); | ||||
|  }); | ||||
|  */ | ||||
| 
 | ||||
| const deleteAssignment = async () => { | ||||
|     await controller.deleteAssignment(assignmentId.value); | ||||
| }; | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|     <div class="container"> | ||||
|         <using-query-result | ||||
|             :query-result="assignmentQueryResult" | ||||
|             v-slot="{ data }: {data: AssignmentResponse}" | ||||
|         > | ||||
|             <v-card v-if="data" class="assignment-card"> | ||||
|                 <div class="top-buttons"> | ||||
|                     <v-btn | ||||
|                         icon | ||||
|                         variant="text" | ||||
|                         class="back-btn" | ||||
|                         to="/user/assignment" | ||||
|                     > | ||||
|                         <v-icon>mdi-arrow-left</v-icon> | ||||
|                     </v-btn> | ||||
| 
 | ||||
|                     <v-btn | ||||
|                         icon | ||||
|                         variant="text" | ||||
|                         class="top-right-btn" | ||||
|                         @click="deleteAssignment" | ||||
|                     > | ||||
|                         <v-icon>mdi-delete</v-icon> | ||||
|                     </v-btn> | ||||
|                 </div> | ||||
|                 <v-card-title class="text-h4">{{ data.title }}</v-card-title> | ||||
|                 <v-card-subtitle class="subtitle-section"> | ||||
|                     <v-btn | ||||
|                         :to="`/learningPath/${language}/${data.learningPath}`" | ||||
|                         variant="tonal" | ||||
|                         color="primary" | ||||
|                     > | ||||
|                         {{ t("learning-path") }} | ||||
|                     </v-btn> | ||||
|                 </v-card-subtitle> | ||||
| 
 | ||||
|                 <v-card-text class="description"> | ||||
|                     {{ data.description }} | ||||
|                 </v-card-text> | ||||
| 
 | ||||
|                 <v-card-text class="group-section"> | ||||
|                     <h3>{{ t("group") }}</h3> | ||||
| 
 | ||||
|                     <!-- Teacher view | ||||
|                     <div v-if="isTeacher"> | ||||
|                         <v-expansion-panels> | ||||
|                             <v-expansion-panel | ||||
|                                 v-for="(group, index) in assignment.groups" | ||||
|                                 :key="group.id" | ||||
|                             > | ||||
|                                 <v-expansion-panel-title> | ||||
|                                     {{ t("group") }} {{ index + 1 }} | ||||
|                                 </v-expansion-panel-title> | ||||
|                                 <v-expansion-panel-text> | ||||
|                                     <ul> | ||||
|                                         <li v-for="student in group.members" :key="student.username"> | ||||
|                                             {{ student.firstName + ' ' + student.lastName }} | ||||
|                                         </li> | ||||
|                                     </ul> | ||||
|                                 </v-expansion-panel-text> | ||||
|                             </v-expansion-panel> | ||||
|                         </v-expansion-panels> | ||||
|                     </div>--> | ||||
|                 </v-card-text> | ||||
|                 <v-card-actions class="justify-end"> | ||||
|                     <v-btn | ||||
|                         size="large" | ||||
|                         color="success" | ||||
|                         variant="text" | ||||
|                     > | ||||
|                         {{ t("view-submissions") }} | ||||
|                     </v-btn> | ||||
|                 </v-card-actions> | ||||
|             </v-card> | ||||
|         </using-query-result> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| @import "@/assets/assignment.css"; | ||||
| </style> | ||||
| 
 | ||||
|  | @ -27,14 +27,15 @@ if (isTeacher.value) { | |||
|     classesQueryResults = useStudentClassesQuery(username, true); | ||||
| } | ||||
| 
 | ||||
| //TODO: replace with query from classes | ||||
| const classController = new ClassController(); | ||||
| 
 | ||||
| 
 | ||||
| const assignments = asyncComputed(async () => { | ||||
|     const classes = classesQueryResults?.data?.value?.classes; | ||||
|     if (!classes) return []; | ||||
|     const result = await Promise.all( | ||||
|         (classes as ClassDTO[]).map(async (cls) => { | ||||
|             //TODO: replace by class queries | ||||
|             const {assignments} = await classController.getAssignments(cls.id); | ||||
|             return assignments.map(a => ({ | ||||
|                 id: a.id, | ||||
|  | @ -51,8 +52,6 @@ const assignments = asyncComputed(async () => { | |||
|     return result.flat(); | ||||
| }, []); | ||||
| 
 | ||||
| console.log(assignments); | ||||
| 
 | ||||
| 
 | ||||
| const goToCreateAssignment = async () => { | ||||
|     await router.push('/assignment/create'); | ||||
|  | @ -67,6 +66,7 @@ const goToAssignmentDetails = async (id: number, class_id: string) => { | |||
| 
 | ||||
| 
 | ||||
| const goToDeleteAssignment = async (id: number, class_id: string) => { | ||||
|     //TODO: replace with query | ||||
|     const controller = new AssignmentController(class_id); | ||||
|     await controller.deleteAssignment(id); | ||||
| }; | ||||
|  | @ -98,7 +98,6 @@ onMounted(async () => { | |||
|                     cols="12" | ||||
|                 > | ||||
|                     <v-card class="assignment-card"> | ||||
|                         <v-card-text class="card-content"> | ||||
|                         <div class="top-content"> | ||||
|                             <div class="assignment-title">{{ assignment.title }}</div> | ||||
|                             <div class="assignment-class"> | ||||
|  | @ -113,17 +112,16 @@ onMounted(async () => { | |||
| 
 | ||||
|                         <div class="button-row"> | ||||
|                             <v-btn color="primary" | ||||
|                                        size="small" | ||||
|                                    variant="text" | ||||
|                                    @click="goToAssignmentDetails(assignment.id, assignment.class.id)"> | ||||
|                                 {{ t('view-assignment') }} | ||||
|                             </v-btn> | ||||
|                             <v-btn v-if="isTeacher" color="red" | ||||
|                                        size="small" | ||||
|                                    variant="text" | ||||
|                                    @click="goToDeleteAssignment(assignment.id, assignment.class.id)"> | ||||
|                                 {{ t('delete') }} | ||||
|                             </v-btn> | ||||
|                         </div> | ||||
|                         </v-card-text> | ||||
|                     </v-card> | ||||
| 
 | ||||
|                 </v-col> | ||||
|  |  | |||
		Reference in a new issue
	
	 Joyelle Ndagijimana
						Joyelle Ndagijimana