Skip to content

Commit

Permalink
implement patch mutation
Browse files Browse the repository at this point in the history
  • Loading branch information
reyniersbram committed May 22, 2024
1 parent ccb7424 commit e87c832
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
</template>

<script setup lang="ts">
import { ref, toRefs, watch } from "vue";
import useAcademicYear from "@/composables/useAcademicYear";
import { computed, ref, toRefs, watch } from "vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
Expand All @@ -86,8 +87,16 @@ watch(currentUserAsInstructor, (newValue) => {
const subjectName = ref(props.subjectName);
const activeAcademicYear = ref<number>(props.academicYear);
const subjectMail = ref(props.subjectMail);
const academicYearItems = [activeAcademicYear.value, activeAcademicYear.value + 1];
const currentAcademicYear = useAcademicYear();
const academicYearItems = computed(() => {
const years = [currentAcademicYear];
if (activeAcademicYear.value !== currentAcademicYear) {
years.push(activeAcademicYear.value);
}
years.push(activeAcademicYear.value + 1);
return years;
});
const rules = {
required: (value: string) => !!value || t("create_subject.field_required"),
length: (value: string) => value.length > 2 || t("create_subject.field_length"),
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/models/Subject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface SubjectDetails {
role: SubjectRole;
}

export default interface SubjectForm {
export interface SubjectForm {
name: string;
email: string;
academic_year: number;
Expand Down
62 changes: 61 additions & 1 deletion frontend/src/queries/Subject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import {
getSubjectUuid,
createSubject,
createSubjectInstructor,
updateSubject,
deleteSubjectInstructor,
} from "@/services/subject";
import { getSubjectProjects } from "@/services/project";
import type User from "@/models/User";
import type Subject from "@/models/Subject";
import type { UserSubjectList } from "@/models/Subject";
import type Project from "@/models/Project";
import type SubjectForm from "@/models/Subject";
import type { SubjectForm } from "@/models/Subject";

function SUBJECT_QUERY_KEY(subjectId: number | string): (string | number)[] {
return ["subject", subjectId];
Expand Down Expand Up @@ -172,6 +174,31 @@ export function useCreateSubjectMutation(): UseMutationReturnType<
});
}

export function useUpdateSubjectMutation(): UseMutationReturnType<
void,
Error,
{ subjectId: number; subject: SubjectForm },
Subject
> {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ subjectId, subject }) => updateSubject(subjectId, subject),
onMutate: ({ subjectId, subject }) => {
const previousSubject = queryClient.getQueryData<Subject>(SUBJECT_QUERY_KEY(subjectId));
queryClient.cancelQueries({ queryKey: SUBJECT_QUERY_KEY(subjectId) });
queryClient.setQueryData(SUBJECT_QUERY_KEY(subjectId), subject);
return previousSubject;
},
onSuccess: (_, { subjectId }) => {
queryClient.invalidateQueries({ queryKey: SUBJECT_QUERY_KEY(subjectId) });
},
onError: (_, { subjectId }, previousSubject) => {
queryClient.setQueryData(SUBJECT_QUERY_KEY(subjectId), previousSubject);
alert("Could not update subject. Please try again.");
},
});
}

/**
* Mutation composable for creating subject instructor
*/
Expand Down Expand Up @@ -209,3 +236,36 @@ export function useCreateSubjectInstructorMutation(): UseMutationReturnType<
},
});
}

export function useDeleteSubjectInstructorMutation(): UseMutationReturnType<
void,
Error,
{ user: User; subjectId: number },
{ previousUsers: User[] }
> {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ user, subjectId }) => deleteSubjectInstructor(subjectId, user.uid),
onMutate: ({ user, subjectId }) => {
const previousUsers = queryClient.getQueryData<User[]>(
SUBJECT_INSTRUCTORS_QUERY_KEY(subjectId)
);
queryClient.cancelQueries({ queryKey: SUBJECT_INSTRUCTORS_QUERY_KEY(subjectId) });
const newUsers = previousUsers ? previousUsers.filter((u) => u.uid !== user.uid) : [];
queryClient.setQueryData(SUBJECT_INSTRUCTORS_QUERY_KEY(subjectId), newUsers);
return { previousUsers: previousUsers || [] };
},
onSuccess: (_, { subjectId }) => {
queryClient.invalidateQueries({
queryKey: SUBJECT_INSTRUCTORS_QUERY_KEY(subjectId),
});
},
onError: (_, { subjectId }, ctx) => {
queryClient.setQueryData<User[]>(
SUBJECT_INSTRUCTORS_QUERY_KEY(subjectId),
() => ctx!.previousUsers!
);
alert("Could not delete subject instructor. Please try again.");
},
});
}
7 changes: 5 additions & 2 deletions frontend/src/services/subject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type User from "@/models/User";
import type Subject from "@/models/Subject";
import type { UserSubjectList } from "@/models/Subject";
import { authorized_fetch } from "@/services";
import type SubjectForm from "@/models/Subject";
import type { SubjectForm } from "@/models/Subject";

