LessonNotes.vue 9.74 KiB
<script setup>
import AbsenceReasonChip from "aleksis.apps.kolego/components/AbsenceReasonChip.vue";
import ExtraMarkChip from "../../extra_marks/ExtraMarkChip.vue";
import ExtraMarksNote from "../personal_notes/ExtraMarksNote.vue";
import TardinessChip from "../absences/TardinessChip.vue";
import PersonalNoteChip from "../personal_notes/PersonalNoteChip.vue";
import TextNoteCard from "../personal_notes/TextNoteCard.vue";
</script>
<template>
<div>
<div
class="d-flex align-center justify-space-between justify-md-end flex-wrap gap"
v-if="compact || documentation.canViewParticipationStatus"
>
<v-chip
dense
color="success"
outlined
v-if="total > 0 && documentation.canViewParticipationStatus"
>
{{
$t("alsijil.coursebook.participations.present_number", {
present,
total,
})
}}
</v-chip>
<v-chip
dense
color="success"
outlined
@click="$emit('open')"
v-bind="dialogActivator.attrs"
v-on="dialogActivator.on"
v-else-if="
total == 1 &&
present == 1 &&
!documentation.canViewParticipationStatus
"
>
{{ $t("alsijil.coursebook.participations.present") }}
</v-chip>
<template v-if="documentation.canViewParticipationStatus">
<absence-reason-chip
v-for="[reasonId, participations] in Object.entries(absences)"
:key="'reason-' + reasonId"
:absence-reason="participations[0].absenceReason"
dense
>
<template #append>
<span
>:
<span>
{{
participations
.slice(0, 5)
.map((participation) => participation.person.firstName)
.join(", ")
}}
</span>
<span v-if="participations.length > 5">
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+{{ participations.length - 5 }}
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</span>
</span>
</template>
</absence-reason-chip>
</template>
<template v-else>
<absence-reason-chip
v-for="[reasonId, participations] in Object.entries(absences)"
:key="'reason-' + reasonId"
:absence-reason="participations[0].absenceReason"
dense
@click="$emit('open')"
v-bind="dialogActivator.attrs"
v-on="dialogActivator.on"
/>
</template>
<template v-if="documentation.canViewParticipationStatus">
<extra-mark-chip
v-for="[markId, [mark, ...participations]] in Object.entries(
extraMarkChips,
)"
:key="'extra-mark-' + markId"
:extra-mark="mark"
dense
>
<template #append>
<span
>:
<span>
{{
participations
.slice(0, 5)
.map((participation) => participation.person.firstName)
.join(", ")
}}
</span>
<span v-if="participations.length > 5">
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+{{ participations.length - 5 }}
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</span>
</span>
</template>
</extra-mark-chip>
</template>
<template v-else>
<extra-mark-chip
v-for="[markId, [mark, ...participations]] in Object.entries(
extraMarkChips,
)"
:key="'extra-mark-' + markId"
:extra-mark="mark"
dense
@click="$emit('open')"
v-bind="dialogActivator.attrs"
v-on="dialogActivator.on"
/>
</template>
<template v-if="documentation.canViewParticipationStatus">
<tardiness-chip v-if="tardyParticipations.length > 0">
<template #default>
{{ $t("alsijil.personal_notes.late") }}
</template>
<template #append>
<span
>:
{{
tardyParticipations
.slice(0, 5)
.map((participation) => participation.person.firstName)
.join(", ")
}}
<span v-if="tardyParticipations.length > 5">
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+{{ tardyParticipations.length - 5 }}
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</span>
</span>
</template>
</tardiness-chip>
</template>
<template v-else>
<tardiness-chip
v-if="tardyParticipations.length > 0"
:tardiness="
tardyParticipations.length == 1
? tardyParticipations[0].tardiness
: undefined
"
@click="$emit('open')"
v-bind="dialogActivator.attrs"
v-on="dialogActivator.on"
/>
</template>
<template v-if="!documentation.canViewParticipationStatus && total == 1">
<personal-note-chip
v-for="note in documentation?.participations[0]?.notesWithNote"
:key="'text-note-note-' + note.id"
:note="note"
@click="$emit('open')"
v-bind="dialogActivator.attrs"
v-on="dialogActivator.on"
/>
</template>
<manage-students-trigger
v-if="documentation.canEditParticipationStatus"
:label-key="manageStudentsLabelKey"
v-bind="documentationPartProps"
/>
</div>
<!-- not compact -->
<div class="main-body" v-else>
<template
v-if="
tardyParticipations.length > 0 || Object.entries(absences).length > 0
"
>
<v-divider />
<div
class="d-flex align-center justify-space-between justify-md-end flex-wrap gap"
>
<tardiness-chip
v-if="tardyParticipations.length > 0"
:tardiness="
tardyParticipations.length == 1
? tardyParticipations[0].tardiness
: undefined
"
/>
<absence-reason-chip
v-for="[reasonId, participations] in Object.entries(absences)"
:key="'reason-' + reasonId"
:absence-reason="participations[0].absenceReason"
dense
/>
</div>
</template>
<template v-if="total == 1">
<v-divider />
<extra-marks-note
v-bind="documentationPartProps"
:participation="documentation?.participations[0]"
:value="documentation?.participations[0].notesWithExtraMark"
:disabled="true"
/>
</template>
<template
v-if="
total == 1 &&
documentation?.participations[0]?.notesWithNote.length > 0
"
>
<v-divider />
<div>
<text-note-card
v-for="note in documentation?.participations[0]?.notesWithNote"
:key="'text-note-note-' + note.id"
:note="note"
/>
</div>
</template>
</div>
</div>
</template>
<script>
import documentationPartMixin from "./documentationPartMixin";
import ManageStudentsTrigger from "../absences/ManageStudentsTrigger.vue";
export default {
name: "LessonNotes",
components: { ManageStudentsTrigger },
mixins: [documentationPartMixin],
computed: {
total() {
return this.documentation.participations.length;
},
/**
* Return the number of present people.
*/
present() {
return this.documentation.participations.filter(
(p) => p.absenceReason === null,
).length;
},
/**
* Get all course attendants who have an absence reason, grouped by that reason.
*/
absences() {
return Object.groupBy(
this.documentation.participations.filter(
(p) => p.absenceReason !== null,
),
({ absenceReason }) => absenceReason.id,
);
},
/**
* Parse and combine all extraMark notes.
*
* Notes with extraMarks are grouped by ExtraMark. ExtraMarks with the showInCoursebook property set to false are ignored.
* @return An object where the keys are extraMark IDs and the values have the structure [extraMark, note1, note2, ..., noteN]
*/
extraMarkChips() {
// Apply the inner function to each participation, with value being the resulting object
return this.documentation.participations.reduce((value, p) => {
// Go through every extra mark of this participation
for (const { extraMark } of p.notesWithExtraMark) {
// Only proceed if the extraMark should be displayed here
if (!extraMark.showInCoursebook) {
continue;
}
// value[extraMark.id] is an Array with the structure [extraMark, note1, note2, ..., noteN]
if (value[extraMark.id]) {
value[extraMark.id].push(p);
} else {
value[extraMark.id] = [
this.extraMarks.find((e) => e.id === extraMark.id),
p,
];
}
}
return value;
}, {});
},
/**
* Return a list Participations with a set tardiness
*/
tardyParticipations() {
return this.documentation.participations.filter((p) => p.tardiness);
},
manageStudentsLabelKey() {
if (this.total == 0) {
return "alsijil.coursebook.notes.show_list";
}
return "";
},
},
};
</script>
<style scoped>
.gap {
gap: 0.25em;
}
.main-body {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 1em;
}
</style>