From c03669eda7cd1eab43be5aafca6ce677387ffe7d Mon Sep 17 00:00:00 2001 From: Adriaan Jacquet Date: Fri, 2 May 2025 13:36:12 +0200 Subject: [PATCH 01/74] feat: teacher's assignments full stack geimplementeerd --- backend/src/controllers/teachers.ts | 11 +++++++++++ backend/src/routes/teachers.ts | 3 +++ backend/src/services/teachers.ts | 14 ++++++++++++++ frontend/src/controllers/teachers.ts | 5 +++++ frontend/src/queries/teachers.ts | 16 ++++++++++++++++ 5 files changed, 49 insertions(+) diff --git a/backend/src/controllers/teachers.ts b/backend/src/controllers/teachers.ts index c8063f80..1ac4888e 100644 --- a/backend/src/controllers/teachers.ts +++ b/backend/src/controllers/teachers.ts @@ -7,6 +7,7 @@ import { getJoinRequestsByClass, getStudentsByTeacher, getTeacher, + getTeacherAssignments, getTeacherQuestions, updateClassJoinRequestStatus, } from '../services/teachers.js'; @@ -60,6 +61,16 @@ export async function getTeacherClassHandler(req: Request, res: Response): Promi res.json({ classes }); } +export async function getTeacherAssignmentsHandler(req: Request, res: Response): Promise { + const username = req.params.username; + const full = req.query.full === 'true'; + requireFields({ username }); + + const assignments = await getTeacherAssignments(username, full); + + res.json({ assignments }); +} + export async function getTeacherStudentHandler(req: Request, res: Response): Promise { const username = req.params.username; const full = req.query.full === 'true'; diff --git a/backend/src/routes/teachers.ts b/backend/src/routes/teachers.ts index 44d3064b..6ff5fd9c 100644 --- a/backend/src/routes/teachers.ts +++ b/backend/src/routes/teachers.ts @@ -4,6 +4,7 @@ import { deleteTeacherHandler, getAllTeachersHandler, getStudentJoinRequestHandler, + getTeacherAssignmentsHandler, getTeacherClassHandler, getTeacherHandler, getTeacherQuestionHandler, @@ -25,6 +26,8 @@ router.delete('/:username', deleteTeacherHandler); router.get('/:username/classes', getTeacherClassHandler); +router.get(`/:username/assignments`, getTeacherAssignmentsHandler); + router.get('/:username/students', getTeacherStudentHandler); router.get('/:username/questions', getTeacherQuestionHandler); diff --git a/backend/src/services/teachers.ts b/backend/src/services/teachers.ts index 4fdb15be..9e617a4d 100644 --- a/backend/src/services/teachers.ts +++ b/backend/src/services/teachers.ts @@ -1,4 +1,5 @@ import { + getAssignmentRepository, getClassJoinRequestRepository, getClassRepository, getLearningObjectRepository, @@ -30,6 +31,8 @@ import { QuestionDTO, QuestionId } from '@dwengo-1/common/interfaces/question'; import { ClassJoinRequestDTO } from '@dwengo-1/common/interfaces/class-join-request'; import { ClassStatus } from '@dwengo-1/common/util/class-join-request'; import { ConflictException } from '../exceptions/conflict-exception.js'; +import { AssignmentDTO, AssignmentDTOId } from '@dwengo-1/common/interfaces/assignment'; +import { mapToAssignmentDTO, mapToAssignmentDTOId } from '../interfaces/assignment.js'; export async function getAllTeachers(full: boolean): Promise { const teacherRepository: TeacherRepository = getTeacherRepository(); @@ -101,6 +104,17 @@ export async function getClassesByTeacher(username: string, full: boolean): Prom return classes.map((cls) => cls.id); } +export async function getTeacherAssignments(username: string, full: boolean): Promise { + const assignmentRepository = getAssignmentRepository(); + const assignments = await assignmentRepository.findAllByResponsibleTeacher(username); + + if (full) { + return assignments.map(mapToAssignmentDTO); + } + + return assignments.map(mapToAssignmentDTOId); +} + export async function getStudentsByTeacher(username: string, full: boolean): Promise { const classes: ClassDTO[] = await fetchClassesByTeacher(username); diff --git a/frontend/src/controllers/teachers.ts b/frontend/src/controllers/teachers.ts index a97cf11f..76fe0162 100644 --- a/frontend/src/controllers/teachers.ts +++ b/frontend/src/controllers/teachers.ts @@ -3,6 +3,7 @@ import type { JoinRequestResponse, JoinRequestsResponse, StudentsResponse } from import type { QuestionsResponse } from "@/controllers/questions.ts"; import type { ClassesResponse } from "@/controllers/classes.ts"; import type { TeacherDTO } from "@dwengo-1/common/interfaces/teacher"; +import type { AssignmentsResponse } from "./assignments"; export interface TeachersResponse { teachers: TeacherDTO[] | string[]; @@ -36,6 +37,10 @@ export class TeacherController extends BaseController { return this.get(`/${username}/classes`, { full }); } + async getAssignments(username: string, full = true): Promise { + return this.get(`/${username}/assignments`, { full }); + } + async getStudents(username: string, full = false): Promise { return this.get(`/${username}/students`, { full }); } diff --git a/frontend/src/queries/teachers.ts b/frontend/src/queries/teachers.ts index 59da84f4..ab799118 100644 --- a/frontend/src/queries/teachers.ts +++ b/frontend/src/queries/teachers.ts @@ -13,6 +13,7 @@ import type { JoinRequestResponse, JoinRequestsResponse, StudentsResponse } from import type { QuestionsResponse } from "@/controllers/questions.ts"; import type { TeacherDTO } from "@dwengo-1/common/interfaces/teacher"; import { studentJoinRequestQueryKey, studentJoinRequestsQueryKey } from "@/queries/students.ts"; +import type { AssignmentResponse, AssignmentsResponse } from "@/controllers/assignments"; const teacherController = new TeacherController(); @@ -29,6 +30,10 @@ function teacherClassesQueryKey(username: string, full: boolean): [string, strin return ["teacher-classes", username, full]; } +function teacherAssignmentsQueryKey(username: string, full: boolean): [string, string, boolean] { + return ["teacher-assignments", username, full]; +} + function teacherStudentsQueryKey(username: string, full: boolean): [string, string, boolean] { return ["teacher-students", username, full]; } @@ -69,6 +74,17 @@ export function useTeacherClassesQuery( }); } +export function useTeacherAssignmentsQuery( + username: MaybeRefOrGetter, + full: MaybeRefOrGetter = false, +): UseQueryReturnType { + return useQuery({ + queryKey: computed(() => teacherAssignmentsQueryKey(toValue(username)!, toValue(full))), + queryFn: async () => teacherController.getAssignments(toValue(username)!, toValue(full)), + enabled: () => Boolean(toValue(username)), + }); +} + export function useTeacherStudentsQuery( username: MaybeRefOrGetter, full: MaybeRefOrGetter = false, From 7e4e179121f1fe6d8c2a135e303c8dbc4a1246ac Mon Sep 17 00:00:00 2001 From: Adriaan Jacquet Date: Fri, 2 May 2025 14:01:00 +0200 Subject: [PATCH 02/74] feat: nieuwe lijstview voor assignment --- .../src/views/assignments/UserAssignments.vue | 334 ++++++++++-------- 1 file changed, 178 insertions(+), 156 deletions(-) diff --git a/frontend/src/views/assignments/UserAssignments.vue b/frontend/src/views/assignments/UserAssignments.vue index 7a144e25..07f02106 100644 --- a/frontend/src/views/assignments/UserAssignments.vue +++ b/frontend/src/views/assignments/UserAssignments.vue @@ -1,188 +1,210 @@ From 509db70c73a50bebb07ebfa7c3fd18a66fc95e29 Mon Sep 17 00:00:00 2001 From: Adriaan Jacquet Date: Fri, 2 May 2025 20:23:14 +0200 Subject: [PATCH 03/74] feat: bezig met ui/ux assignment, bug in testdata --- backend/src/controllers/assignments.ts | 16 +- frontend/src/components/DwengoTable.vue | 49 ++++ .../components/assignments/AssignmentCard.vue | 0 frontend/src/controllers/assignments.ts | 2 +- frontend/src/queries/assignments.ts | 2 +- .../src/views/assignments/UserAssignments.vue | 237 ++++++++++++------ 6 files changed, 227 insertions(+), 79 deletions(-) create mode 100644 frontend/src/components/DwengoTable.vue create mode 100644 frontend/src/components/assignments/AssignmentCard.vue diff --git a/backend/src/controllers/assignments.ts b/backend/src/controllers/assignments.ts index 2ca6d2fc..bd2c7244 100644 --- a/backend/src/controllers/assignments.ts +++ b/backend/src/controllers/assignments.ts @@ -13,6 +13,7 @@ import { requireFields } from './error-helper.js'; import { BadRequestException } from '../exceptions/bad-request-exception.js'; import { Assignment } from '../entities/assignments/assignment.entity.js'; import { EntityDTO } from '@mikro-orm/core'; +import { FALLBACK_LANG } from '../config.js'; function getAssignmentParams(req: Request): { classid: string; assignmentNumber: number; full: boolean } { const classid = req.params.classid; @@ -38,14 +39,19 @@ export async function getAllAssignmentsHandler(req: Request, res: Response): Pro export async function createAssignmentHandler(req: Request, res: Response): Promise { const classid = req.params.classid; - const description = req.body.description; - const language = req.body.language; - const learningPath = req.body.learningPath; + const description = req.body.description || ""; + const language = req.body.language || FALLBACK_LANG; + const learningPath = req.body.learningPath || ""; const title = req.body.title; - requireFields({ description, language, learningPath, title }); + requireFields({ title }); - const assignmentData = req.body as AssignmentDTO; + const assignmentData = { + description: description, + language: language, + learningPath: learningPath, + title: title, + } as AssignmentDTO; const assignment = await createAssignment(classid, assignmentData); res.json({ assignment }); diff --git a/frontend/src/components/DwengoTable.vue b/frontend/src/components/DwengoTable.vue new file mode 100644 index 00000000..01490751 --- /dev/null +++ b/frontend/src/components/DwengoTable.vue @@ -0,0 +1,49 @@ + + + \ No newline at end of file diff --git a/frontend/src/components/assignments/AssignmentCard.vue b/frontend/src/components/assignments/AssignmentCard.vue new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/controllers/assignments.ts b/frontend/src/controllers/assignments.ts index 0d46e311..79da6965 100644 --- a/frontend/src/controllers/assignments.ts +++ b/frontend/src/controllers/assignments.ts @@ -25,7 +25,7 @@ export class AssignmentController extends BaseController { return this.get(`/${num}`); } - async createAssignment(data: AssignmentDTO): Promise { + async createAssignment(data: Partial): Promise { return this.post(`/`, data); } diff --git a/frontend/src/queries/assignments.ts b/frontend/src/queries/assignments.ts index 2bb0a929..eb007bab 100644 --- a/frontend/src/queries/assignments.ts +++ b/frontend/src/queries/assignments.ts @@ -117,7 +117,7 @@ export function useAssignmentQuery( export function useCreateAssignmentMutation(): UseMutationReturnType< AssignmentResponse, Error, - { cid: string; data: AssignmentDTO }, + { cid: string; data: Partial }, unknown > { const queryClient = useQueryClient(); diff --git a/frontend/src/views/assignments/UserAssignments.vue b/frontend/src/views/assignments/UserAssignments.vue index 07f02106..e8bdf6df 100644 --- a/frontend/src/views/assignments/UserAssignments.vue +++ b/frontend/src/views/assignments/UserAssignments.vue @@ -6,10 +6,10 @@ import authState from "@/services/auth/auth-service.ts"; import auth from "@/services/auth/auth-service.ts"; import { useTeacherAssignmentsQuery, useTeacherClassesQuery } from "@/queries/teachers.ts"; import { useStudentAssignmentsQuery, useStudentClassesQuery } from "@/queries/students.ts"; -import { ClassController } from "@/controllers/classes.ts"; +import { ClassController, type ClassesResponse } from "@/controllers/classes.ts"; import type { ClassDTO } from "@dwengo-1/common/interfaces/class"; import { asyncComputed } from "@vueuse/core"; -import { useDeleteAssignmentMutation } from "@/queries/assignments.ts"; +import { useCreateAssignmentMutation, useDeleteAssignmentMutation } from "@/queries/assignments.ts"; import type { AssignmentsResponse } from "@/controllers/assignments"; import type { AssignmentDTO } from "@dwengo-1/common/interfaces/assignment"; import UsingQueryResult from "@/components/UsingQueryResult.vue"; @@ -38,8 +38,14 @@ onMounted(async () => { }); const isTeacher = computed(() => role.value === "teacher"); - const assignmentsQuery = isTeacher ? useTeacherAssignmentsQuery(username, true) : useStudentAssignmentsQuery(username, true); +const { mutate: assignmentMutation, isSuccess: assignmentIsSuccess } = useCreateAssignmentMutation(); + +const classesQuery = isTeacher ? useTeacherClassesQuery(username, true) : useStudentClassesQuery(username, true); +const selectedClass = ref(undefined); +const isClassSelected = ref(false); + +const assignmentTitle = ref(""); async function goToCreateAssignment(): Promise { await router.push("/assignment/create"); @@ -65,6 +71,27 @@ onMounted(async () => { const user = await auth.loadUser(); username.value = user?.profile?.preferred_username ?? ""; }); + +async function createAssignment(): Promise { + const cid = selectedClass.value!.id; + const assignmentData: Partial = { + within: cid, + title: assignmentTitle.value!, + }; + + assignmentMutation({ cid: cid, data: assignmentData}, { + onSuccess: async (classResponse) => { + // showSnackbar(t("classCreated"), "success"); + // const createdClass: ClassDTO = classResponse.class; + // code.value = createdClass.id; + await assignmentsQuery.refetch(); + }, + onError: (err) => { + console.log(err); + // showSnackbar(t("creationFailed") + ": " + err.message, "error"); + }, + }); +} @@ -207,4 +236,68 @@ onMounted(async () => { font-weight: 500; color: #333; } + +.header { + font-weight: bold !important; + background-color: #0e6942; + color: white; + padding: 10px; +} + +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; +} + +td, +th { + border-bottom: 1px solid #0e6942; + border-top: 1px solid #0e6942; +} + +.table { + width: 90%; + padding-top: 10px; + border-collapse: collapse; +} + +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; +} From d8a7a86da05f893b6021b4c00bdf5d3ded4dc51c Mon Sep 17 00:00:00 2001 From: Adriaan Jacquet Date: Fri, 2 May 2025 21:12:34 +0200 Subject: [PATCH 04/74] fix: bug in populate groups van assignment --- backend/src/data/assignments/assignment-repository.ts | 3 ++- backend/src/services/assignments.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/src/data/assignments/assignment-repository.ts b/backend/src/data/assignments/assignment-repository.ts index 1c8bb504..9d04d6e2 100644 --- a/backend/src/data/assignments/assignment-repository.ts +++ b/backend/src/data/assignments/assignment-repository.ts @@ -7,7 +7,7 @@ export class AssignmentRepository extends DwengoEntityRepository { return this.findOne({ within: within, id: id }, { populate: ['groups', 'groups.members'] }); } public async findByClassIdAndAssignmentId(withinClass: string, id: number): Promise { - return this.findOne({ within: { classId: withinClass }, id: id }); + return this.findOne({ within: { classId: withinClass }, id: id }, { populate: ['groups', 'groups.members'] }); } public async findAllByResponsibleTeacher(teacherUsername: string): Promise { return this.findAll({ @@ -20,6 +20,7 @@ export class AssignmentRepository extends DwengoEntityRepository { }, }, }, + populate: ['groups', 'groups.members'] }); } public async findAllAssignmentsInClass(within: Class): Promise { diff --git a/backend/src/services/assignments.ts b/backend/src/services/assignments.ts index 2379ecfb..728904d3 100644 --- a/backend/src/services/assignments.ts +++ b/backend/src/services/assignments.ts @@ -43,6 +43,8 @@ export async function getAllAssignments(classid: string, full: boolean): Promise const assignmentRepository = getAssignmentRepository(); const assignments = await assignmentRepository.findAllAssignmentsInClass(cls); + console.log(assignments); + if (full) { return assignments.map(mapToAssignmentDTO); } From 6c28c0fc3d7cae0a1dca723b5ce425e71cbaaddd Mon Sep 17 00:00:00 2001 From: Adriaan Jacquet Date: Sat, 3 May 2025 11:44:43 +0200 Subject: [PATCH 05/74] feat: werkende aan group edit pagina --- .../views/assignments/TeacherAssignment.vue | 391 ++++++++++++------ 1 file changed, 271 insertions(+), 120 deletions(-) diff --git a/frontend/src/views/assignments/TeacherAssignment.vue b/frontend/src/views/assignments/TeacherAssignment.vue index e626a8be..caec311c 100644 --- a/frontend/src/views/assignments/TeacherAssignment.vue +++ b/frontend/src/views/assignments/TeacherAssignment.vue @@ -8,6 +8,8 @@ import type { Language } from "@/data-objects/language.ts"; import type { AssignmentResponse } from "@/controllers/assignments.ts"; import type { GroupDTO } from "@dwengo-1/common/interfaces/group"; +import type { AssignmentDTO } from "@dwengo-1/common/interfaces/assignment"; +import type { StudentDTO } from "@dwengo-1/common/interfaces/student"; const props = defineProps<{ classId: string; @@ -24,7 +26,7 @@ const groups = ref(); const learningPath = ref(); - const assignmentQueryResult = useAssignmentQuery(() => props.classId, props.assignmentId); + const assignmentQueryResult = useAssignmentQuery(props.classId, props.assignmentId); learningPath.value = assignmentQueryResult.data.value?.assignment?.learningPath; // Get learning path object const lpQueryResult = useGetLearningPathQuery( @@ -88,138 +90,185 @@ Const {groupProgressMap} = props.useGroupsWithProgress(
- -
- + + + - mdi-arrow-left - +
+ + mdi-arrow-left + - - mdi-delete - -
- {{ data.assignment.title }} - - - - {{ t("learning-path") }} - - - - - - {{ data.assignment.description }} - - - -