/**
* Fetches the subject with the given ID.
Expand Down Expand Up @@ -51,7 +51,10 @@ export async function registerToSubject(subjectUuid: string): Promise<Subject> {
}

export async function getSubjectUuid(subjectId: number): Promise<string> {
const result = await authorized_fetch(`/api/subjects/${subjectId}/uuid`, { method: "GET" });
const result = await authorized_fetch<{ subject_uuid: string }>(
`/api/subjects/${subjectId}/uuid`,
{ method: "GET" }
);
return result.subject_uuid;
}

Expand Down
80 changes: 37 additions & 43 deletions frontend/src/views/subject/modify/PatchSubjectView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
>
</ModifySubjectHeaderContainer>
<ModifySubjectBody
:current-user="currentUser"
:current-user="currentUser!"
:instructors="shownInstructors"
@add-instructor="addInstructor"
@remove-instructor="removeInstructor"
Expand All @@ -79,8 +79,14 @@

<script setup lang="ts">
import { computed, ref, toRefs } from "vue";
import { useSubjectInstructorsQuery, useSubjectQuery } from "@/queries/Subject";
import type SubjectForm from "@/models/Subject";
import {
useCreateSubjectInstructorMutation,
useDeleteSubjectInstructorMutation,
useSubjectInstructorsQuery,
useSubjectQuery,
useUpdateSubjectMutation,
} from "@/queries/Subject";
import type { SubjectForm } from "@/models/Subject";
import type User from "@/models/User";
import { useCurrentUserQuery } from "@/queries/User";
import { useRouter } from "vue-router";
Expand All @@ -97,12 +103,12 @@ const snackbar = ref(false);
const dialog = ref(false);
const isSubjectNameError = ref(false);
const isSubjectMailError = ref(false);
const subjectName = ref(null);
const subjectMail = ref(null);
const subjectName = ref("");
const subjectMail = ref("");
const activeAcademicYear = ref<number | null>(null);
const currentUserAsInstructor = ref(computed(() => isInstructor.value));
const addedInstructors = ref<Set<User>>(new Set());
const removedInstructorUIDs = ref<Set<string>>(new Set());
const removedInstructors = ref<Set<User>>(new Set());
const subjectNameChanged = ref(false);
const subjectMailChanged = ref(false);
Expand All @@ -122,6 +128,10 @@ const {
isError: isInstructorsError,
} = useSubjectInstructorsQuery(subjectId);
const { mutateAsync: updateSubject } = useUpdateSubjectMutation();
const { mutateAsync: createSubjectInstructor } = useCreateSubjectInstructorMutation();
const { mutateAsync: deleteSubjectInstructor } = useDeleteSubjectInstructorMutation();
const isLoading = computed(
() => isCurrentUserLoading.value || isSubjectLoading.value || isInstructorsLoading.value
);
Expand All @@ -140,23 +150,17 @@ const isCurrentInstructor = (user: User) => {
);
};
const name = computed<string | null>(() =>
subjectNameChanged.value ? subjectName.value : subject.value?.name
);
const academicYear = computed<number | null>(
() => activeAcademicYear.value || subject.value?.academic_year
);
const mail = computed<string | null>(() =>
subjectMailChanged.value ? subjectMail.value : subject.value?.email
);
const name = computed(() => (subjectNameChanged.value ? subjectName.value : subject.value!.name));
const academicYear = computed(() => activeAcademicYear.value || subject.value!.academic_year);
const mail = computed(() => (subjectMailChanged.value ? subjectMail.value : subject.value!.email));
const router = useRouter();
const shownInstructors = computed(() => {
return Array.from(
new Set(
[...(instructors.value || []), ...addedInstructors.value].filter((instructor: User) => {
return !removedInstructorUIDs.value.has(instructor.uid);
return !removedInstructors.value.has(instructor);
})
)
).sort((a, b) => {
Expand All @@ -172,24 +176,23 @@ const shownInstructors = computed(() => {
const addInstructor = (instructor: User) => {
if (isCurrentInstructor(instructor)) {
removedInstructorUIDs.value.delete(instructor.uid);
} else {
addedInstructors.value.add(instructor);
removedInstructors.value.delete(instructor);
}
addedInstructors.value.add(instructor);
};
const removeInstructor = (instructor: User) => {
if (isCurrentInstructor(instructor)) {
removedInstructorUIDs.value.add(instructor.uid);
removedInstructors.value.add(instructor);
}
addedInstructors.value.delete(instructor);
};
const onCurrentUserAsInstructorChanged = (isCurrentUserInstructor: boolean) => {
if (isCurrentUserInstructor) {
removedInstructorUIDs.value.delete(currentUser.value.uid);
removedInstructors.value.delete(currentUser.value!);
} else {
removedInstructorUIDs.value.add(currentUser.value.uid);
removedInstructors.value.add(currentUser.value!);
}
};
Expand Down Expand Up @@ -248,36 +251,27 @@ async function handleSubmit() {
academic_year: academicYear.value,
};
const addedInstructorUIDs = Array.from(addedInstructors.value).map(
(instructor) => instructor.uid
);
console.log(subjectData);
console.log(addedInstructorUIDs);
console.log(removedInstructorUIDs.value);
/*
try {
await updateSubject({
subjectData
});
await updateSubject({ subject: subjectData, subjectId: subjectId.value });
for (const instructor of removedInstructorUIDs) {
await removeSubjectInstructorMutation.mutateAsync(instructor);
for (let instructor of removedInstructors.value) {
await deleteSubjectInstructor({
subjectId: subjectId.value,
user: instructor,
});
}
for (const instructor of addedInstructorUIDs) {
await createSubjectInstructorMutation.mutateAsync(instructor);
for (let instructor of addedInstructors.value) {
await createSubjectInstructor({
subjectId: subjectId.value,
user: instructor,
});
}
await router.push({name: 'subject', params: {subjectId: subjectId.value}});
await router.push({ name: "subject", params: { subjectId: subjectId.value } });
} catch (error) {
console.error("Error during subject alteration:", error);
}
*/
}
</script>

Expand Down

0 comments on commit e87c832

Please sign in to comment.