fix: kleine fixes

This commit is contained in:
Joyelle Ndagijimana 2025-05-17 20:27:28 +02:00
parent 0abe9b1bce
commit 7f1c66c757
5 changed files with 131 additions and 44 deletions

View file

@ -3,6 +3,7 @@
import UsingQueryResult from "@/components/UsingQueryResult.vue"; import UsingQueryResult from "@/components/UsingQueryResult.vue";
import { useAssignmentSubmissionsQuery } from "@/queries/assignments.ts"; import { useAssignmentSubmissionsQuery } from "@/queries/assignments.ts";
import type { SubmissionsResponse } from "@/controllers/submissions.ts"; import type { SubmissionsResponse } from "@/controllers/submissions.ts";
import {watch} from "vue";
const props = defineProps<{ const props = defineProps<{
group: object; group: object;
@ -11,6 +12,8 @@
goToGroupSubmissionLink: (groupNo: number) => void; goToGroupSubmissionLink: (groupNo: number) => void;
}>(); }>();
const emit = defineEmits<(e: "update:hasSubmission", hasSubmission: boolean) => void>();
const { t } = useI18n(); const { t } = useI18n();
const submissionsQuery = useAssignmentSubmissionsQuery( const submissionsQuery = useAssignmentSubmissionsQuery(
() => props.classId, () => props.classId,
@ -18,6 +21,16 @@
() => props.group.originalGroupNo, () => props.group.originalGroupNo,
() => true, () => true,
); );
watch(
() => submissionsQuery.data.value,
(data) => {
if (data) {
emit("update:hasSubmission", data.submissions.length > 0);
}
},
{ immediate: true }
);
</script> </script>
<template> <template>

View file

@ -355,7 +355,7 @@ function removeStudent(groupIndex: number, student: StudentItem): void {
</script> </script>
<template> <template>
<v-card class="pa-4"> <v-card class="pa-4 minimal-card">
<!-- Current groups and unassigned students Preview --> <!-- Current groups and unassigned students Preview -->
<div v-if="showGroupsPreview" class="mb-6"> <div v-if="showGroupsPreview" class="mb-6">
<h3 class="mb-2">{{ t("current-groups") }}</h3> <h3 class="mb-2">{{ t("current-groups") }}</h3>
@ -364,20 +364,13 @@ function removeStudent(groupIndex: number, student: StudentItem): void {
<label>{{ currentGroups.length }}</label> <label>{{ currentGroups.length }}</label>
</div> </div>
</div> </div>
<div v-if="unassignedStudents.length > 0" class="mt-3">
<strong>{{ t("unassigned-students") }}:</strong>
<div class="d-flex flex-wrap">
<label>{{ unassignedStudents.length }}</label>
</div>
</div>
</div> </div>
<v-row justify="center" class="mb-4"> <v-row justify="center" class="mb-4">
<v-btn color="primary" @click="activeDialog = 'random'"> <v-btn color="primary" @click="activeDialog = 'random'" prepend-icon="mdi-shuffle">
{{ t("randomly-create-groups") }} {{ t("random-grouping") }}
</v-btn> </v-btn>
<v-btn color="secondary" class="ml-4" @click="activeDialog = 'dragdrop'"> <v-btn color="secondary" class="ml-4" @click="activeDialog = 'dragdrop'" prepend-icon="mdi-drag">
{{ t("drag-and-drop") }} {{ t("drag-and-drop") }}
</v-btn> </v-btn>
</v-row> </v-row>
@ -388,8 +381,8 @@ function removeStudent(groupIndex: number, student: StudentItem): void {
@update:model-value="(val) => (val ? (activeDialog = 'random') : (activeDialog = null))" @update:model-value="(val) => (val ? (activeDialog = 'random') : (activeDialog = null))"
max-width="600" max-width="600"
> >
<v-card> <v-card class="custom-dialog">
<v-card-title>{{ t("randomly-create-groups") }}</v-card-title> <v-card-title class="dialog-title">{{ t("auto-generate-groups") }}</v-card-title>
<v-card-text> <v-card-text>
<v-row align="center"> <v-row align="center">
<v-col cols="6"> <v-col cols="6">
@ -442,7 +435,7 @@ function removeStudent(groupIndex: number, student: StudentItem): void {
</div> </div>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions class="dialog-actions">
<v-spacer/> <v-spacer/>
<v-btn text @click="activeDialog = null">{{ t("cancel") }}</v-btn> <v-btn text @click="activeDialog = null">{{ t("cancel") }}</v-btn>
<v-btn <v-btn
@ -462,8 +455,8 @@ function removeStudent(groupIndex: number, student: StudentItem): void {
@update:model-value="(val) => (val ? (activeDialog = 'dragdrop') : (activeDialog = null))" @update:model-value="(val) => (val ? (activeDialog = 'dragdrop') : (activeDialog = null))"
max-width="900" max-width="900"
> >
<v-card> <v-card class="custom-dialog">
<v-card-title class="d-flex justify-space-between align-center"> <v-card-title class=" dialog-title d-flex justify-space-between align-center">
<div>{{ t("drag-and-drop") }}</div> <div>{{ t("drag-and-drop") }}</div>
<v-btn color="primary" small @click="addNewGroup">+</v-btn> <v-btn color="primary" small @click="addNewGroup">+</v-btn>
</v-card-title> </v-card-title>
@ -603,4 +596,60 @@ function removeStudent(groupIndex: number, student: StudentItem): void {
visibility: hidden; visibility: hidden;
display: inline-block; display: inline-block;
} }
.custom-dialog {
border-radius: 16px;
padding: 24px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}
.dialog-title {
color: #00796b; /* teal-like green */
font-weight: bold;
font-size: 1.25rem;
margin-bottom: 16px;
}
.dialog-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 24px;
}
.v-btn.custom-green {
background-color: #43a047;
color: white;
}
.v-btn.custom-green:hover {
background-color: #388e3c
}
.v-btn.custom-blue {
background-color: #1e88e5;
color: white;
}
.v-btn.custom-blue:hover {
background-color: #1565c0 ;
}
.v-btn.cancel-button {
background-color: #e0f2f1;
color: #00695c;
}
.minimal-card {
box-shadow: none; /* remove card shadow */
border: none; /* remove border */
background-color: transparent; /* make background transparent */
padding: 0; /* reduce padding */
margin-bottom: 1rem; /* keep some spacing below */
}
/* Optionally, keep some padding only around buttons */
.minimal-card > .v-row {
padding: 1rem 0; /* give vertical padding around buttons */
}
</style> </style>

View file

@ -36,6 +36,7 @@ const assignmentTitle = ref("");
const selectedLearningPath = ref<LearningPath | undefined>(undefined); const selectedLearningPath = ref<LearningPath | undefined>(undefined);
const lpIsSelected = ref(false); const lpIsSelected = ref(false);
watch(learningPathsQueryResults.data, (data) => { watch(learningPathsQueryResults.data, (data) => {
const hruidFromRoute = route.query.hruid?.toString(); const hruidFromRoute = route.query.hruid?.toString();
if (!hruidFromRoute || !data) return; if (!hruidFromRoute || !data) return;
@ -61,9 +62,8 @@ async function submitFormHandler(): Promise<void> {
if (!valid) return; if (!valid) return;
const lp = lpIsSelected.value const lp = lpIsSelected.value
? route.query.hruid ? route.query.hruid?.toString()
: selectedLearningPath.value?.hruid; : selectedLearningPath.value?.hruid;
if (!lp) { if (!lp) {
return; return;
} }
@ -71,10 +71,10 @@ async function submitFormHandler(): Promise<void> {
const assignmentDTO: AssignmentDTO = { const assignmentDTO: AssignmentDTO = {
id: 0, id: 0,
within: selectedClass.value?.id || "", within: selectedClass.value?.id || "",
title: assignmentTitle.value.toString(), title: assignmentTitle.value,
description: "", description: "",
learningPath: lp.toString(), learningPath: lp,
language: language.value.toString(), language: language.value,
deadline: null, deadline: null,
groups: [], groups: [],
}; };
@ -83,9 +83,9 @@ async function submitFormHandler(): Promise<void> {
} }
const learningPathRules = [ const learningPathRules = [
(value: any) => { (value: LearningPath): string | boolean => {
if(lpIsSelected.value) return; if(lpIsSelected.value) return true;
if (!value) return t("lp-required"); if (!value) return t("lp-required");
@ -146,17 +146,17 @@ const classRules = [
v-slot="{ data }: { data: LearningPath[] }" v-slot="{ data }: { data: LearningPath[] }"
> >
<v-combobox <v-combobox
v-model="selectedLearningPath"
:items="data" :items="data"
:label="t('choose-lp')" :label="t('choose-lp')"
:rules="lpIsSelected ? [] : learningPathRules" :rules="lpIsSelected ? [] : learningPathRules"
variant="solo-filled" variant="solo-filled"
clearable clearable
:model-value="lpIsSelected ? data.find(lp => lp.hruid === route.query.hruid?.toString()) : selectedLearningPath"
item-title="title" item-title="title"
item-value="hruid"
:disabled="lpIsSelected" :disabled="lpIsSelected"
return-object return-object
/> />
</using-query-result> </using-query-result>
<!-- Klas keuze --> <!-- Klas keuze -->

View file

@ -60,6 +60,9 @@ watchEffect(() => {
} }
}); });
const hasSubmissions = ref<boolean>(false);
const allGroups = computed(() => { const allGroups = computed(() => {
const groups = groupsQueryResult.data.value?.groups; const groups = groupsQueryResult.data.value?.groups;
@ -73,7 +76,7 @@ const allGroups = computed(() => {
groupNo: index + 1, // New group number that will be used groupNo: index + 1, // New group number that will be used
name: `${t("group")} ${index + 1}`, name: `${t("group")} ${index + 1}`,
members: group.members, members: group.members,
originalGroupNo: group.groupNumber, // Keep original number if needed originalGroupNo: group.groupNumber
})); }));
}); });
@ -298,29 +301,42 @@ async function handleGroupsUpdated(updatedGroups: string[][]): Promise<void> {
<!-- A pop up to show group members --> <!-- A pop up to show group members -->
<v-dialog <v-dialog
v-model="dialog" v-model="dialog"
max-width="50%" max-width="600"
persistent
> >
<v-card> <v-card class="pa-4 rounded-xl elevation-6 group-members-dialog">
<v-card-title class="headline">{{ t("members") }}</v-card-title> <v-card-title class="text-h6 font-weight-bold">
{{ t("members") }}
</v-card-title>
<v-divider class="my-2" />
<v-card-text> <v-card-text>
<v-list> <v-list>
<v-list-item <v-list-item
v-for="(member, index) in selectedGroup.members" v-for="(member, index) in selectedGroup.members"
:key="index" :key="index"
class="py-2"
> >
<v-list-item-content> <v-list-item-content>
<v-list-item-title <v-list-item-title class="text-body-1">
>{{ member.firstName + " " + member.lastName }} {{ member.firstName }} {{ member.lastName }}
</v-list-item-title> </v-list-item-title>
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
</v-list> </v-list>
</v-card-text> </v-card-text>
<v-card-actions>
<v-divider class="my-2" />
<v-card-actions class="justify-end">
<v-btn <v-btn
color="primary" color="primary"
variant="outlined"
@click="dialog = false" @click="dialog = false"
>Close prepend-icon="mdi-close-circle"
>
{{ t("close") }}
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
@ -345,6 +361,7 @@ async function handleGroupsUpdated(updatedGroups: string[][]): Promise<void> {
<v-btn <v-btn
@click="editGroups = true" @click="editGroups = true"
variant="text" variant="text"
:disabled="hasSubmissions"
> >
<v-icon>mdi-pencil</v-icon> <v-icon>mdi-pencil</v-icon>
</v-btn> </v-btn>
@ -358,11 +375,9 @@ async function handleGroupsUpdated(updatedGroups: string[][]): Promise<void> {
> >
<td> <td>
<v-btn <v-btn
@click="openGroupDetails(g)"
variant="text" variant="text"
> >
{{ g.name }} {{ g.name }}
<v-icon end>mdi-menu-right</v-icon>
</v-btn> </v-btn>
</td> </td>
@ -383,16 +398,18 @@ async function handleGroupsUpdated(updatedGroups: string[][]): Promise<void> {
:class-id="classId" :class-id="classId"
:language="lang" :language="lang"
:go-to-group-submission-link="goToGroupSubmissionLink" :go-to-group-submission-link="goToGroupSubmissionLink"
@update:hasSubmission="(hasSubmission) => hasSubmissions = hasSubmission"
/> />
</td> </td>
<!-- Edit icon --> <!-- Edit icon -->
<td> <td>
<v-btn <v-btn
@click="" @click="openGroupDetails(g)"
variant="text" variant="text"
> >
<v-icon color="red">mdi-delete</v-icon> <v-icon>mdi-eye</v-icon>
</v-btn> </v-btn>
</td> </td>
</tr> </tr>
@ -416,16 +433,18 @@ async function handleGroupsUpdated(updatedGroups: string[][]): Promise<void> {
@close="editGroups = false" @close="editGroups = false"
/> />
</v-card-text> </v-card-text>
<v-divider></v-divider>
<v-card-actions> <v-card-actions>
<v-btn <v-spacer></v-spacer>
text <v-btn text @click="editGroups = false">
@click="editGroups = false" {{ t("cancel") }}
>{{ t("cancel") }} </v-btn>
</v-btn
>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
</v-container> </v-container>
</using-query-result> </using-query-result>
</div> </div>
@ -557,4 +576,10 @@ main {
flex-basis: 100% !important; flex-basis: 100% !important;
} }
} }
.group-members-dialog {
max-height: 80vh;
overflow-y: auto;
}
</style> </style>

View file

@ -146,7 +146,7 @@
<v-btn <v-btn
v-if="isTeacher" v-if="isTeacher"
color="primary" :style="{ backgroundColor: '#0E6942' }"
class="mb-4 center-btn" class="mb-4 center-btn"
@click="goToCreateAssignment" @click="goToCreateAssignment"
> >