feat(frontend): nieuwe "cancel" knop bij create assignment

This commit is contained in:
Joyelle Ndagijimana 2025-04-19 15:19:58 +02:00
parent 1d29adaa31
commit 800f6433d6
10 changed files with 44 additions and 238 deletions

View file

@ -11,7 +11,7 @@
const role = auth.authState.activeRole; const role = auth.authState.activeRole;
const name: string = "";//auth.authState.user!.profile.name!; const name = "";//Auth.authState.user!.profile.name!;
const initials: string = name const initials: string = name
.split(" ") .split(" ")
.map((n) => n[0]) .map((n) => n[0])

View file

@ -92,6 +92,6 @@
"group": "Gruppe", "group": "Gruppe",
"description": "Beschreibung", "description": "Beschreibung",
"no-submission": "keine vorlage", "no-submission": "keine vorlage",
"submission": "einreichung", "submission": "Einreichung",
"progress": "Fortschritte" "progress": "Fortschritte"
} }

View file

@ -33,7 +33,7 @@
"JoinClassExplanation": "Enter the code the teacher has given you to join the class.", "JoinClassExplanation": "Enter the code the teacher has given you to join the class.",
"invalidFormat": "Invalid format.", "invalidFormat": "Invalid format.",
"submitCode": "submit", "submitCode": "submit",
"members": "members", "members": "Members",
"themes": "Themes", "themes": "Themes",
"choose-theme": "Select a theme", "choose-theme": "Select a theme",
"choose-age": "Select age", "choose-age": "Select age",
@ -92,6 +92,6 @@
"group": "Group", "group": "Group",
"description": "Description", "description": "Description",
"no-submission": "no submission", "no-submission": "no submission",
"submission": "submission", "submission": "Submission",
"progress": "Progress" "progress": "Progress"
} }

View file

@ -33,7 +33,7 @@
"JoinClassExplanation": "Entrez le code que l'enseignant vous a donné pour rejoindre la classe.", "JoinClassExplanation": "Entrez le code que l'enseignant vous a donné pour rejoindre la classe.",
"invalidFormat": "Format non valide.", "invalidFormat": "Format non valide.",
"submitCode": "envoyer", "submitCode": "envoyer",
"members": "membres", "members": "Membres",
"themes": "Thèmes", "themes": "Thèmes",
"choose-theme": "Choisis un thème", "choose-theme": "Choisis un thème",
"choose-age": "Choisis un âge", "choose-age": "Choisis un âge",
@ -92,6 +92,6 @@
"group": "Groupe", "group": "Groupe",
"description": "Description", "description": "Description",
"no-submission": "aucune soumission", "no-submission": "aucune soumission",
"submission": "soumission", "submission": "Soumission",
"progress": "Progrès" "progress": "Progrès"
} }

View file

@ -33,7 +33,7 @@
"JoinClassExplanation": "Voer de code in die je van de docent hebt gekregen om lid te worden van de klas.", "JoinClassExplanation": "Voer de code in die je van de docent hebt gekregen om lid te worden van de klas.",
"invalidFormat": "Ongeldig formaat.", "invalidFormat": "Ongeldig formaat.",
"submitCode": "verzenden", "submitCode": "verzenden",
"members": "leden", "members": "Leden",
"themes": "Lesthema's", "themes": "Lesthema's",
"choose-theme": "Kies een thema", "choose-theme": "Kies een thema",
"choose-age": "Kies een leeftijd", "choose-age": "Kies een leeftijd",
@ -92,6 +92,6 @@
"group": "Groep", "group": "Groep",
"description": "Beschrijving", "description": "Beschrijving",
"no-submission": "geen indiening", "no-submission": "geen indiening",
"submission": "indiening", "submission": "Indiening",
"progress": "Vooruitgang" "progress": "Vooruitgang"
} }

View file

