feat: zie alle studenten van een klas
This commit is contained in:
		
							parent
							
								
									dd08738f99
								
							
						
					
					
						commit
						e5bdb9f621
					
				
					 4 changed files with 257 additions and 8 deletions
				
			
		|  | @ -28,7 +28,7 @@ export async function createClassHandler(req: Request, res: Response): Promise<v | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     res.status(201).json({ cls }); | ||||
|     res.status(201).json({ class: cls }); | ||||
| } | ||||
| 
 | ||||
| export async function getClassHandler(req: Request, res: Response): Promise<void> { | ||||
|  | @ -40,7 +40,7 @@ export async function getClassHandler(req: Request, res: Response): Promise<void | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     res.json(cls); | ||||
|     res.json({ class: cls }); | ||||
| } | ||||
| 
 | ||||
| export async function getClassStudentsHandler(req: Request, res: Response): Promise<void> { | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ export interface ClassesResponse { | |||
| } | ||||
| 
 | ||||
| export interface ClassResponse { | ||||
|     cls: ClassDTO; | ||||
|     class: ClassDTO; | ||||
| } | ||||
| 
 | ||||
| export interface TeacherInvitationsResponse { | ||||
|  |  | |||
|  | @ -1,7 +1,256 @@ | |||
| <script setup lang="ts"></script> | ||||
| <script setup lang="ts"> | ||||
|     import { useI18n } from "vue-i18n"; | ||||
|     import authState from "@/services/auth/auth-service.ts"; | ||||
|     import { computed, onMounted, ref, type ComputedRef } from "vue"; | ||||
|     import type { TeacherDTO } from "@dwengo-1/common/interfaces/teacher"; | ||||
|     import type { ClassDTO } from "@dwengo-1/common/interfaces/class"; | ||||
|     import type { TeacherInvitationDTO } from "@dwengo-1/common/interfaces/teacher-invitation"; | ||||
|     import { useTeacherClassesQuery } from "@/queries/teachers"; | ||||
|     import { useRoute } from "vue-router"; | ||||
|     import { ClassController, type ClassResponse } from "@/controllers/classes"; | ||||
|     import type { StudentsResponse } from "@/controllers/students"; | ||||
|     import { type StudentDTO } from "@dwengo-1/common/interfaces/student"; | ||||
| 
 | ||||
|     const { t } = useI18n(); | ||||
| 
 | ||||
|     // Username of logged in teacher | ||||
|     const username = ref<string | undefined>(undefined); | ||||
|     const classController: ClassController = new ClassController(); | ||||
| 
 | ||||
|     // find class id from route | ||||
|     const route = useRoute(); | ||||
|     const classId: string = route.params.id as string; | ||||
| 
 | ||||
|     const isLoading = ref(true); | ||||
|     const currentClass = ref<ClassDTO | undefined>(undefined); | ||||
|     const students = ref<StudentDTO[]>([]); | ||||
| 
 | ||||
|     // Find the username of the logged in user so it can be used to fetch other information | ||||
|     // When loading the page | ||||
|     onMounted(async () => { | ||||
|         const userObject = await authState.loadUser(); | ||||
|         username.value = userObject?.profile?.preferred_username ?? undefined; | ||||
| 
 | ||||
|         // get class of which information should be shown | ||||
|         const classResponse: ClassResponse = await classController.getById(classId); | ||||
|         console.log(classResponse); | ||||
|         if (classResponse && classResponse.class) { | ||||
|             currentClass.value = classResponse.class; | ||||
|             isLoading.value = false; | ||||
|         } | ||||
| 
 | ||||
|         // Fetch all students of the class | ||||
|         const studentsResponse: StudentsResponse = await classController.getStudents(classId); | ||||
|         if (studentsResponse && studentsResponse.students) students.value = studentsResponse.students as StudentDTO[]; | ||||
| 
 | ||||
|     }); | ||||
| 
 | ||||
|     // TODO: Boolean that handles visibility for dialogs | ||||
|     // Creating a class will generate a popup with the generated code | ||||
|     const dialog = ref(false); | ||||
| 
 | ||||
|     // TODO: waiting on frontend controllers | ||||
|     const invitations = ref<TeacherInvitationDTO[]>([]); | ||||
| 
 | ||||
|     // Function to handle a accepted invitation request | ||||
|     function acceptRequest(): void { | ||||
|         //TODO > waiting on updated frontend controllers | ||||
|         console.log("request accepted"); | ||||
|     } | ||||
| 
 | ||||
|     // Function to handle a denied invitation request | ||||
|     function denyRequest(): void { | ||||
|         //TODO > waiting on frontend controllers | ||||
|         console.log("request denied"); | ||||
|     } | ||||
| 
 | ||||
|     // remove student from class | ||||
|     function removeStudentFromclass(s: StudentDTO): void { | ||||
|         //TODO | ||||
|     } | ||||
| </script> | ||||
| <template> | ||||
|     <main></main> | ||||
| </template> | ||||
|     <main> | ||||
|         <div | ||||
|             v-if="isLoading" | ||||
|             class="text-center py-10" | ||||
|         > | ||||
|             <v-progress-circular | ||||
|                 indeterminate | ||||
|                 color="primary" | ||||
|             /> | ||||
|             <p>Loading...</p> | ||||
|         </div> | ||||
|         <div v-else> | ||||
|             <h1 class="title">{{ currentClass!.displayName }}</h1> | ||||
|             <v-container | ||||
|                 fluid | ||||
|                 class="ma-4" | ||||
|             > | ||||
|                 <v-row | ||||
|                     no-gutters | ||||
|                     fluid | ||||
|                 > | ||||
|                     <v-col | ||||
|                         cols="12" | ||||
|                         sm="6" | ||||
|                         md="6" | ||||
|                     > | ||||
|                         <v-table class="table"> | ||||
|                             <thead> | ||||
|                                 <tr> | ||||
|                                     <th class="header">{{ t("students") }}</th> | ||||
|                                     <th class="header"></th> | ||||
|                                 </tr> | ||||
|                             </thead> | ||||
|                             <tbody> | ||||
|                                 <tr | ||||
|                                     v-for="s in students" | ||||
|                                     :key="s.id" | ||||
|                                 > | ||||
|                                     <td> | ||||
|                                         {{ s.firstName + " " + s.lastName }} | ||||
|                                     </td> | ||||
|                                     <td> | ||||
|                                         <v-btn @click="removeStudentFromclass(s)"> remove </v-btn> | ||||
|                                     </td> | ||||
|                                 </tr> | ||||
|                             </tbody> | ||||
|                         </v-table> | ||||
|                     </v-col> | ||||
|                 </v-row> | ||||
|             </v-container> | ||||
| 
 | ||||
| <style scoped></style> | ||||
|             <h1 class="title"> | ||||
|                 {{ t("invitations") }} | ||||
|             </h1> | ||||
|             <v-table class="table"> | ||||
|                 <thead> | ||||
|                     <tr> | ||||
|                         <th class="header">{{ t("class") }}</th> | ||||
|                         <th class="header">{{ t("sender") }}</th> | ||||
|                         <th class="header"></th> | ||||
|                     </tr> | ||||
|                 </thead> | ||||
|                 <tbody> | ||||
|                     <tr | ||||
|                         v-for="i in invitations" | ||||
|                         :key="(i.class as ClassDTO).id" | ||||
|                     > | ||||
|                         <td> | ||||
|                             {{ (i.class as ClassDTO).displayName }} | ||||
|                         </td> | ||||
|                         <td>{{ (i.sender as TeacherDTO).firstName + " " + (i.sender as TeacherDTO).lastName }}</td> | ||||
|                         <td class="text-right"> | ||||
|                             <div> | ||||
|                                 <v-btn | ||||
|                                     color="green" | ||||
|                                     @click="acceptRequest" | ||||
|                                     class="mr-2" | ||||
|                                 > | ||||
|                                     {{ t("accept") }} | ||||
|                                 </v-btn> | ||||
|                                 <v-btn | ||||
|                                     color="red" | ||||
|                                     @click="denyRequest" | ||||
|                                 > | ||||
|                                     {{ t("deny") }} | ||||
|                                 </v-btn> | ||||
|                             </div> | ||||
|                         </td> | ||||
|                     </tr> | ||||
|                 </tbody> | ||||
|             </v-table> | ||||
|         </div> | ||||
|     </main> | ||||
| </template> | ||||
| <style scoped> | ||||
|     .header { | ||||
|         font-weight: bold !important; | ||||
|         background-color: #0e6942; | ||||
|         color: white; | ||||
|         padding: 10px; | ||||
|     } | ||||
| 
 | ||||
|     table thead th:first-child { | ||||
|         border-top-left-radius: 10px; | ||||
|     } | ||||
| 
 | ||||
|     .table thead th:last-child { | ||||
|         border-top-right-radius: 10px; | ||||
|     } | ||||
| 
 | ||||
|     .table tbody tr:nth-child(odd) { | ||||
|         background-color: white; | ||||
|     } | ||||
| 
 | ||||
|     .table tbody tr:nth-child(even) { | ||||
|         background-color: #f6faf2; | ||||
|     } | ||||
| 
 | ||||
|     td, | ||||
|     th { | ||||
|         border-bottom: 1px solid #0e6942; | ||||
|         border-top: 1px solid #0e6942; | ||||
|     } | ||||
| 
 | ||||
|     .table { | ||||
|         width: 90%; | ||||
|         padding-top: 10px; | ||||
|         border-collapse: collapse; | ||||
|     } | ||||
| 
 | ||||
|     h1 { | ||||
|         color: #0e6942; | ||||
|         text-transform: uppercase; | ||||
|         font-weight: bolder; | ||||
|         padding-top: 2%; | ||||
|         font-size: 50px; | ||||
|     } | ||||
| 
 | ||||
|     h2 { | ||||
|         color: #0e6942; | ||||
|         font-size: 30px; | ||||
|     } | ||||
| 
 | ||||
|     .join { | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         gap: 20px; | ||||
|         margin-top: 50px; | ||||
|     } | ||||
| 
 | ||||
|     .link { | ||||
|         color: #0b75bb; | ||||
|         text-decoration: underline; | ||||
|     } | ||||
| 
 | ||||
|     main { | ||||
|         margin-left: 30px; | ||||
|     } | ||||
| 
 | ||||
|     @media screen and (max-width: 800px) { | ||||
|         h1 { | ||||
|             text-align: center; | ||||
|             padding-left: 0; | ||||
|         } | ||||
| 
 | ||||
|         .join { | ||||
|             text-align: center; | ||||
|             align-items: center; | ||||
|             margin-left: 0; | ||||
|         } | ||||
| 
 | ||||
|         .sheet { | ||||
|             width: 100%; | ||||
|         } | ||||
| 
 | ||||
|         main { | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
|             align-items: center; | ||||
|             justify-content: center; | ||||
|             margin: 5px; | ||||
|         } | ||||
|     } | ||||
| </style> | ||||
|  |  | |||
|  | @ -85,7 +85,7 @@ | |||
|                     joinRequests: [], | ||||
|                 }; | ||||
|                 const classResponse: ClassResponse = await classController.createClass(classDto); | ||||
|                 const createdClass: ClassDTO = classResponse.cls; | ||||
|                 const createdClass: ClassDTO = classResponse.class; | ||||
|                 code.value = createdClass.id; | ||||
|                 dialog.value = true; | ||||
|                 showSnackbar(t("created"), "success"); | ||||
|  |  | |||
		Reference in a new issue
	
	 laurejablonski
						laurejablonski