From 075616b67b4f901720fe65e8c7c67857632a118a Mon Sep 17 00:00:00 2001 From: Gabriellvl Date: Wed, 2 Apr 2025 13:00:31 +0200 Subject: [PATCH] refactor: type responses --- frontend/src/controllers/assignments.ts | 2 +- frontend/src/controllers/classes.ts | 2 +- frontend/src/controllers/groups.ts | 2 +- frontend/src/controllers/questions.ts | 2 +- frontend/src/controllers/students.ts | 8 +- frontend/src/controllers/submissions.ts | 2 +- frontend/src/controllers/teachers.ts | 6 +- frontend/src/queries/students.ts | 200 ++++++++++++++---------- frontend/src/queries/teachers.ts | 141 ++++++++++------- 9 files changed, 221 insertions(+), 144 deletions(-) diff --git a/frontend/src/controllers/assignments.ts b/frontend/src/controllers/assignments.ts index 7b275c25..6783b876 100644 --- a/frontend/src/controllers/assignments.ts +++ b/frontend/src/controllers/assignments.ts @@ -1,3 +1,3 @@ import type {AssignmentDTO} from "dwengo-1-common/src/interfaces/assignment"; -export type AssignmentsResponse = { assignments: AssignmentDTO[] }; // TODO ID +export interface AssignmentsResponse { assignments: AssignmentDTO[] } // TODO ID diff --git a/frontend/src/controllers/classes.ts b/frontend/src/controllers/classes.ts index 79475e00..76e57783 100644 --- a/frontend/src/controllers/classes.ts +++ b/frontend/src/controllers/classes.ts @@ -1,3 +1,3 @@ import type {ClassDTO} from "dwengo-1-common/src/interfaces/class"; -export type ClassesResponse = { classes: ClassDTO[] | string[] }; +export interface ClassesResponse { classes: ClassDTO[] | string[] } diff --git a/frontend/src/controllers/groups.ts b/frontend/src/controllers/groups.ts index bf946080..8de73049 100644 --- a/frontend/src/controllers/groups.ts +++ b/frontend/src/controllers/groups.ts @@ -1,3 +1,3 @@ import type {GroupDTO} from "dwengo-1-common/src/interfaces/group"; -export type GroupsResponse = { groups: GroupDTO[] }; // | TODO id +export interface GroupsResponse { groups: GroupDTO[] } // | TODO id diff --git a/frontend/src/controllers/questions.ts b/frontend/src/controllers/questions.ts index 40be2f37..14be81b1 100644 --- a/frontend/src/controllers/questions.ts +++ b/frontend/src/controllers/questions.ts @@ -1,3 +1,3 @@ import type {QuestionDTO, QuestionId} from "dwengo-1-common/src/interfaces/question"; -export type QuestionsResponse = { questions: QuestionDTO[] | QuestionId[] } +export interface QuestionsResponse { questions: QuestionDTO[] | QuestionId[] } diff --git a/frontend/src/controllers/students.ts b/frontend/src/controllers/students.ts index d221f5d3..9e81b03c 100644 --- a/frontend/src/controllers/students.ts +++ b/frontend/src/controllers/students.ts @@ -7,10 +7,10 @@ import type {SubmissionsResponse} from "@/controllers/submissions.ts"; import type {QuestionsResponse} from "@/controllers/questions.ts"; import type {ClassJoinRequestDTO} from "dwengo-1-common/src/interfaces/class-join-request"; -export type StudentsResponse = { students: StudentDTO[] | string[] }; -export type StudentResponse = { student: StudentDTO }; -export type JoinRequestsResponse = { requests: ClassJoinRequestDTO[] }; -export type JoinRequestResponse = { request: ClassJoinRequestDTO }; +export interface StudentsResponse { students: StudentDTO[] | string[] } +export interface StudentResponse { student: StudentDTO } +export interface JoinRequestsResponse { requests: ClassJoinRequestDTO[] } +export interface JoinRequestResponse { request: ClassJoinRequestDTO } export class StudentController extends BaseController { diff --git a/frontend/src/controllers/submissions.ts b/frontend/src/controllers/submissions.ts index f3f23f85..40816932 100644 --- a/frontend/src/controllers/submissions.ts +++ b/frontend/src/controllers/submissions.ts @@ -1,3 +1,3 @@ import {type SubmissionDTO, SubmissionDTOId} from "dwengo-1-common/src/interfaces/submission"; -export type SubmissionsResponse = { submissions: SubmissionDTO[] | SubmissionDTOId[] }; +export interface SubmissionsResponse { submissions: SubmissionDTO[] | SubmissionDTOId[] } diff --git a/frontend/src/controllers/teachers.ts b/frontend/src/controllers/teachers.ts index f6162818..e338053d 100644 --- a/frontend/src/controllers/teachers.ts +++ b/frontend/src/controllers/teachers.ts @@ -4,8 +4,8 @@ import type {QuestionsResponse} from "@/controllers/questions.ts"; import type {ClassesResponse} from "@/controllers/classes.ts"; import type {TeacherDTO} from "dwengo-1-common/src/interfaces/teacher"; -export type TeachersResponse = { teachers: TeacherDTO[] | string[] }; -export type TeacherResponse = { teacher: TeacherDTO | string }; +export interface TeachersResponse { teachers: TeacherDTO[] | string[] } +export interface TeacherResponse { teacher: TeacherDTO | string } export class TeacherController extends BaseController { @@ -21,7 +21,7 @@ export class TeacherController extends BaseController { return this.get(`/${username}`); } - async createTeacher(data: any): Promise { + async createTeacher(data: TeacherDTO): Promise { return this.post("/", data); } diff --git a/frontend/src/queries/students.ts b/frontend/src/queries/students.ts index 810c5529..0105c346 100644 --- a/frontend/src/queries/students.ts +++ b/frontend/src/queries/students.ts @@ -1,28 +1,69 @@ import { computed, toValue } from "vue"; import type { MaybeRefOrGetter } from "vue"; -import { useMutation, useQuery, useQueryClient } from "@tanstack/vue-query"; -import { StudentController } from "@/controllers/students.ts"; +import { + useMutation, + type UseMutationReturnType, + useQuery, + useQueryClient, + type UseQueryReturnType +} from "@tanstack/vue-query"; +import { + type JoinRequestResponse, + type JoinRequestsResponse, + StudentController, + type StudentResponse, + type StudentsResponse +} from "@/controllers/students.ts"; +import type {ClassesResponse} from "@/controllers/classes.ts"; +import type {AssignmentsResponse} from "@/controllers/assignments.ts"; +import type {GroupsResponse} from "@/controllers/groups.ts"; +import type {SubmissionsResponse} from "@/controllers/submissions.ts"; +import type {QuestionsResponse} from "@/controllers/questions.ts"; +import type {StudentDTO} from "dwengo-1-common/src/interfaces/student"; const studentController = new StudentController(); /** 🔑 Query keys */ -const STUDENTS_QUERY_KEY = (full: boolean) => ["students", full]; -const STUDENT_QUERY_KEY = (username: string) => ["student", username]; -const STUDENT_CLASSES_QUERY_KEY = (username: string, full: boolean) => ["student-classes", username, full]; -const STUDENT_ASSIGNMENTS_QUERY_KEY = (username: string, full: boolean) => ["student-assignments", username, full]; -const STUDENT_GROUPS_QUERY_KEY = (username: string, full: boolean) => ["student-groups", username, full]; -const STUDENT_SUBMISSIONS_QUERY_KEY = (username: string) => ["student-submissions", username]; -const STUDENT_QUESTIONS_QUERY_KEY = (username: string, full: boolean) => ["student-questions", username, full]; -const STUDENT_JOIN_REQUESTS_QUERY_KEY = (username: string) => ["student-join-requests", username]; +function STUDENTS_QUERY_KEY(full: boolean): [string, boolean] { + return ["students", full]; +} +function STUDENT_QUERY_KEY(username: string): [string, string] { + return ["student", username]; +} +function STUDENT_CLASSES_QUERY_KEY(username: string, full: boolean): [string, string, boolean] { + return ["student-classes", username, full]; +} +function STUDENT_ASSIGNMENTS_QUERY_KEY(username: string, full: boolean): [string, string, boolean] { + return ["student-assignments", username, full]; +} +function STUDENT_GROUPS_QUERY_KEY(username: string, full: boolean): [string, string, boolean] { + return ["student-groups", username, full]; +} +function STUDENT_SUBMISSIONS_QUERY_KEY(username: string): [string, string] { + return ["student-submissions", username]; +} +function STUDENT_QUESTIONS_QUERY_KEY(username: string, full: boolean): [string, string, boolean] { + return ["student-questions", username, full]; +} +function STUDENT_JOIN_REQUESTS_QUERY_KEY(username: string): [string, string] { + return ["student-join-requests", username]; +} +function STUDENT_JOIN_REQUEST_QUERY_KEY(username: string, classId: string): [string, string, string] { + return ["student-join-request", username, classId]; +} -export function useStudentsQuery(full: MaybeRefOrGetter = true) { +export function useStudentsQuery( + full: MaybeRefOrGetter = true +): UseQueryReturnType { return useQuery({ queryKey: computed(() => STUDENTS_QUERY_KEY(toValue(full))), queryFn: async () => studentController.getAll(toValue(full)), }); } -export function useStudentQuery(username: MaybeRefOrGetter) { +export function useStudentQuery( + username: MaybeRefOrGetter +): UseQueryReturnType { return useQuery({ queryKey: computed(() => STUDENT_QUERY_KEY(toValue(username)!)), queryFn: async () => studentController.getByUsername(toValue(username)!), @@ -32,8 +73,8 @@ export function useStudentQuery(username: MaybeRefOrGetter) export function useStudentClassesQuery( username: MaybeRefOrGetter, - full: MaybeRefOrGetter = true, -) { + full: MaybeRefOrGetter = true +): UseQueryReturnType { return useQuery({ queryKey: computed(() => STUDENT_CLASSES_QUERY_KEY(toValue(username)!, toValue(full))), queryFn: async () => studentController.getClasses(toValue(username)!, toValue(full)), @@ -43,8 +84,8 @@ export function useStudentClassesQuery( export function useStudentAssignmentsQuery( username: MaybeRefOrGetter, - full: MaybeRefOrGetter = true, -) { + full: MaybeRefOrGetter = true +): UseQueryReturnType { return useQuery({ queryKey: computed(() => STUDENT_ASSIGNMENTS_QUERY_KEY(toValue(username)!, toValue(full))), queryFn: async () => studentController.getAssignments(toValue(username)!, toValue(full)), @@ -54,8 +95,8 @@ export function useStudentAssignmentsQuery( export function useStudentGroupsQuery( username: MaybeRefOrGetter, - full: MaybeRefOrGetter = true, -) { + full: MaybeRefOrGetter = true +): UseQueryReturnType { return useQuery({ queryKey: computed(() => STUDENT_GROUPS_QUERY_KEY(toValue(username)!, toValue(full))), queryFn: async () => studentController.getGroups(toValue(username)!, toValue(full)), @@ -63,7 +104,9 @@ export function useStudentGroupsQuery( }); } -export function useStudentSubmissionsQuery(username: MaybeRefOrGetter) { +export function useStudentSubmissionsQuery( + username: MaybeRefOrGetter +): UseQueryReturnType { return useQuery({ queryKey: computed(() => STUDENT_SUBMISSIONS_QUERY_KEY(toValue(username)!)), queryFn: async () => studentController.getSubmissions(toValue(username)!), @@ -73,8 +116,8 @@ export function useStudentSubmissionsQuery(username: MaybeRefOrGetter, - full: MaybeRefOrGetter = true, -) { + full: MaybeRefOrGetter = true +): UseQueryReturnType { return useQuery({ queryKey: computed(() => STUDENT_QUESTIONS_QUERY_KEY(toValue(username)!, toValue(full))), queryFn: async () => studentController.getQuestions(toValue(username)!, toValue(full)), @@ -82,38 +125,9 @@ export function useStudentQuestionsQuery( }); } -export function useCreateStudentMutation() { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async (data: any) => studentController.createStudent(data), - onSuccess: () => { - await queryClient.invalidateQueries({ queryKey: ["students"] }); - }, - onError: (err) => { - alert("Create student failed:", err); - }, - }); -} - -// TODO -// Setquerydata -// Previous students -export function useDeleteStudentMutation() { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async (username: string) => studentController.deleteStudent(username), - onSuccess: () => { - await queryClient.invalidateQueries({ queryKey: ["students"] }); - }, - onError: (err) => { - alert("Delete student failed:", err); - }, - }); -} - -export function useStudentJoinRequestsQuery(username: MaybeRefOrGetter) { +export function useStudentJoinRequestsQuery( + username: MaybeRefOrGetter +): UseQueryReturnType { return useQuery({ queryKey: computed(() => STUDENT_JOIN_REQUESTS_QUERY_KEY(toValue(username)!)), queryFn: async () => studentController.getJoinRequests(toValue(username)!), @@ -123,47 +137,75 @@ export function useStudentJoinRequestsQuery(username: MaybeRefOrGetter, - classId: MaybeRefOrGetter, -) { + classId: MaybeRefOrGetter +): UseQueryReturnType { return useQuery({ - queryKey: computed(() => STUDENT_JOIN_REQUESTS_QUERY_KEY(toValue(username)!)), + queryKey: computed(() => STUDENT_JOIN_REQUEST_QUERY_KEY(toValue(username)!, toValue(classId)!)), queryFn: async () => studentController.getJoinRequest(toValue(username)!, toValue(classId)!), - enabled: () => Boolean(toValue(username)), + enabled: () => Boolean(toValue(username)) && Boolean(toValue(classId)), }); } -/** - * Mutation to create a join request for a class - */ -export function useCreateJoinRequestMutation() { +export function useCreateStudentMutation(): UseMutationReturnType< + StudentResponse, + Error, + StudentDTO, + unknown +> { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ username, classId }: { username: string; classId: string }) => - studentController.createJoinRequest(username, classId), - onSuccess: (_, { username }) => { - await queryClient.invalidateQueries({ queryKey: STUDENT_JOIN_REQUESTS_QUERY_KEY(username) }); - }, - onError: (err) => { - alert("Create join request failed:", err); + mutationFn: async (data) => studentController.createStudent(data), + onSuccess: async () => { + await queryClient.invalidateQueries({ queryKey: ["students"] }); }, }); } -/** - * Mutation to delete a join request for a class - */ -export function useDeleteJoinRequestMutation() { +export function useDeleteStudentMutation(): UseMutationReturnType< + StudentResponse, + Error, + string, + unknown +> { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ username, classId }: { username: string; classId: string }) => - studentController.deleteJoinRequest(username, classId), - onSuccess: (_, { username }) => { - await queryClient.invalidateQueries({ queryKey: STUDENT_JOIN_REQUESTS_QUERY_KEY(username) }); - }, - onError: (err) => { - alert("Delete join request failed:", err); + mutationFn: async (username) => studentController.deleteStudent(username), + onSuccess: async () => { + await queryClient.invalidateQueries({ queryKey: ["students"] }); + }, + }); +} + +export function useCreateJoinRequestMutation(): UseMutationReturnType< + JoinRequestResponse, + Error, + { username: string; classId: string }, + unknown +> { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ({ username, classId }) => studentController.createJoinRequest(username, classId), + onSuccess: async ({ username }) => { + await queryClient.invalidateQueries({ queryKey: STUDENT_JOIN_REQUESTS_QUERY_KEY(username) }); + }, + }); +} + +export function useDeleteJoinRequestMutation(): UseMutationReturnType< + JoinRequestResponse, + Error, + { username: string; classId: string }, + unknown +> { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ({ username, classId }) => studentController.deleteJoinRequest(username, classId), + onSuccess: async ({ username }) => { + await queryClient.invalidateQueries({ queryKey: STUDENT_JOIN_REQUESTS_QUERY_KEY(username) }); }, }); } diff --git a/frontend/src/queries/teachers.ts b/frontend/src/queries/teachers.ts index 3daf9e1f..c4d35919 100644 --- a/frontend/src/queries/teachers.ts +++ b/frontend/src/queries/teachers.ts @@ -1,125 +1,160 @@ import { computed, toValue } from "vue"; import type { MaybeRefOrGetter } from "vue"; -import { useQuery, useMutation, useQueryClient } from "@tanstack/vue-query"; -import { TeacherController } from "@/controllers/teachers.ts"; +import { + useMutation, + useQuery, + useQueryClient, + UseMutationReturnType, + UseQueryReturnType, +} from "@tanstack/vue-query"; +import {TeacherController, type TeacherResponse, type TeachersResponse} from "@/controllers/teachers.ts"; +import type { + TeacherDTO, + ClassDTO, + StudentDTO, + QuestionDTO, + QuestionId, + JoinRequestDTO, +} from "dwengo-1-common/src/interfaces"; +import type {ClassesResponse} from "@/controllers/classes.ts"; +import type {JoinRequestResponse, JoinRequestsResponse, StudentsResponse} from "@/controllers/students.ts"; +import type {QuestionsResponse} from "@/controllers/questions.ts"; // pas dit aan naar jouw pad indien nodig const teacherController = new TeacherController(); /** 🔑 Query keys */ -const TEACHERS_QUERY_KEY = (full: boolean) => ["teachers", full]; -const TEACHER_QUERY_KEY = (username: string) => ["teacher", username]; -const TEACHER_CLASSES_QUERY_KEY = (username: string, full: boolean) => ["teacher-classes", username, full]; -const TEACHER_STUDENTS_QUERY_KEY = (username: string, full: boolean) => ["teacher-students", username, full]; -const TEACHER_QUESTIONS_QUERY_KEY = (username: string, full: boolean) => ["teacher-questions", username, full]; -const JOIN_REQUESTS_QUERY_KEY = (username: string, classId: string) => ["join-requests", username, classId]; +function TEACHERS_QUERY_KEY(full: boolean): [string, boolean] { + return ["teachers", full]; +} -export function useTeachersQuery(full: MaybeRefOrGetter = false) { +function TEACHER_QUERY_KEY(username: string): [string, string] { + return ["teacher", username]; +} + +function TEACHER_CLASSES_QUERY_KEY(username: string, full: boolean): [string, string, boolean] { + return ["teacher-classes", username, full]; +} + +function TEACHER_STUDENTS_QUERY_KEY(username: string, full: boolean): [string, string, boolean] { + return ["teacher-students", username, full]; +} + +function TEACHER_QUESTIONS_QUERY_KEY(username: string, full: boolean): [string, string, boolean] { + return ["teacher-questions", username, full]; +} + + +export function useTeachersQuery( + full: MaybeRefOrGetter = false +): UseQueryReturnType { return useQuery({ queryKey: computed(() => TEACHERS_QUERY_KEY(toValue(full))), - queryFn: async () => teacherController.getAll(toValue(full)), + queryFn: () => teacherController.getAll(toValue(full)), }); } -export function useTeacherQuery(username: MaybeRefOrGetter) { +export function useTeacherQuery( + username: MaybeRefOrGetter +): UseQueryReturnType { return useQuery({ queryKey: computed(() => TEACHER_QUERY_KEY(toValue(username)!)), - queryFn: async () => teacherController.getByUsername(toValue(username)!), + queryFn: () => teacherController.getByUsername(toValue(username)!), enabled: () => Boolean(toValue(username)), }); } export function useTeacherClassesQuery( username: MaybeRefOrGetter, - full: MaybeRefOrGetter = false, -) { + full: MaybeRefOrGetter = false +): UseQueryReturnType { return useQuery({ queryKey: computed(() => TEACHER_CLASSES_QUERY_KEY(toValue(username)!, toValue(full))), - queryFn: async () => teacherController.getClasses(toValue(username)!, toValue(full)), + queryFn: () => teacherController.getClasses(toValue(username)!, toValue(full)), enabled: () => Boolean(toValue(username)), }); } export function useTeacherStudentsQuery( username: MaybeRefOrGetter, - full: MaybeRefOrGetter = false, -) { + full: MaybeRefOrGetter = false +): UseQueryReturnType { return useQuery({ queryKey: computed(() => TEACHER_STUDENTS_QUERY_KEY(toValue(username)!, toValue(full))), - queryFn: async () => teacherController.getStudents(toValue(username)!, toValue(full)), + queryFn: () => teacherController.getStudents(toValue(username)!, toValue(full)), enabled: () => Boolean(toValue(username)), }); } export function useTeacherQuestionsQuery( username: MaybeRefOrGetter, - full: MaybeRefOrGetter = false, -) { + full: MaybeRefOrGetter = false +): UseQueryReturnType { return useQuery({ queryKey: computed(() => TEACHER_QUESTIONS_QUERY_KEY(toValue(username)!, toValue(full))), - queryFn: async () => teacherController.getQuestions(toValue(username)!, toValue(full)), + queryFn: () => teacherController.getQuestions(toValue(username)!, toValue(full)), enabled: () => Boolean(toValue(username)), }); } export function useTeacherJoinRequestsQuery( username: MaybeRefOrGetter, - classId: MaybeRefOrGetter, -) { + classId: MaybeRefOrGetter +): UseQueryReturnType { return useQuery({ queryKey: computed(() => JOIN_REQUESTS_QUERY_KEY(toValue(username)!, toValue(classId)!)), - queryFn: async () => teacherController.getStudentJoinRequests(toValue(username)!, toValue(classId)!), + queryFn: () => teacherController.getStudentJoinRequests(toValue(username)!, toValue(classId)!), enabled: () => Boolean(toValue(username)) && Boolean(toValue(classId)), }); } -export function useCreateTeacherMutation() { +export function useCreateTeacherMutation(): UseMutationReturnType< + TeacherResponse, + Error, + TeacherDTO, + unknown +> { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async (data: any) => teacherController.createTeacher(data), - onSuccess: () => { + mutationFn: (data: TeacherDTO) => teacherController.createTeacher(data), + onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["teachers"] }); }, - onError: (err) => { - alert("Create teacher failed:", err); - }, }); } -export function useDeleteTeacherMutation() { +export function useDeleteTeacherMutation(): UseMutationReturnType< + TeacherResponse, + Error, + string, + unknown +> { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async (username: string) => teacherController.deleteTeacher(username), - onSuccess: () => { + mutationFn: (username: string) => teacherController.deleteTeacher(username), + onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["teachers"] }); }, - onError: (err) => { - alert("Delete teacher failed:", err); - }, }); } -export function useUpdateJoinRequestMutation() { +export function useUpdateJoinRequestMutation(): UseMutationReturnType< + JoinRequestResponse, + Error, + { teacherUsername: string; classId: string; studentUsername: string; accepted: boolean }, + unknown +> { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ - teacherUsername, - classId, - studentUsername, - accepted, - }: { - teacherUsername: string; - classId: string; - studentUsername: string; - accepted: boolean; - }) => teacherController.updateStudentJoinRequest(teacherUsername, classId, studentUsername, accepted), - onSuccess: (_, { teacherUsername, classId }) => { - queryClient.invalidateQueries({ queryKey: JOIN_REQUESTS_QUERY_KEY(teacherUsername, classId) }); - }, - onError: (err) => { - alert("Failed to update join request:", err); + mutationFn: ({ teacherUsername, classId, studentUsername, accepted }) => + teacherController.updateStudentJoinRequest(teacherUsername, classId, studentUsername, accepted), + onSuccess: async (_, { teacherUsername, classId }) => { + await queryClient.invalidateQueries({ + queryKey: JOIN_REQUESTS_QUERY_KEY(teacherUsername, classId), + // TODO + }); }, }); }