diff --git a/frontend/src/assets/assignment.css b/frontend/src/assets/assignment.css index 91ebcef2..851f2c3b 100644 --- a/frontend/src/assets/assignment.css +++ b/frontend/src/assets/assignment.css @@ -7,7 +7,7 @@ } .assignment-card { - width: 85%; + width: 80%; padding: 2%; border-radius: 12px; } diff --git a/frontend/src/components/assignments/AssignmentForm.vue b/frontend/src/components/assignments/AssignmentForm.vue index 4442f020..75fb2060 100644 --- a/frontend/src/components/assignments/AssignmentForm.vue +++ b/frontend/src/components/assignments/AssignmentForm.vue @@ -23,28 +23,12 @@ const {t, locale} = useI18n(); const role = ref(auth.authState.activeRole); const username = ref(""); -async function submitForm(assignmentTitle: string, - selectedLearningPath: string, - selectedClass: string, - groups: string[][], - deadline: string, - description: string, - currentLanguage: string): Promise { - const assignmentDTO: AssignmentDTO = { - id: 0, - class: selectedClass, - title: assignmentTitle, - description: description, - learningPath: selectedLearningPath, - language: currentLanguage, - groups: groups, - //deadline: deadline, - }; - +async function submitForm(assignmentDTO: AssignmentDTO): Promise { //TODO: replace with query function - const controller: AssignmentController = new AssignmentController(selectedClass); + const controller: AssignmentController = new AssignmentController(assignmentDTO.class); await controller.createAssignment(assignmentDTO); + // Navigate back to all assignments await router.push('/user/assignment'); } @@ -79,22 +63,30 @@ const description = ref(''); const groups = ref([]); // New group is added to the list -const addGroupToList = (students: string[]) => { +function addGroupToList(students: string[]): void { if (students.length) { groups.value = [...groups.value, students]; } -}; +} watch(selectedClass, () => { groups.value = []; }); -const submitFormHandler = async () => { +async function submitFormHandler(): Promise { const {valid} = await form.value.validate(); // Don't submit the form if all rules don't apply if (!valid) return; - await submitForm(assignmentTitle.value, selectedLearningPath.value?.hruid, selectedClass.value.id, groups.value, deadline.value, description.value, locale.value); -}; + const assignmentDTO: AssignmentDTO = { + id: 0, + class: selectedClass.value?.id || "", + title: assignmentTitle.value, + description: description.value, + learningPath: selectedLearningPath.value?.hruid || "", + language: language.value + } + await submitForm(assignmentDTO); +} diff --git a/frontend/src/components/assignments/GroupSelector.vue b/frontend/src/components/assignments/GroupSelector.vue index 797e22cc..8750457a 100644 --- a/frontend/src/components/assignments/GroupSelector.vue +++ b/frontend/src/components/assignments/GroupSelector.vue @@ -7,7 +7,7 @@ import type {StudentsResponse} from "@/controllers/students.ts"; const props = defineProps<{ classId: string | undefined - groups: string[][], // All groups + groups: string[][], }>(); const emit = defineEmits(['groupCreated']); const {t} = useI18n(); @@ -16,7 +16,6 @@ const selectedStudents = ref([]); const studentQueryResult = useClassStudentsQuery(() => props.classId, true); - function filterStudents(data: StudentsResponse): { title: string, value: string }[] { const students = data.students; const studentsInGroups = props.groups.flat(); diff --git a/frontend/src/queries/students.ts b/frontend/src/queries/students.ts index 822083d9..5bbd3d4e 100644 --- a/frontend/src/queries/students.ts +++ b/frontend/src/queries/students.ts @@ -1,8 +1,9 @@ -import { computed, toValue } from "vue"; -import type { MaybeRefOrGetter } from "vue"; +import {computed, type Ref, toValue} from "vue"; +import type {MaybeRefOrGetter} from "vue"; import { + type QueryObserverResult, useMutation, - type UseMutationReturnType, + type UseMutationReturnType, useQueries, useQuery, useQueryClient, type UseQueryReturnType, @@ -14,12 +15,12 @@ import { 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/interfaces/student"; +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/interfaces/student"; const studentController = new StudentController(); @@ -27,27 +28,35 @@ const studentController = new StudentController(); function studentsQueryKey(full: boolean): [string, boolean] { return ["students", full]; } + function studentQueryKey(username: string): [string, string] { return ["student", username]; } + function studentClassesQueryKey(username: string, full: boolean): [string, string, boolean] { return ["student-classes", username, full]; } + function studentAssignmentsQueryKey(username: string, full: boolean): [string, string, boolean] { return ["student-assignments", username, full]; } + function studentGroupsQueryKeys(username: string, full: boolean): [string, string, boolean] { return ["student-groups", username, full]; } + function studentSubmissionsQueryKey(username: string): [string, string] { return ["student-submissions", username]; } + function studentQuestionsQueryKey(username: string, full: boolean): [string, string, boolean] { return ["student-questions", username, full]; } + export function studentJoinRequestsQueryKey(username: string): [string, string] { return ["student-join-requests", username]; } + export function studentJoinRequestQueryKey(username: string, classId: string): [string, string, string] { return ["student-join-request", username, classId]; } @@ -69,6 +78,21 @@ export function useStudentQuery( }); } +export function useStudentsByUsernamesQuery( + usernames: MaybeRefOrGetter +): Ref[]> { + const resolvedUsernames = toValue(usernames) ?? []; + + return useQueries({ + queries: resolvedUsernames?.map((username) => ({ + queryKey: computed(() => studentQueryKey(toValue(username))), + queryFn: async () => studentController.getByUsername(toValue(username)), + enabled: Boolean(toValue(username)), + })), + }); +} + + export function useStudentClassesQuery( username: MaybeRefOrGetter, full: MaybeRefOrGetter = true, @@ -150,7 +174,7 @@ export function useCreateStudentMutation(): UseMutationReturnType studentController.createStudent(data), onSuccess: async () => { - await queryClient.invalidateQueries({ queryKey: ["students"] }); + await queryClient.invalidateQueries({queryKey: ["students"]}); }, }); } @@ -161,8 +185,8 @@ export function useDeleteStudentMutation(): UseMutationReturnType studentController.deleteStudent(username), onSuccess: async (deletedUser) => { - await queryClient.invalidateQueries({ queryKey: ["students"] }); - await queryClient.invalidateQueries({ queryKey: studentQueryKey(deletedUser.student.username) }); + await queryClient.invalidateQueries({queryKey: ["students"]}); + await queryClient.invalidateQueries({queryKey: studentQueryKey(deletedUser.student.username)}); }, }); } @@ -176,7 +200,7 @@ export function useCreateJoinRequestMutation(): UseMutationReturnType< const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ username, classId }) => studentController.createJoinRequest(username, classId), + mutationFn: async ({username, classId}) => studentController.createJoinRequest(username, classId), onSuccess: async (newJoinRequest) => { await queryClient.invalidateQueries({ queryKey: studentJoinRequestsQueryKey(newJoinRequest.request.requester), @@ -194,12 +218,12 @@ export function useDeleteJoinRequestMutation(): UseMutationReturnType< const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ username, classId }) => studentController.deleteJoinRequest(username, classId), + mutationFn: async ({username, classId}) => studentController.deleteJoinRequest(username, classId), onSuccess: async (deletedJoinRequest) => { const username = deletedJoinRequest.request.requester; const classId = deletedJoinRequest.request.class; - await queryClient.invalidateQueries({ queryKey: studentJoinRequestsQueryKey(username) }); - await queryClient.invalidateQueries({ queryKey: studentJoinRequestQueryKey(username, classId) }); + await queryClient.invalidateQueries({queryKey: studentJoinRequestsQueryKey(username)}); + await queryClient.invalidateQueries({queryKey: studentJoinRequestQueryKey(username, classId)}); }, }); } diff --git a/frontend/src/views/assignments/SingleAssignment.vue b/frontend/src/views/assignments/SingleAssignment.vue index 1533053c..9f740f56 100644 --- a/frontend/src/views/assignments/SingleAssignment.vue +++ b/frontend/src/views/assignments/SingleAssignment.vue @@ -1,18 +1,48 @@