@ -4,7 +4,7 @@
* Ensures that the title is not empty. * Ensures that the title is not empty.
*/ */
export const assignmentTitleRules = [ export const assignmentTitleRules = [
(value: string) => { (value: string): string | boolean => {
if (value?.length >= 1) return true; // Title must not be empty if (value?.length >= 1) return true; // Title must not be empty
return 'Title cannot be empty.'; return 'Title cannot be empty.';
}, },
@ -16,7 +16,7 @@ export const assignmentTitleRules = [
* Ensures that a valid learning path is selected. * Ensures that a valid learning path is selected.
*/ */
export const learningPathRules = [ export const learningPathRules = [
(value: { hruid: string; title: string }) => { (value: { hruid: string; title: string }): string | boolean => {
if (value && value.hruid) { if (value && value.hruid) {
return true; // Valid if hruid is present return true; // Valid if hruid is present
} }
@ -30,7 +30,7 @@ export const learningPathRules = [
* Ensures that at least one class is selected. * Ensures that at least one class is selected.
*/ */
export const classRules = [ export const classRules = [
(value: string) => { (value: string): string | boolean => {
if (value) return true; if (value) return true;
return 'You must select at least one class.'; return 'You must select at least one class.';
}, },
@ -42,7 +42,7 @@ export const classRules = [
* Ensures that a valid deadline is selected and is in the future. * Ensures that a valid deadline is selected and is in the future.
*/ */
export const deadlineRules = [ export const deadlineRules = [
(value: string) => { (value: string): string | boolean => {
if (!value) return "You must set a deadline."; if (!value) return "You must set a deadline.";
const selectedDateTime = new Date(value); const selectedDateTime = new Date(value);
@ -57,7 +57,7 @@ export const deadlineRules = [
]; ];
export const descriptionRules = [ export const descriptionRules = [
(value: string) => { (value: string): string | boolean => {
if (!value || value.trim() === "") return "Description cannot be empty."; if (!value || value.trim() === "") return "Description cannot be empty.";
return true; return true;
}, },

View file

@ -1,24 +1,24 @@
// TODO : temp data until frontend controllers are ready // TODO : temp data until frontend controllers are ready
type Teacher = { interface Teacher {
username: string; username: string;
firstName: string; firstName: string;
lastName: string; lastName: string;
classes: Array<Class>; classes: Class[];
}; }
type Student = { interface Student {
username: string; username: string;
firstName: string; firstName: string;
lastName: string; lastName: string;
classes: Array<Class>; classes: Class[];
}; }
type Class = { interface Class {
id: string; id: string;
displayName: string; displayName: string;
teachers: Array<Teacher>; teachers: Teacher[];
students: Array<Student>; students: Student[];
}; }
const student01: Student = {username: "id01", firstName: "Mark", lastName: "Knopfler", classes: []}; const student01: Student = {username: "id01", firstName: "Mark", lastName: "Knopfler", classes: []};
const student02: Student = {username: "id02", firstName: "John", lastName: "Hiat", classes: []}; const student02: Student = {username: "id02", firstName: "John", lastName: "Hiat", classes: []};
@ -55,11 +55,11 @@ teacher01.classes = [class01];
teacher02.classes = [class02]; teacher02.classes = [class02];
teacher03.classes = [class03]; teacher03.classes = [class03];
type Assignment = { interface Assignment {
id: string; id: string;
title: string; title: string;
description: string; description: string;
}; }
export const assignments: Assignment[] = Array.from({length: 4}, (_, i) => ({ export const assignments: Assignment[] = Array.from({length: 4}, (_, i) => ({
@ -100,4 +100,4 @@ export const assignments: Assignment[] = Array.from({length: 4}, (_, i) => ({
})); }));
export const classes: Array<Class> = [class01, class02, class03]; export const classes: Class[] = [class01, class02, class03];

View file

@ -1,200 +0,0 @@
<script setup lang="ts">
import { useRoute } from "vue-router";
import {ref, computed} from "vue";
import {useI18n} from "vue-i18n";
import auth from "@/services/auth/auth-service.ts";
import {AssignmentController} from "@/controllers/assignments.ts";
import {asyncComputed} from "@vueuse/core";
const {t, locale} = useI18n();
const language = computed(() => locale.value);
const route = useRoute();
const assignmentId = ref(Number(route.params.id));
const classId = window.history.state?.class_id;
const controller = new AssignmentController(classId);
const role = auth.authState.activeRole;
const isTeacher = computed(() => role === 'teacher');
const assignment = asyncComputed(async () => {
return await controller.getByNumber(assignmentId.value)
}, null);
const submitted = ref(true);//TODO: update by fetching submissions and check group
const submitAssignment = async () => {
//TODO
};
/***
// Display group members
const myGroup = computed(() => {
if (!assignment.value || !assignment.value.groups) return null;
console.log(assignment.value.groups)
return assignment.value.groups.find(group =>
group.members.some(m => m.username === myUsername)
);
});
*/
const deleteAssignment = async () => {
await controller.deleteAssignment(assignmentId.value);
};
</script>
<template>
<div class="container">
<v-card v-if="assignment" class="assignment-card">
<div class="top-buttons">
<v-btn
icon
variant="text"
class="back-btn"
to="/user/assignment"
>
<v-icon>mdi-arrow-left</v-icon>
</v-btn>
<v-btn
v-if="isTeacher"
icon
variant="text"
class="top-right-btn"
@click="deleteAssignment"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
<v-chip
v-if="!isTeacher"
class="ma-2 top-right-btn"
label
color="success"
>
{{ t("submitted") }}
</v-chip>
</div>
<v-card-title class="text-h4">{{ assignment.title }}</v-card-title>
<v-card-subtitle class="subtitle-section">
<v-btn
:to="`/learningPath/${language}/${assignment.learningPath}`"
variant="tonal"
color="primary"
>
{{ t("learning-path") }}
</v-btn>
</v-card-subtitle>
<v-card-text class="description">
{{ assignment.description }}
</v-card-text>
<v-card-text class="group-section">
<h3>{{ t("group") }}</h3>
<!-- Student view
<div v-if="!isTeacher">
<div v-if="myGroup">
<ul>
<li v-for="student in myGroup.members" :key="student.username">
{{ student.firstName + ' ' + student.lastName}}
</li>
</ul>
</div>
</div>-->
<!-- Teacher view
<div v-if="isTeacher">
<v-expansion-panels>
<v-expansion-panel
v-for="(group, index) in assignment.groups"
:key="group.id"
>
<v-expansion-panel-title>
{{ t("group") }} {{ index + 1 }}
</v-expansion-panel-title>
<v-expansion-panel-text>
<ul>
<li v-for="student in group.members" :key="student.username">
{{ student.firstName + ' ' + student.lastName }}
</li>
</ul>
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
</div>-->
</v-card-text >
<v-card-actions class="justify-end">
<v-btn
v-if="!isTeacher"
size="large"
color="success"
variant="flat"
@click="submitAssignment"
>
{{ t("submit") }}
</v-btn>
<v-btn
v-if="isTeacher"
size="large"
color="success"
variant="text"
>
{{ t("view-submissions") }}
</v-btn>
</v-card-actions>
</v-card>
</div>
</template>
<style scoped>
.container {
display: flex;
justify-content: center;
align-items: center;
padding: 2%;
min-height: 100vh;
}
.assignment-card {
width: 85%;
padding: 2%;
border-radius: 12px;
}
.description {
margin-top: 2%;
line-height: 1.6;
font-size: 1.1rem;
}
.top-right-btn {
position: absolute;
right: 2%;
color: red;
}
.group-section {
margin-top: 2rem;
}
.group-section h3 {
margin-bottom: 0.5rem;
}
.group-section ul {
padding-left: 1.2rem;
list-style-type: disc;
}
.subtitle-section {
display: flex;
align-items: center;
justify-content: space-between;
}
</style>

View file

@ -18,12 +18,12 @@ import {useRoute} from "vue-router";
/*** /***
TODO: when clicking the assign button from lp page pass the lp-hruid in a query like this: TODO: when clicking the assign button from lp page pass the lp-hruid in a query like this:
router.push({ router.push({
path: "/assignment/create, path: "/assignment/create,
query: { query: {
...route.query, ...route.query,
lp: hruid, lp: hruid,
}, },
}); });
*/ */
const route = useRoute(); const route = useRoute();
@ -176,7 +176,12 @@ async function submitFormHandler(): Promise<void> {
:rules="descriptionRules" :rules="descriptionRules"
></v-textarea> ></v-textarea>
</v-card-text> </v-card-text>
<v-btn class="mt-2" color="secondary" type="submit" block>Submit</v-btn> <v-card-text>
<v-btn class="mt-2" color="secondary" type="submit" block>{{ t("submit") }}</v-btn>
<v-btn to="/user/assignment" color="grey" block>{{ t("cancel") }}</v-btn>
</v-card-text>
</v-container> </v-container>
</v-form> </v-form>
</v-card> </v-card>

View file

@ -66,13 +66,14 @@ function openGroupDetails(group): void {
dialog.value = true; dialog.value = true;
} }
const headers = ref([ const headers = computed(() => [
{title: t('group'), align: 'start', key: 'name'}, { title: t('group'), align: 'start', key: 'name' },
{title: t('progress'), align: 'center', key: 'progress'}, { title: t('progress'), align: 'center', key: 'progress' },
{title: t('submission'), align: 'center', key: 'submission'} { title: t('submission'), align: 'center', key: 'submission' }
]); ]);
const {mutate, isSuccess} = useDeleteAssignmentMutation(); const {mutate, isSuccess} = useDeleteAssignmentMutation();
async function deleteAssignment(num: number, clsId: string): Promise<void> { async function deleteAssignment(num: number, clsId: string): Promise<void> {
@ -177,7 +178,7 @@ async function deleteAssignment(num: number, clsId: string): Promise<void> {
<v-dialog v-model="dialog" max-width="50%"> <v-dialog v-model="dialog" max-width="50%">
<v-card> <v-card>
<v-card-title class="headline">Group Members</v-card-title> <v-card-title class="headline">{{t("members")}}</v-card-title>
<v-card-text> <v-card-text>
<v-list> <v-list>
<v-list-item <v-list-item