feat(frontend): controllers integreren in assignments

This commit is contained in:
Joyelle Ndagijimana 2025-04-07 21:18:09 +02:00
parent baea0051e6
commit 23947ecd92
11 changed files with 100 additions and 65 deletions

View file

@ -16,6 +16,7 @@
"test:unit": "vitest --run" "test:unit": "vitest --run"
}, },
"dependencies": { "dependencies": {
"@dwengo-1/common": "^0.1.1",
"@mikro-orm/core": "6.4.9", "@mikro-orm/core": "6.4.9",
"@mikro-orm/knex": "6.4.9", "@mikro-orm/knex": "6.4.9",
"@mikro-orm/postgresql": "6.4.9", "@mikro-orm/postgresql": "6.4.9",

View file

@ -51,5 +51,17 @@
"noLearningPathsFoundDescription": "Es gibt keine Lernpfade, die zu Ihrem Suchbegriff passen.", "noLearningPathsFoundDescription": "Es gibt keine Lernpfade, die zu Ihrem Suchbegriff passen.",
"legendNotCompletedYet": "Noch nicht fertig", "legendNotCompletedYet": "Noch nicht fertig",
"legendCompleted": "Fertig", "legendCompleted": "Fertig",
"legendTeacherExclusive": "Information für Lehrkräfte" "legendTeacherExclusive": "Information für Lehrkräfte",
"new-assignment": "Neue Aufgabe",
"edit-assignment": "Zuordnung bearbeiten",
"groups": "Gruppen",
"learning-path": "Lernpfad",
"choose-lp": "Einen lernpfad auswählen",
"choose-classes": "Klassen wählen",
"create-groups": "Gruppen erstellen",
"title": "Titel",
"pick-class": "Wählen Sie eine klasse",
"choose-students": "Studenten auswählen",
"create-group": "Gruppe erstellen",
"class": "klasse"
} }

View file

@ -54,8 +54,6 @@
"read-more": "Read more", "read-more": "Read more",
"new-assignment": "New Assignment", "new-assignment": "New Assignment",
"edit-assignment": "Edit Assignment", "edit-assignment": "Edit Assignment",
"next": "next",
"previous": "previous",
"groups": "Groups", "groups": "Groups",
"learning-path": "Learning path", "learning-path": "Learning path",
"choose-lp": "Select a learning path", "choose-lp": "Select a learning path",

View file

@ -54,8 +54,6 @@
"read-more": "En savoir plus", "read-more": "En savoir plus",
"new-assignment": "Nouveau travail", "new-assignment": "Nouveau travail",
"edit-assignment": "Modifier le travail", "edit-assignment": "Modifier le travail",
"next": "suivant",
"previous": "précédent",
"groups": "Groupes", "groups": "Groupes",
"learning-path": "Parcours d'apprentissage", "learning-path": "Parcours d'apprentissage",
"choose-lp": "Choisissez un parcours d'apprentissage", "choose-lp": "Choisissez un parcours d'apprentissage",

View file

@ -54,8 +54,6 @@
"read-more": "Lees meer", "read-more": "Lees meer",
"new-assignment": "Nieuwe opdracht", "new-assignment": "Nieuwe opdracht",
"edit-assignment": "Opdracht bewerken", "edit-assignment": "Opdracht bewerken",
"next": "volgende",
"previous": "vorige",
"groups": "Groepen", "groups": "Groepen",
"learning-path": "Leerpad", "learning-path": "Leerpad",
"choose-lp": "Kies een leerpad", "choose-lp": "Kies een leerpad",

View file

