diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue index 7f96c23967989239d6440071ed1a6fc55d4d1052..02349f01add8910e22f6cdfdfb16d99ad303ffb5 100644 --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue @@ -12,11 +12,13 @@ import PersonalNotes from "../personal_notes/PersonalNotes.vue"; import ExtraMarkChip from "../../extra_marks/ExtraMarkChip.vue"; import TardinessChip from "./TardinessChip.vue"; import TardinessField from "./TardinessField.vue"; +import ExtraMarkButtons from "../../extra_marks/ExtraMarkButtons.vue"; export default { name: "ManageStudentsDialog", extends: MobileFullscreenDialog, components: { + ExtraMarkButtons, TardinessChip, ExtraMarkChip, AbsenceReasonChip, @@ -57,9 +59,9 @@ export default { }, }, methods: { - handleMultipleAction(absenceReasonId) { + handleMultipleAction(field, id) { this.loadSelected = true; - this.sendToServer(this.selected, "absenceReason", absenceReasonId); + this.sendToServer(this.selected, field, id); this.$once("save", this.resetMultipleAction); }, resetMultipleAction() { @@ -209,11 +211,17 @@ export default { <template #actions> <v-scroll-y-reverse-transition> <div v-show="selected.length > 0" class="full-width"> + <h4>{{ $t("alsijil.coursebook.participation_status") }}</h4> <absence-reason-buttons + class="mb-1" allow-empty empty-value="present" :custom-absence-reasons="absenceReasons" - @input="handleMultipleAction" + @input="handleMultipleAction('absenceReason', $event)" + /> + <h4>{{ $t("alsijil.extra_marks.title_plural") }}</h4> + <extra-mark-buttons + @input="handleMultipleAction('extraMark', $event)" /> </div> </v-scroll-y-reverse-transition> diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/sendToServerMixin.js b/aleksis/apps/alsijil/frontend/components/coursebook/absences/sendToServerMixin.js index d75f72173b80315705e6cf3f86fe614caeafe051..55cae9e6e8d69b0f4e5d299e9869228ccf9c2702 100644 --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/sendToServerMixin.js +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/sendToServerMixin.js @@ -1,6 +1,7 @@ /** * Mixin to provide shared functionality needed to send updated participation data to the server */ +import { createPersonalNotes } from "../personal_notes/personal_notes.graphql"; import { updateParticipationStatuses } from "./participationStatus.graphql"; import mutateMixin from "aleksis.core/mixins/mutateMixin.js"; @@ -18,6 +19,10 @@ export default { fieldValue = { tardiness: value, }; + } else if (field === "extraMark") { + // Too much different logic → own method + this.addExtraMarks(participations, value); + return; } else { console.error(`Wrong field '${field}' for sendToServer`); return; @@ -46,6 +51,42 @@ export default { participationStatus.isOptimistic = newStatus.isOptimistic; }); + return storedDocumentations; + }, + ); + }, + addExtraMarks(participations, extraMarkId) { + // Get all participation statuses without this extra mark and get the respective person ids + const participants = participations + .filter( + (participation) => + !participation.notesWithExtraMark.some( + (note) => note.extraMark.id === extraMarkId, + ), + ) + .map((participation) => participation.person.id); + + // CREATE new personal note + this.mutate( + createPersonalNotes, + { + input: participants.map((person) => ({ + documentation: this.documentation.id, + person: person, + extraMark: extraMarkId, + })), + }, + (storedDocumentations, incomingPersonalNotes) => { + const documentation = storedDocumentations.find( + (doc) => doc.id === this.documentation.id, + ); + incomingPersonalNotes.forEach((note, index) => { + const participationStatus = documentation.participations.find( + (part) => part.person.id === participants[index], + ); + participationStatus.notesWithExtraMark.push(note); + }); + return storedDocumentations; }, ); diff --git a/aleksis/apps/alsijil/frontend/components/extra_marks/ExtraMarkButtons.vue b/aleksis/apps/alsijil/frontend/components/extra_marks/ExtraMarkButtons.vue new file mode 100644 index 0000000000000000000000000000000000000000..919749ac85ed97f937d5b862a6aa37d199529b30 --- /dev/null +++ b/aleksis/apps/alsijil/frontend/components/extra_marks/ExtraMarkButtons.vue @@ -0,0 +1,73 @@ +<script> +import { extraMarks } from "./extra_marks.graphql"; + +export default { + name: "ExtraMarkButtons", + data() { + return { + extraMarks: [], + }; + }, + apollo: { + extraMarks: { + query: extraMarks, + update: (data) => data.items, + skip() { + return this.customExtraMarks > 0; + }, + }, + }, + props: { + customExtraMarks: { + type: Array, + required: false, + default: () => [], + }, + }, + computed: { + innerExtraMarks() { + if (this.customExtraMarks.length > 0) { + return this.customExtraMarks; + } else { + return this.extraMarks; + } + }, + }, + methods: { + emit(value) { + this.$emit("input", value); + this.$emit("click", value); + }, + }, +}; +</script> + +<template> + <div class="d-flex flex-wrap" style="gap: 0.5em"> + <v-skeleton-loader + class="full-width d-flex flex-wrap child-flex-grow-1" + style="gap: 0.5em" + v-if="$apollo.queries.extraMarks.loading" + type="button@4" + /> + <template v-else> + <v-btn + v-for="extraMark in innerExtraMarks" + :key="'extra-mark-' + extraMark.id" + :color="extraMark.colourBg" + :style="{ color: extraMark.colourFg }" + class="flex-grow-1" + depressed + @click="emit(extraMark.id)" + > + {{ extraMark.name }} + </v-btn> + </template> + </div> +</template> + +<style> +.child-flex-grow-1 > * { + flex-grow: 1; +} +</style> diff --git a/aleksis/apps/alsijil/frontend/messages/en.json b/aleksis/apps/alsijil/frontend/messages/en.json index 2ab6f3647fb2ff6d659862ff6b045747b725ec57..d1a039d4caa7b94b15fdeb36a396b6ec745eef70 100644 --- a/aleksis/apps/alsijil/frontend/messages/en.json +++ b/aleksis/apps/alsijil/frontend/messages/en.json @@ -55,6 +55,7 @@ "cancelled": "Lesson cancelled", "pending": "Lesson pending" }, + "participation_status": "Participation Status", "summary": { "topic": { "label": "Topic", diff --git a/aleksis/apps/alsijil/schema/participation_status.py b/aleksis/apps/alsijil/schema/participation_status.py index 335f5bc8d1c22682725563d2c3c83b88032fbc38..951ab4419341641cc26059a18f04f91890749f1c 100644 --- a/aleksis/apps/alsijil/schema/participation_status.py +++ b/aleksis/apps/alsijil/schema/participation_status.py @@ -47,7 +47,7 @@ class ParticipationStatusType( person=root.person, documentation=root.related_documentation, note__isnull=False, - ) + ).exclude(note="") class ParticipationStatusBatchPatchMutation(BaseBatchPatchMutation):