diff --git a/frontend/src/queries/answers.ts b/frontend/src/queries/answers.ts index f2d0f9c4..830f3066 100644 --- a/frontend/src/queries/answers.ts +++ b/frontend/src/queries/answers.ts @@ -1,16 +1,35 @@ -import type { QuestionId } from "@dwengo-1/common/dist/interfaces/question.ts"; -import { type MaybeRefOrGetter, toValue } from "vue"; -import { useMutation, type UseMutationReturnType, useQuery, type UseQueryReturnType } from "@tanstack/vue-query"; -import { AnswerController, type AnswerResponse, type AnswersResponse } from "@/controllers/answers.ts"; -import type { AnswerData } from "@dwengo-1/common/dist/interfaces/answer.ts"; +import {computed, type MaybeRefOrGetter, toValue} from "vue"; +import { + useMutation, + type UseMutationReturnType, + useQuery, + type UseQueryReturnType, + useQueryClient, +} from "@tanstack/vue-query"; +import { + AnswerController, + type AnswerResponse, + type AnswersResponse, +} from "@/controllers/answers.ts"; +import type { AnswerData } from "@dwengo-1/common/interfaces/answer"; +import type {QuestionId} from "@dwengo-1/common/interfaces/question"; -// TODO caching +/** 🔑 Query keys */ +export function answersQueryKey(questionId: QuestionId, full: boolean): [string, string, number, string, number, boolean] { + const loId = questionId.learningObjectIdentifier; + return ["answers", loId.hruid, loId.version!, loId.language, questionId.sequenceNumber, full]; +} +export function answerQueryKey(questionId: QuestionId, sequenceNumber: number): [string, string, number, string, number, number] { + const loId = questionId.learningObjectIdentifier; + return ["answer", loId.hruid, loId.version!, loId.language, questionId.sequenceNumber, sequenceNumber]; +} export function useAnswersQuery( questionId: MaybeRefOrGetter, full: MaybeRefOrGetter = true, ): UseQueryReturnType { return useQuery({ + queryKey: computed(() => answersQueryKey(toValue(questionId), toValue(full))), queryFn: async () => new AnswerController(toValue(questionId)).getAll(toValue(full)), enabled: () => Boolean(toValue(questionId)), }); @@ -21,31 +40,69 @@ export function useAnswerQuery( sequenceNumber: MaybeRefOrGetter, ): UseQueryReturnType { return useQuery({ + queryKey: computed(() => answerQueryKey(toValue(questionId), toValue(sequenceNumber))), queryFn: async () => new AnswerController(toValue(questionId)).getBy(toValue(sequenceNumber)), - enabled: () => Boolean(toValue(questionId)), + enabled: () => Boolean(toValue(questionId)) && Boolean(toValue(sequenceNumber)), }); } export function useCreateAnswerMutation( questionId: MaybeRefOrGetter, ): UseMutationReturnType { + const queryClient = useQueryClient(); + return useMutation({ mutationFn: async (data) => new AnswerController(toValue(questionId)).create(data), + onSuccess: async () => { + await queryClient.invalidateQueries({ + queryKey: answersQueryKey(toValue(questionId), true), + }); + await queryClient.invalidateQueries({ + queryKey: answersQueryKey(toValue(questionId), false), + }); + }, }); } export function useDeleteAnswerMutation( questionId: MaybeRefOrGetter, ): UseMutationReturnType { + const queryClient = useQueryClient(); + return useMutation({ mutationFn: async (seq) => new AnswerController(toValue(questionId)).remove(seq), + onSuccess: async () => { + await queryClient.invalidateQueries({ + queryKey: answersQueryKey(toValue(questionId), true), + }); + await queryClient.invalidateQueries({ + queryKey: answersQueryKey(toValue(questionId), false), + }); + }, }); } export function useUpdateAnswerMutation( questionId: MaybeRefOrGetter, ): UseMutationReturnType { + const queryClient = useQueryClient(); + return useMutation({ - mutationFn: async (data, seq) => new AnswerController(toValue(questionId)).update(seq, data), + mutationFn: async ({ answerData, seq }) => + new AnswerController(toValue(questionId)).update(seq, answerData), + onSuccess: async (_, { seq }) => { + await queryClient.invalidateQueries({ + queryKey: answerQueryKey(toValue(questionId), seq), + }); + await queryClient.invalidateQueries({ + queryKey: answersQueryKey(toValue(questionId), true), + }); + await queryClient.invalidateQueries({ + queryKey: answersQueryKey(toValue(questionId), true), + }); + await queryClient.invalidateQueries({ + queryKey: answersQueryKey(toValue(questionId), false), + }); + }, }); } diff --git a/frontend/src/queries/questions.ts b/frontend/src/queries/questions.ts index b69164a4..66f1492f 100644 --- a/frontend/src/queries/questions.ts +++ b/frontend/src/queries/questions.ts @@ -14,12 +14,12 @@ export function questionsQueryKey( loId: LearningObjectIdentifierDTO, full: boolean, ): [string, string, number, string, boolean] { - return ["questions", loId.hruid, loId.version, loId.language, full]; + return ["questions", loId.hruid, loId.version!, loId.language, full]; } export function questionQueryKey(questionId: QuestionId): [string, string, number, string, number] { const loId = questionId.learningObjectIdentifier; - return ["question", loId.hruid, loId.version, loId.language, questionId.sequenceNumber]; + return ["question", loId.hruid, loId.version!, loId.language, questionId.sequenceNumber]; } export function useQuestionsQuery( @@ -39,7 +39,7 @@ export function useQuestionQuery( const loId = toValue(questionId).learningObjectIdentifier; const sequenceNumber = toValue(questionId).sequenceNumber; return useQuery({ - queryKey: computed(() => questionQueryKey(loId, sequenceNumber)), + queryKey: computed(() => questionQueryKey(toValue(questionId))), queryFn: async () => new QuestionController(loId).getBy(sequenceNumber), enabled: () => Boolean(toValue(questionId)), }); @@ -55,6 +55,7 @@ export function useCreateQuestionMutation( onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), true) }); await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), false) }); + await queryClient.invalidateQueries({ queryKey: ["answers"] }); }, }); } @@ -88,6 +89,8 @@ export function useDeleteQuestionMutation( await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), true) }); await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), false) }); await queryClient.invalidateQueries({ queryKey: questionQueryKey(toValue(questionId)) }); + await queryClient.invalidateQueries({ queryKey: ["answers"] }); + await queryClient.invalidateQueries({ queryKey: ["answer"] }); }, }); } diff --git a/frontend/src/queries/teacher-invitations.ts b/frontend/src/queries/teacher-invitations.ts index 59357c32..3e650343 100644 --- a/frontend/src/queries/teacher-invitations.ts +++ b/frontend/src/queries/teacher-invitations.ts @@ -1,36 +1,56 @@ -import { useMutation, useQuery, type UseMutationReturnType, type UseQueryReturnType } from "@tanstack/vue-query"; -import { computed, toValue } from "vue"; +import { + useMutation, + useQuery, + useQueryClient, + type UseMutationReturnType, + type UseQueryReturnType, +} from "@tanstack/vue-query"; +import { toValue } from "vue"; import type { MaybeRefOrGetter } from "vue"; import { TeacherInvitationController, type TeacherInvitationResponse, type TeacherInvitationsResponse, -} from "@/controllers/teacher-invitations.ts"; +} from "@/controllers/teacher-invitations"; import type { TeacherInvitationData } from "@dwengo-1/common/interfaces/teacher-invitation"; -import type { TeacherDTO } from "@dwengo-1/common/interfaces/teacher"; const controller = new TeacherInvitationController(); +/** 🔑 Query keys */ +export function teacherInvitationsSentQueryKey(username: string): [string, string, string] { + return ["teacher-invitations", "sent", username]; +} + +export function teacherInvitationsReceivedQueryKey(username: string): [string, string, string] { + return ["teacher-invitations", "received", username ]; +} + +export function teacherInvitationQueryKey(data: TeacherInvitationData): [string, string, string, string] { + return ["teacher-invitation", data.sender, data.receiver, data.class]; +} + /** - All the invitations the teacher sent -**/ + * All the invitations the teacher sent + */ export function useTeacherInvitationsSentQuery( username: MaybeRefOrGetter, ): UseQueryReturnType { return useQuery({ - queryFn: computed(async () => controller.getAll(toValue(username), true)), + queryKey: teacherInvitationsSentQueryKey(toValue(username)!), + queryFn: async () => controller.getAll(toValue(username)!, true), enabled: () => Boolean(toValue(username)), }); } /** - All the pending invitations sent to this teacher + * All the pending invitations sent to this teacher */ export function useTeacherInvitationsReceivedQuery( username: MaybeRefOrGetter, ): UseQueryReturnType { return useQuery({ - queryFn: computed(async () => controller.getAll(toValue(username), false)), + queryKey: teacherInvitationsReceivedQueryKey(toValue(username)!), + queryFn: async () => controller.getAll(toValue(username)!, false), enabled: () => Boolean(toValue(username)), }); } @@ -39,7 +59,8 @@ export function useTeacherInvitationQuery( data: MaybeRefOrGetter, ): UseQueryReturnType { return useQuery({ - queryFn: computed(async () => controller.getBy(toValue(data))), + queryKey: teacherInvitationQueryKey(toValue(data)!), + queryFn: async () => controller.getBy(toValue(data)!), enabled: () => Boolean(toValue(data)), }); } @@ -47,32 +68,68 @@ export function useTeacherInvitationQuery( export function useCreateTeacherInvitationMutation(): UseMutationReturnType< TeacherInvitationResponse, Error, - TeacherDTO, + TeacherInvitationData, unknown > { + const queryClient = useQueryClient(); + return useMutation({ - mutationFn: async (data: TeacherInvitationData) => controller.create(data), + mutationFn: async (data) => controller.create(data), + onSuccess: async (_, data) => { + await queryClient.invalidateQueries({ + queryKey: teacherInvitationsSentQueryKey(data.sender), + }); + await queryClient.invalidateQueries({ + queryKey: teacherInvitationsReceivedQueryKey(data.receiver), + }); + }, }); } export function useRespondTeacherInvitationMutation(): UseMutationReturnType< TeacherInvitationResponse, Error, - TeacherDTO, + TeacherInvitationData, unknown > { + const queryClient = useQueryClient(); + return useMutation({ - mutationFn: async (data: TeacherInvitationData) => controller.respond(data), + mutationFn: async (data) => controller.respond(data), + onSuccess: async (_, data) => { + await queryClient.invalidateQueries({ + queryKey: teacherInvitationsSentQueryKey(data.sender), + }); + await queryClient.invalidateQueries({ + queryKey: teacherInvitationsReceivedQueryKey(data.receiver), + }); + await queryClient.invalidateQueries({ + queryKey: teacherInvitationQueryKey(data), + }); + }, }); } export function useDeleteTeacherInvitationMutation(): UseMutationReturnType< TeacherInvitationResponse, Error, - TeacherDTO, + TeacherInvitationData, unknown > { + const queryClient = useQueryClient(); + return useMutation({ - mutationFn: async (data: TeacherInvitationData) => controller.remove(data), + mutationFn: async (data) => controller.remove(data), + onSuccess: async (_, data) => { + await queryClient.invalidateQueries({ + queryKey: teacherInvitationsSentQueryKey(data.sender), + }); + await queryClient.invalidateQueries({ + queryKey: teacherInvitationsReceivedQueryKey(data.receiver), + }); + await queryClient.invalidateQueries({ + queryKey: teacherInvitationQueryKey(data), + }); + }, }); } diff --git a/frontend/src/queries/teachers.ts b/frontend/src/queries/teachers.ts index 3e77f819..59da84f4 100644 --- a/frontend/src/queries/teachers.ts +++ b/frontend/src/queries/teachers.ts @@ -137,7 +137,7 @@ export function useUpdateJoinRequestMutation(): UseMutationReturnType< mutationFn: async ({ teacherUsername, classId, studentUsername, accepted }) => teacherController.updateStudentJoinRequest(teacherUsername, classId, studentUsername, accepted), onSuccess: async (deletedJoinRequest) => { - const username = deletedJoinRequest.request.requester; + const username = deletedJoinRequest.request.requester.username; const classId = deletedJoinRequest.request.class; await queryClient.invalidateQueries({ queryKey: studentJoinRequestsQueryKey(username) }); await queryClient.invalidateQueries({ queryKey: studentJoinRequestQueryKey(username, classId) }); diff --git a/frontend/src/queries/themes.ts b/frontend/src/queries/themes.ts index c3be25ae..ee197d14 100644 --- a/frontend/src/queries/themes.ts +++ b/frontend/src/queries/themes.ts @@ -1,7 +1,7 @@ import { useQuery, type UseQueryReturnType } from "@tanstack/vue-query"; import { type MaybeRefOrGetter, toValue } from "vue"; -import type { Theme } from "@dwengo-1/interfaces/theme"; import { getThemeController } from "@/controllers/controllers.ts"; +import type {Theme} from "@dwengo-1/common/interfaces/theme"; const themeController = getThemeController();