@ -9,7 +9,7 @@ import CreateDiscussion from "@/views/discussions/CreateDiscussion.vue";
import CallbackPage from "@/views/CallbackPage.vue"; import CallbackPage from "@/views/CallbackPage.vue";
import UserDiscussions from "@/views/discussions/UserDiscussions.vue"; import UserDiscussions from "@/views/discussions/UserDiscussions.vue";
import UserClasses from "@/views/classes/UserClasses.vue"; import UserClasses from "@/views/classes/UserClasses.vue";
import UserAssignments from "@/views/classes/UserAssignments.vue"; import UserAssignments from "@/views/assignments/UserAssignments.vue";
import authState from "@/services/auth/auth-service.ts"; import authState from "@/services/auth/auth-service.ts";
import LearningPathPage from "@/views/learning-paths/LearningPathPage.vue"; import LearningPathPage from "@/views/learning-paths/LearningPathPage.vue";
import LearningPathSearchPage from "@/views/learning-paths/LearningPathSearchPage.vue"; import LearningPathSearchPage from "@/views/learning-paths/LearningPathSearchPage.vue";
@ -79,10 +79,20 @@ const router = createRouter({
meta: { requiresAuth: true }, meta: { requiresAuth: true },
}, },
{ {
path: "/assignment/:id", path: "/assignment",
name: "SingleAssigment", meta: {requiresAuth: true},
component: SingleAssignment, children: [
meta: { requiresAuth: true }, {
path: "create",
name: "CreateAssigment",
component: CreateAssignment,
},
{
path: ":id",
name: "SingleAssigment",
component: SingleAssignment,
},
]
}, },
{ {
path: "/class/create", path: "/class/create",

View file

@ -1,42 +1,46 @@
/** /**
* Submits the form data to the backend. * Submits the form data to the backend.
* *
* @param assignmentTitle - The title of the assignment. * @param assignmentTitle - The title of the assignment.
* @param selectedLearningPath - The selected learning path, containing hruid and title. * @param selectedLearningPath - The selected learning path, containing hruid and title.
* @param selectedClasses - The selected classes, an array of class objects. * @param selectedClass - The selected classes, an array of class objects.
* @param groups - An array of groups, each containing student IDs. * @param groups - An array of groups, each containing student IDs.
* @param deadline - The deadline of the assignment in ISO format. * @param deadline - The deadline of the assignment in ISO format.
* @param description - The description of the aasignment * @param description - The description of the assignment
* Sends a POST request to the backend with the form data. * Sends a POST request to the backend with the form data.
*/ */
import {AssignmentController} from "@/controllers/assignments.ts";
import type {AssignmentDTO} from "@dwengo-1/common/interfaces/assignment";
export const submitForm = async ( export const submitForm = async (
assignmentTitle: string, assignmentTitle: string,
selectedLearningPath: any, selectedLearningPath: any,
selectedClasses: any[], selectedClass: string,
groups: string[][], groups: string[][],
deadline: string, deadline: string,
description: string description: string,
currentLanguage: string
) => { ) => {
const formData = { const formData: AssignmentDTO = {
id: 0,
class: selectedClass,
title: assignmentTitle, title: assignmentTitle,
hruid: selectedLearningPath?.hruid, description: description,
classes: selectedClasses.map(cl => cl.value), learningPath: selectedLearningPath,
groups: groups, language: currentLanguage,
deadline: deadline, groups: [],
description: description //deadline: deadline,
}; };
try { console.log(formData);
const response = await fetch(/*"http://localhost:3000/api/assignment"*/"", {
method: "POST", const controller: AssignmentController = new AssignmentController(selectedClass);
headers: { "Content-Type": "application/json" },
body: JSON.stringify(formData) const response = await controller.createAssignment(formData);
}); console.log(response);
const data = await response.json();
console.log("Form submitted successfully:", data);
} catch (error) {
console.error("Error submitting form:", error);
}
}; };
/** /**
@ -70,9 +74,9 @@ export const learningPathRules = [
* *
* Ensures that at least one class is selected. * Ensures that at least one class is selected.
*/ */
export const classesRules = [ export const classRules = [
(value: any[]) => { (value: string) => {
if (value?.length >= 1) return true; if (value) return true;
return 'You must select at least one class.'; return 'You must select at least one class.';
}, },
]; ];

View file

@ -29,7 +29,7 @@ const teacher02: Student = {username: "id12", firstName: "John", lastName: "Hiat
const teacher03: Student = {username: "id13", firstName: "Aaron", lastName: "Lewis", classes: []}; const teacher03: Student = {username: "id13", firstName: "Aaron", lastName: "Lewis", classes: []};
const class01: Class = { const class01: Class = {
id: "class01", id: "34d484a1-295f-4e9f-bfdc-3e7a23d86a89",
displayName: "class 01", displayName: "class 01",
teachers: [teacher01], teachers: [teacher01],
students: [student01, student02], students: [student01, student02],

View file

@ -5,7 +5,7 @@
import {classes} from "@/utils/tempData.ts"; import {classes} from "@/utils/tempData.ts";
import { import {
assignmentTitleRules, assignmentTitleRules,
classesRules, classRules,
descriptionRules, descriptionRules,
learningPathRules, learningPathRules,
submitForm submitForm
@ -97,7 +97,7 @@
const { valid } = await form.value.validate(); const { valid } = await form.value.validate();
// Don't submit thr form if all rules don't apply // Don't submit thr form if all rules don't apply
if (!valid) return; if (!valid) return;
submitForm(assignmentTitle.value, selectedLearningPath.value, selectedClass.value, groups.value, deadline.value, description.value); submitForm(assignmentTitle.value, selectedLearningPath.value?.hruid, selectedClass.value.value, groups.value, deadline.value, description.value, locale.value);
}; };
</script> </script>
@ -109,7 +109,7 @@
<v-form ref="form" class="form-container" validate-on="submit lazy" @submit.prevent="submitFormHandler"> <v-form ref="form" class="form-container" validate-on="submit lazy" @submit.prevent="submitFormHandler">
<v-container class="step-container"> <v-container class="step-container">
<v-card-text> <v-card-text>
<v-text-field :v-model="assignmentTitle" :label="t('title')" :rules="assignmentTitleRules" <v-text-field v-model="assignmentTitle" :label="t('title')" :rules="assignmentTitleRules"
density="compact" variant="outlined" clearable required></v-text-field> density="compact" variant="outlined" clearable required></v-text-field>
</v-card-text> </v-card-text>
@ -136,7 +136,7 @@
v-model="selectedClass" v-model="selectedClass"
:items="allClasses" :items="allClasses"
:label="t('pick-class')" :label="t('pick-class')"
:rules="classesRules" :rules="classRules"
variant="outlined" variant="outlined"
clearable clearable
hide-details hide-details

View file

@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue'; import {ref, computed, onMounted} from 'vue';
import { useI18n } from 'vue-i18n'; import {useI18n} from 'vue-i18n';
import { useRouter } from 'vue-router'; import {useRouter} from 'vue-router';
import auth from "@/services/auth/auth-service.ts"; import auth from "@/services/auth/auth-service.ts";
import {assignments} from "@/utils/tempData.ts"; import {assignments} from "@/utils/tempData.ts";
const { t } = useI18n(); const {t} = useI18n();
const router = useRouter(); const router = useRouter();
const role = auth.authState.activeRole; const role = auth.authState.activeRole;
@ -19,17 +19,12 @@
}; };
onMounted(loadAssignments); onMounted(loadAssignments);
const goToCreateAssignment = () => { const goToCreateAssignment = () => {
router.push('/assignment/create'); router.push('/assignment/create');
}; };
const goToEditAssignment = (id: string) => {
router.push(`/assignment/${id}/edit`);
};
const goToAssignmentDetails = (id: string) => { const goToAssignmentDetails = (id: string) => {
router.push(`/assignment/${id}`); router.push(`/assignment/${id}`);
}; };
@ -45,7 +40,7 @@
<v-btn <v-btn
v-if="isTeacher" v-if="isTeacher"
color="primary" color="primary"
class="mb-4" class="mb-4 center-btn"
@click="goToCreateAssignment" @click="goToCreateAssignment"
> >
{{ t('new-assignment') }} {{ t('new-assignment') }}
@ -58,24 +53,26 @@
:key="assignment.id" :key="assignment.id"
cols="12" cols="12"
> >
<v-card class="assignment-card" variant="outlined"> <v-card class="assignment-card">
<v-card-text class="card-content"> <v-card-text class="card-content">
<div class="left-content"> <div class="left-content">
<div class="assignment-title">{{ assignment.title }}</div> <div class="assignment-title">{{ assignment.title }}</div>
<div class="assignment-class"> <div class="assignment-class">
{{ t('class') }}: {{ t('class') }}:
<span class="class-name"> <span class="class-name">
{{ assignment.class }} {{ assignment.class }}
</span> </span>
</div> </div>
</div> </div>
<div class="right-content"> <div class="right-content">
<v-btn <v-card-actions>
color="primary" <v-btn color="primary" @click="goToAssignmentDetails(assignment.id)">
@click="goToAssignmentDetails(assignment.id)" {{ t('view-assignment') }}
> </v-btn>
{{ t('view-assignment') }} <v-btn v-if="isTeacher" color="red" @click="goToDeleteAssignment(assignment.id)">
</v-btn> {{ t('delete') }}
</v-btn>
</v-card-actions>
</div> </div>
</v-card-text> </v-card-text>
</v-card> </v-card>
@ -94,6 +91,13 @@
box-sizing: border-box; box-sizing: border-box;
} }
.center-btn {
display: block;
margin-left: auto;
margin-right: auto;
}
.assignment-card { .assignment-card {
padding: 1rem; padding: 1rem;
} }
@ -117,7 +121,7 @@
.assignment-title { .assignment-title {
font-weight: bold; font-weight: bold;
font-size: 1.5rem; font-size: 1.5rem;
margin-bottom: 0.3rem; margin-bottom: 0.1rem;
word-break: break-word; word-break: break-word;
} }
@ -133,8 +137,17 @@
.right-content { .right-content {
display: flex; display: flex;
align-items: center;
justify-content: flex-end; justify-content: flex-end;
align-items: center;
flex-shrink: 0; flex-shrink: 0;
flex-wrap: wrap;
width: 100%;
} }
@media (min-width: 700px) {
.right-content {
width: auto;
}
}
</style> </style>

7
package-lock.json generated
View file

@ -31,6 +31,7 @@
"name": "@dwengo-1/backend", "name": "@dwengo-1/backend",
"version": "0.1.1", "version": "0.1.1",
"dependencies": { "dependencies": {
"@dwengo-1/common": "^0.1.1",
"@mikro-orm/core": "6.4.9", "@mikro-orm/core": "6.4.9",
"@mikro-orm/knex": "6.4.9", "@mikro-orm/knex": "6.4.9",
"@mikro-orm/postgresql": "6.4.9", "@mikro-orm/postgresql": "6.4.9",
@ -10780,9 +10781,9 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "6.2.3", "version": "6.2.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.3.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.5.tgz",
"integrity": "sha512-IzwM54g4y9JA/xAeBPNaDXiBF8Jsgl3VBQ2YQ/wOY6fyW3xMdSoltIV3Bo59DErdqdE6RxUfv8W69DvUorE4Eg==", "integrity": "sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {