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; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     res.status(201).json({ cls }); |     res.status(201).json({ class: cls }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getClassHandler(req: Request, res: Response): Promise<void> { | 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; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     res.json(cls); |     res.json({ class: cls }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getClassStudentsHandler(req: Request, res: Response): Promise<void> { | export async function getClassStudentsHandler(req: Request, res: Response): Promise<void> { | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ export interface ClassesResponse { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ClassResponse { | export interface ClassResponse { | ||||||
|     cls: ClassDTO; |     class: ClassDTO; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface TeacherInvitationsResponse { | 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> | <template> | ||||||
|     <main></main> |     <main> | ||||||
| </template> |         <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: [], |                     joinRequests: [], | ||||||
|                 }; |                 }; | ||||||
|                 const classResponse: ClassResponse = await classController.createClass(classDto); |                 const classResponse: ClassResponse = await classController.createClass(classDto); | ||||||
|                 const createdClass: ClassDTO = classResponse.cls; |                 const createdClass: ClassDTO = classResponse.class; | ||||||
|                 code.value = createdClass.id; |                 code.value = createdClass.id; | ||||||
|                 dialog.value = true; |                 dialog.value = true; | ||||||
|                 showSnackbar(t("created"), "success"); |                 showSnackbar(t("created"), "success"); | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 laurejablonski
						laurejablonski