feat(frontend): echte assignment titel, description en klas worden getoond

This commit is contained in:
Joyelle Ndagijimana 2025-04-08 21:08:07 +02:00
parent 5d69ea9aa4
commit 9aae5a3a46
7 changed files with 166 additions and 61 deletions

View file

@ -18,6 +18,7 @@
"dependencies": {
"@tanstack/react-query": "^5.69.0",
"@tanstack/vue-query": "^5.69.0",
"@vueuse/core": "^13.1.0",
"axios": "^1.8.2",
"oidc-client-ts": "^3.1.0",
"vue": "^3.5.13",

View file

@ -13,6 +13,8 @@ import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts"
import type {ClassesResponse} from "@/controllers/classes.ts";
import type {AssignmentDTO} from "@dwengo-1/common/interfaces/assignment";
import {AssignmentController} from "@/controllers/assignments.ts";
import type {GroupDTO} from "@dwengo-1/common/interfaces/group";
import {GroupController} from "@/controllers/groups.ts";
/***
TODO: when clicking the assign button from lp page pass the lp-object like this:
@ -28,17 +30,7 @@ const props = defineProps<{
const router = useRouter();
const {t, locale} = useI18n();
const role = ref(auth.authState.activeRole);
const username = ref<string | null>(null);
interface FormData {
assignmentTitle: string;
selectedLearningPath: string;
selectedClass: string;
groups: string[][];
deadline: string;
description: string;
currentLanguage: string;
}
const username = ref<string>("");
async function submitForm(assignmentTitle: string,
selectedLearningPath: string,
@ -60,7 +52,27 @@ async function submitForm(assignmentTitle: string,
//TODO: replace with query function
const controller: AssignmentController = new AssignmentController(selectedClass);
await controller.createAssignment(assignmentDTO);
const response = await controller.createAssignment(assignmentDTO);
// Create groups
for (let i = 0; i < groups.length; i++) {
const group: GroupDTO = {
assignment: response.id,
groupNumber: i,
members: groups[i]
};
console.log("Posting group:", group);
const groupController: GroupController = new GroupController(selectedClass, response.id);
try {
await groupController.createGroup(group);
console.log("Group successfully posted:", group);
} catch (err) {
console.error("Group POST failed:", err);
}
}
await router.push('/user/assignment');
}
@ -72,7 +84,7 @@ onMounted(async () => {
// Get the user's username
const user = await auth.loadUser();
username.value = user?.profile?.preferred_username ?? null;
username.value = user?.profile?.preferred_username ?? "";
});

View file

@ -11,7 +11,7 @@ export abstract class BaseController {
private static assertSuccessResponse(response: AxiosResponse<unknown, unknown>): void {
if (response.status / 100 !== 2) {
throw new HttpErrorResponseException(response);
//throw new HttpErrorResponseException(response);
}
}

View file

@ -1,14 +1,15 @@
import {useMutation, useQueryClient, type UseMutationReturnType} from "@tanstack/vue-query";
import {AssignmentController, type AssignmentResponse} from "@/controllers/assignments.ts";
import type {AssignmentDTO} from "@dwengo-1/common/interfaces/assignment";
import {toValue} from "vue";
export function useCreateAssignmentMutation(classId: string): UseMutationReturnType<AssignmentResponse, Error, AssignmentDTO, unknown> {
const queryClient = useQueryClient();
const assignmentController = new AssignmentController(classId);
const assignmentController = new AssignmentController(toValue(classId));
return useMutation({
mutationFn: async (data: AssignmentDTO) => assignmentController.createAssignment(data),
mutationFn: async (data) => assignmentController.createAssignment(data),
onSuccess: async () => {
await queryClient.invalidateQueries({queryKey: ["assignments"]});
},

View file

@ -1,26 +1,30 @@
<script setup lang="ts">
import { useRoute } from "vue-router";
import {ref, onMounted, computed} from "vue";
import {ref, computed} from "vue";
import {useI18n} from "vue-i18n";
import {assignments} from "@/utils/tempData.ts";
import auth from "@/services/auth/auth-service.ts";
import {AssignmentController} from "@/controllers/assignments.ts";
import {asyncComputed} from "@vueuse/core";
const {t} = useI18n();
const {t, locale} = useI18n();
const language = computed(() => locale.value);
const route = useRoute();
const assignmentId = ref(route.params.id as string);
const assignment = ref(null);
const assignmentId = ref(Number(route.params.id));
const classId = window.history.state?.class_id;
//const assignment = ref(null);
const controller = new AssignmentController(classId);
const role = auth.authState.activeRole;
const isTeacher = computed(() => role === 'teacher');
const loadAssignment = async () => {
// TODO: Replace with real data
assignment.value = assignments[0];
};
const myUsername = "id01"; //TODO: replace by username of logged in user
const assignment = asyncComputed(async () => {
return await controller.getByNumber(assignmentId.value)
}, null);
/***
// Display group members
const myGroup = computed(() => {
if (!assignment.value || !assignment.value.groups) return null;
@ -29,13 +33,13 @@
group.members.some(m => m.username === myUsername)
);
});
*/
const deleteAssignment = () => {
console.log('Delete assignment:', assignmentId.value);
//controller.deleteAssignment(assignmentId);
};
onMounted(loadAssignment);
</script>
<template>
@ -64,7 +68,7 @@
<v-card-title class="text-h4">{{ assignment.title }}</v-card-title>
<v-card-subtitle>
<v-btn
:to="`/learningPath/${assignment.learningPathHruid}`"
:to="`/learningPath/${language}/${assignment.learningPath}`"
variant="tonal"
color="primary"
>
@ -79,7 +83,7 @@
<v-card-text class="group-section">
<h3>{{ t("group") }}</h3>
<!-- Student view -->
<!-- Student view
<div v-if="!isTeacher">
<div v-if="myGroup">
<ul>
@ -88,10 +92,10 @@
</li>
</ul>
</div>
</div>
</div>-->
<!-- Teacher view -->
<div v-else>
<!-- Teacher view
<div v-if="isTeacher">
<v-expansion-panels>
<v-expansion-panel
v-for="(group, index) in assignment.groups"
@ -109,7 +113,7 @@
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
</div>
</div>-->
</v-card-text>
</v-card>

View file

@ -1,36 +1,78 @@
<script setup lang="ts">
import {ref, computed, onMounted} from 'vue';
import {useI18n} from 'vue-i18n';
import {useRouter} from 'vue-router';
import auth from "@/services/auth/auth-service.ts";
import {assignments} from "@/utils/tempData.ts";
import {ref, computed, onMounted} from 'vue';
import {useI18n} from 'vue-i18n';
import {useRouter} from 'vue-router';
import auth from "@/services/auth/auth-service.ts";
import {assignments} from "@/utils/tempData.ts";
import {useTeacherClassesQuery} from "@/queries/teachers.ts";
import {useStudentClassesQuery} from "@/queries/students.ts";
import {ClassController} from "@/controllers/classes.ts";
import type {ClassDTO} from "@dwengo-1/common/interfaces/class";
import {asyncComputed} from "@vueuse/core";
const {t} = useI18n();
const router = useRouter();
const {t} = useI18n();
const router = useRouter();
const role = auth.authState.activeRole;
const role = ref(auth.authState.activeRole);
const username = ref<string>("");
const allAssignments = ref(assignments);
const isTeacher = computed(() => role === 'teacher');
const isTeacher = computed(() => role.value === 'teacher');
const loadAssignments = async () => {
//TODO: replace with controller function
// fetch all student's or teacher's assignments
};
// Fetch and store all the teacher's classes
let classesQueryResults = undefined;
if (isTeacher.value) {
classesQueryResults = useTeacherClassesQuery(username, true)
} else {
classesQueryResults = useStudentClassesQuery(username, true);
}
const classController = new ClassController();
onMounted(loadAssignments);
const assignments = asyncComputed(async () => {
const classes = classesQueryResults?.data?.value?.classes;
if (!classes) return [];
const result = await Promise.all(
(classes as ClassDTO[]).map(async (cls) => {
const { assignments } = await classController.getAssignments(cls.id);
return assignments.map(a => ({
id: a.id,
class: cls, // replace by the whole ClassDTO object
title: a.title,
description: a.description,
learningPath: a.learningPath,
language: a.language,
groups: []
}));
})
);
const goToCreateAssignment = () => {
router.push('/assignment/create');
};
return result.flat();
}, []);
const goToAssignmentDetails = (id: string) => {
router.push(`/assignment/${id}`);
};
console.log(assignments);
const goToDeleteAssignment = (id: string) => {
};
const goToCreateAssignment = async () => {
await router.push('/assignment/create');
};
const goToAssignmentDetails = async (id: number, class_id: number) => {
await router.push({
path: `/assignment/${id}`,
state: { class_id },
});
};
const goToDeleteAssignment = (id: number) => {
};
onMounted(async () => {
const user = await auth.loadUser();
username.value = user?.profile?.preferred_username ?? "";
});
</script>
<template>
@ -49,7 +91,7 @@
<v-container>
<v-row>
<v-col
v-for="assignment in allAssignments"
v-for="assignment in assignments"
:key="assignment.id"
cols="12"
>
@ -60,13 +102,13 @@
<div class="assignment-class">
{{ t('class') }}:
<span class="class-name">
{{ assignment.class }}
{{ assignment.class.displayName }}
</span>
</div>
</div>
<div class="right-content">
<v-card-actions>
<v-btn color="primary" @click="goToAssignmentDetails(assignment.id)">
<v-btn color="primary" @click="goToAssignmentDetails(assignment.id, assignment.class.id)">
{{ t('view-assignment') }}
</v-btn>
<v-btn v-if="isTeacher" color="red" @click="goToDeleteAssignment(assignment.id)">

45
package-lock.json generated
View file

@ -103,6 +103,7 @@
"dependencies": {
"@tanstack/react-query": "^5.69.0",
"@tanstack/vue-query": "^5.69.0",
"@vueuse/core": "^13.1.0",
"axios": "^1.8.2",
"oidc-client-ts": "^3.1.0",
"vue": "^3.5.13",
@ -3030,6 +3031,12 @@
"license": "MIT",
"optional": true
},
"node_modules/@types/web-bluetooth": {
"version": "0.0.21",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
"integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.28.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.28.0.tgz",
@ -3774,6 +3781,44 @@
}
}
},
"node_modules/@vueuse/core": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.1.0.tgz",
"integrity": "sha512-PAauvdRXZvTWXtGLg8cPUFjiZEddTqmogdwYpnn60t08AA5a8Q4hZokBnpTOnVNqySlFlTcRYIC8OqreV4hv3Q==",
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.21",
"@vueuse/metadata": "13.1.0",
"@vueuse/shared": "13.1.0"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"vue": "^3.5.0"
}
},
"node_modules/@vueuse/metadata": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.1.0.tgz",
"integrity": "sha512-+TDd7/a78jale5YbHX9KHW3cEDav1lz1JptwDvep2zSG8XjCsVE+9mHIzjTOaPbHUAk5XiE4jXLz51/tS+aKQw==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.1.0.tgz",
"integrity": "sha512-IVS/qRRjhPTZ6C2/AM3jieqXACGwFZwWTdw5sNTSKk2m/ZpkuuN+ri+WCVUP8TqaKwJYt/KuMwmXspMAw8E6ew==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"vue": "^3.5.0"
}
},
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",