{{ t("groups") }}

-
- - + + - - - - -
-
- - - - {{ t("members") }} - - - - - {{ member.firstName + " " + member.lastName }} - - - - + + {{ assignmentResponse.data.assignment.description }} - + + +

{{ t("groups") }}

+
+ + + + + + + +
+
+ + + + {{ t("members") }} + + + + + {{ member.firstName + " " + member.lastName }} + + + + + + + Close + + + +
-
- - + + + + + + {{ t("group") }} + + {{ t("progress") }} + + {{ t("Members") }} + + + mdi-pencil + + + + + + + + + {{ g.groupNumber }} + mdi-menu-right + + + + + + + + {{ (g.members! as StudentDTO[]).map(member => member.username).join(', ') }} + + + mdi-delete + + + + + + + +
@@ -231,4 +280,106 @@ Const {groupProgressMap} = props.useGroupsWithProgress( overflow-x: auto; -webkit-overflow-scrolling: touch; } + + .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: 850px) { + 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; + } + + .custom-breakpoint { + flex-direction: column !important; + } + + .table { + width: 100%; + } + + .responsive-col { + max-width: 100% !important; + flex-basis: 100% !important; + } + } From 20173169b749f9cfd577a4bb7af771f21c6a469f Mon Sep 17 00:00:00 2001 From: laurejablonski Date: Sun, 4 May 2025 10:25:02 +0200 Subject: [PATCH 06/74] feat: edit assignments --- frontend/src/assets/assignment.css | 18 +- .../views/assignments/TeacherAssignment.vue | 483 ++++++++++++------ 2 files changed, 331 insertions(+), 170 deletions(-) diff --git a/frontend/src/assets/assignment.css b/frontend/src/assets/assignment.css index 029dec22..35e50792 100644 --- a/frontend/src/assets/assignment.css +++ b/frontend/src/assets/assignment.css @@ -18,12 +18,22 @@ font-size: 1.1rem; } -.top-right-btn { - position: absolute; - right: 2%; - color: red; +.top-buttons-wrapper { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem; + position: relative; } +.right-buttons { + display: flex; + gap: 0.5rem; + align-items: center; + color: #0e6942 +} + + .group-section { margin-top: 2rem; } diff --git a/frontend/src/views/assignments/TeacherAssignment.vue b/frontend/src/views/assignments/TeacherAssignment.vue index caec311c..04fea1a6 100644 --- a/frontend/src/views/assignments/TeacherAssignment.vue +++ b/frontend/src/views/assignments/TeacherAssignment.vue @@ -4,12 +4,12 @@ import { useAssignmentQuery, useDeleteAssignmentMutation } from "@/queries/assignments.ts"; import UsingQueryResult from "@/components/UsingQueryResult.vue"; import { useGroupsQuery } from "@/queries/groups.ts"; - import { useGetLearningPathQuery } from "@/queries/learning-paths.ts"; + import { useGetAllLearningPaths, useGetLearningPathQuery } from "@/queries/learning-paths.ts"; import type { Language } from "@/data-objects/language.ts"; import type { AssignmentResponse } from "@/controllers/assignments.ts"; import type { GroupDTO } from "@dwengo-1/common/interfaces/group"; -import type { AssignmentDTO } from "@dwengo-1/common/interfaces/assignment"; -import type { StudentDTO } from "@dwengo-1/common/interfaces/student"; + import type { StudentDTO } from "@dwengo-1/common/interfaces/student"; + import type { LearningPath } from "@/data-objects/learning-paths/learning-path"; const props = defineProps<{ classId: string; @@ -21,19 +21,43 @@ import type { StudentDTO } from "@dwengo-1/common/interfaces/student"; ) => { groupProgressMap: Map }; }>(); + const isEditing = ref(false); + const { t, locale } = useI18n(); const language = computed(() => locale.value); const groups = ref(); const learningPath = ref(); + const editingLearningPath = ref(learningPath); + const description = ref(""); const assignmentQueryResult = useAssignmentQuery(props.classId, props.assignmentId); learningPath.value = assignmentQueryResult.data.value?.assignment?.learningPath; + const learningPathsQueryResults = useGetAllLearningPaths(language); + // Get learning path object const lpQueryResult = useGetLearningPathQuery( computed(() => assignmentQueryResult.data.value?.assignment?.learningPath ?? ""), computed(() => language.value as Language), ); + const learningPathRules = [ + (value: { hruid: string; title: string }): string | boolean => { + if (value && value.hruid) { + return true; // Valid if hruid is present + } + return "You must select a learning path."; + }, + ]; + + const descriptionRules = [ + (value: string): string | boolean => { + if (!value || value.trim() === "") { + return "Description cannot be empty."; + } + return true; + }, + ]; + // Get all the groups withing the assignment const groupsQueryResult = useGroupsQuery(props.classId, props.assignmentId, true); groups.value = groupsQueryResult.data.value?.groups; @@ -84,6 +108,13 @@ Const {groupProgressMap} = props.useGroupsWithProgress( }, ); } + + function saveChanges() { + //TODO + const new_learningpath = editingLearningPath.value; + const new_description = description.value; + isEditing.value = false; + } From 195e19259880b1f0e25c1d2069594042a7ff86c9 Mon Sep 17 00:00:00 2001 From: Joyelle Ndagijimana Date: Sun, 4 May 2025 13:26:19 +0200 Subject: [PATCH 07/74] feat: leerkracht kan progress van groepen zien --- frontend/src/components/GroupProgressRow.vue | 45 ++++++++++++ .../views/assignments/SingleAssignment.vue | 35 +++++----- .../views/assignments/StudentAssignment.vue | 8 +-- .../views/assignments/TeacherAssignment.vue | 70 ++++++++----------- 4 files changed, 96 insertions(+), 62 deletions(-) create mode 100644 frontend/src/components/GroupProgressRow.vue diff --git a/frontend/src/components/GroupProgressRow.vue b/frontend/src/components/GroupProgressRow.vue new file mode 100644 index 00000000..022e07c5 --- /dev/null +++ b/frontend/src/components/GroupProgressRow.vue @@ -0,0 +1,45 @@ + + + diff --git a/frontend/src/views/assignments/SingleAssignment.vue b/frontend/src/views/assignments/SingleAssignment.vue index 3d9f7f0a..cf7b48e6 100644 --- a/frontend/src/views/assignments/SingleAssignment.vue +++ b/frontend/src/views/assignments/SingleAssignment.vue @@ -19,35 +19,33 @@ function useGroupsWithProgress( groups: Ref, hruid: Ref, - language: Ref, - ): { groupProgressMap: Map } { - const groupProgressMap: Map = new Map(); + language: Ref, + ): { groupProgressMap: Map; } { + const groupProgressMap = ref(new Map()); watchEffect(() => { // Clear existing entries to avoid stale data - groupProgressMap.clear(); + groupProgressMap.value.clear(); - const lang = ref(language.value as Language); - - groups.value.forEach((group) => { + groups?.value.forEach((group) => { const groupKey = group.groupNumber; - const forGroup = ref({ - forGroup: groupKey, - assignmentNo: assignmentId, - classId: classId, - }); - - const query = useGetLearningPathQuery(hruid.value, lang, forGroup); + const query = useGetLearningPathQuery( + hruid, + language, + () => ({ + forGroup: groupKey, + assignmentNo: assignmentId.value, + classId: classId.value, + }) + ); const data = query.data.value; - groupProgressMap.set(groupKey, data ? calculateProgress(data) : 0); + groupProgressMap.value.set(groupKey, data ? calculateProgress(data) : 0); }); }); - return { - groupProgressMap, - }; + return { groupProgressMap: groupProgressMap.value }; } function calculateProgress(lp: LearningPath): number { @@ -59,7 +57,6 @@ diff --git a/frontend/src/views/assignments/StudentAssignment.vue b/frontend/src/views/assignments/StudentAssignment.vue index fb81a265..fdb33a82 100644 --- a/frontend/src/views/assignments/StudentAssignment.vue +++ b/frontend/src/views/assignments/StudentAssignment.vue @@ -22,8 +22,8 @@ ) => { groupProgressMap: Map }; }>(); - const { t, locale } = useI18n(); - const language = ref(locale.value as Language); + const { t } = useI18n(); + const lang = ref(); const learningPath = ref(); // Get the user's username/id const username = asyncComputed(async () => { @@ -38,7 +38,7 @@ const lpQueryResult = useGetLearningPathQuery( computed(() => assignmentQueryResult.data.value?.assignment?.learningPath ?? ""), - computed(() => language.value), + computed(() => assignmentQueryResult.data.value?.assignment?.language as Language), ); const groupsQueryResult = useGroupsQuery(props.classId, props.assignmentId, true); @@ -100,7 +100,7 @@ language > diff --git a/frontend/src/views/assignments/TeacherAssignment.vue b/frontend/src/views/assignments/TeacherAssignment.vue index e626a8be..9ea54cf4 100644 --- a/frontend/src/views/assignments/TeacherAssignment.vue +++ b/frontend/src/views/assignments/TeacherAssignment.vue @@ -1,5 +1,5 @@