From 9e566fe4daafe87ac08b08141e2337835b1bc753 Mon Sep 17 00:00:00 2001 From: Michael Bauer <michael-bauer@posteo.de> Date: Fri, 9 Feb 2024 20:34:16 +0100 Subject: [PATCH] Implement modal lesson summary component --- .../frontend/components/Coursebook.vue | 6 +- .../documentation/Documentation.vue | 48 ++++++++--- .../documentation/DocumentationModal.vue | 39 +++++++++ .../documentation/LessonSummary.vue | 84 ++++++++++++------- 4 files changed, 134 insertions(+), 43 deletions(-) create mode 100644 aleksis/apps/alsijil/frontend/components/documentation/DocumentationModal.vue diff --git a/aleksis/apps/alsijil/frontend/components/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/Coursebook.vue index 718ea3dbb..0d27a6e38 100644 --- a/aleksis/apps/alsijil/frontend/components/Coursebook.vue +++ b/aleksis/apps/alsijil/frontend/components/Coursebook.vue @@ -12,7 +12,7 @@ <v-list-item-title>{{ $d(day[0], "short") }}</v-list-item-title> <v-list> <v-list-item v-for="doc in day.slice(1)"> - <documentation :documentation="doc" /> + <documentation-modal :documentation="doc" /> </v-list-item> </v-list> </v-list-item-content> @@ -23,7 +23,7 @@ <script> import CRUDIterator from "aleksis.core/components/generic/CRUDIterator.vue"; -import Documentation from "./documentation/Documentation.vue"; +import DocumentationModal from "./documentation/DocumentationModal.vue"; import { documentationsForCoursebook } from "./coursebook.graphql"; import { DateTime } from "luxon"; @@ -31,7 +31,7 @@ export default { name: "Coursebook", components: { CRUDIterator, - Documentation, + DocumentationModal, }, props: { // Either as props OR route params diff --git a/aleksis/apps/alsijil/frontend/components/documentation/Documentation.vue b/aleksis/apps/alsijil/frontend/components/documentation/Documentation.vue index de75c7ef4..6b38b4c60 100644 --- a/aleksis/apps/alsijil/frontend/components/documentation/Documentation.vue +++ b/aleksis/apps/alsijil/frontend/components/documentation/Documentation.vue @@ -1,21 +1,39 @@ <template> <v-card class="my-2 full-width"> - <div class="full-width d-flex flex-column flex-md-row align-stretch"> + <!-- flex-md-row zeile ab medium --> + <!-- align-stretch - stretch full-width --> + <div + class="full-width d-flex flex-column align-stretch" + :class="{ 'flex-md-row': ('compact' in $attrs) }" + > <lesson-information - :documentation="documentation" + class="flex-grow-1" + :documentation="$attrs.documentation" /> <lesson-summary class="flex-grow-1" - :documentation="documentation" + ref="summary" + v-bind="$attrs" :is-create="false" :gql-patch-mutation="documentationsMutation" - @edit="popup" + @open="$emit('open')" + @loading="loading = $event" + @save="$emit('close')" /> <lesson-notes class="flex-grow-1" - :documentation="documentation" + :documentation="$attrs.documentation" /> </div> + <v-divider/> + <v-card-actions v-if="!('compact' in $attrs)"> + <v-spacer/> + <cancel-button @click="$emit('close')" :disabled="loading" /> + <save-button + @click="save" + :loading="loading" + /> + </v-card-actions> </v-card> </template> @@ -24,7 +42,9 @@ import LessonInformation from "./LessonInformation.vue"; import LessonSummary from "./LessonSummary.vue"; import LessonNotes from "./LessonNotes.vue"; -// or pass from Coursebook? +import SaveButton from "aleksis.core/components/generic/buttons/SaveButton.vue"; +import CancelButton from "aleksis.core/components/generic/buttons/CancelButton.vue"; + import { createOrUpdateDocumentations } from "../coursebook.graphql"; export default { @@ -33,17 +53,21 @@ export default { LessonInformation, LessonSummary, LessonNotes, + SaveButton, + CancelButton, }, - props: { - documentation: { - type: Object, - required: true, - }, - }, + emits: ["open", "close"], data() { return { + loading: false, documentationsMutation: createOrUpdateDocumentations, }; }, + methods: { + save() { + this.$refs.summary.save(); + this.$emit('close'); + }, + }, }; </script> diff --git a/aleksis/apps/alsijil/frontend/components/documentation/DocumentationModal.vue b/aleksis/apps/alsijil/frontend/components/documentation/DocumentationModal.vue new file mode 100644 index 000000000..95ce18a01 --- /dev/null +++ b/aleksis/apps/alsijil/frontend/components/documentation/DocumentationModal.vue @@ -0,0 +1,39 @@ +<!-- Wrapper around Documentation.vue --> +<!-- That uses it either as list item or as editable modal dialog. --> +<template> + <mobile-fullscreen-dialog v-model="popup" max-width="500px"> + <template #activator="{ on, attrs }"> + <!-- list view -> activate dialog --> + <documentation + compact + @open="popup = true" + v-bind="{...$attrs, ...attrs}" + v-on="on" + /> + </template> + <!-- dialog view -> deactivate dialog --> + <!-- cancel | save (through lesson-summary) --> + <documentation + v-bind="$attrs" + @close="popup = false" + /> + </mobile-fullscreen-dialog> +</template> + +<script> +import MobileFullscreenDialog from "aleksis.core/components/generic/dialogs/MobileFullscreenDialog.vue" +import Documentation from "./Documentation.vue"; + +export default { + name: "DocumentationModal", + components: { + MobileFullscreenDialog, + Documentation, + }, + data() { + return { + popup: false, + }; + }, +}; +</script> diff --git a/aleksis/apps/alsijil/frontend/components/documentation/LessonSummary.vue b/aleksis/apps/alsijil/frontend/components/documentation/LessonSummary.vue index 230bb1716..2d0599841 100644 --- a/aleksis/apps/alsijil/frontend/components/documentation/LessonSummary.vue +++ b/aleksis/apps/alsijil/frontend/components/documentation/LessonSummary.vue @@ -1,41 +1,55 @@ <template> <v-card-text> - <!-- Are focusout & enter enough trigger? --> - <!-- TODO: focusout on enter --> + <!-- compact --> <v-text-field + dense filled + v-if="compact" label="Thema" :value="documentation.topic" @input="topic=$event" - @focusout="saveTopic" - @keydown.enter="saveTopic" + @focusout="save" + @keydown.enter="saveAndBlur" /> - <v-text-field - filled - v-if="!compact" - label="Hausaufgaben" - :value="documentation.homework" - @input="homework=$event" - /> - <v-text-field - filled - v-if="!compact" - label="Gruppennotiz" - :value="documentation.groupnote" - @input="groupnote=$event" - /> <v-chip v-if="compact" outlined + @click="$emit('open')" > Hausaufgaben: {{ truncate(documentation.homework) }} </v-chip> <v-chip v-if="compact" outlined + @click="$emit('open')" > - Gruppennotiz: {{ truncate(documentation.groupnote) }} + Gruppennotiz: {{ truncate(documentation.groupNote) }} </v-chip> + <!-- not compact --> + <!-- Are focusout & enter enough trigger? --> + <v-text-field + filled + v-if="!compact" + label="Thema" + :value="documentation.topic" + @input="topic=$event" + /> + <v-textarea + filled + auto-grow + v-if="!compact" + label="Hausaufgaben" + :value="documentation.homework" + @input="homework=$event" + /> + <v-textarea + filled + auto-grow + v-if="!compact" + label="Gruppennotiz" + :value="documentation.groupNote" + @input="groupNote=$event" + /> </v-card-text> </template> @@ -54,30 +68,44 @@ export default { compact: { type: Boolean, required: false, - default: true, + default: false, }, }, + emits: ["open"], data() { return { topic: "", homework: "", - groupnote: "", + groupNote: "", }; }, methods: { - saveTopic() { - if (this.topic) { + truncate(str) { + return str ? + (str.length > 25) ? str.slice(0, 24) + ' …' : str + : ""; + }, + save() { + if (this.topic || this.homework || this.groupNote) { + const topic = this.topic ? { topic: this.topic } : {}; + const homework = this.homework ? { homework: this.homework } : {}; + const groupNote = this.groupNote ? { groupNote: this.groupNote } : {}; + this.createOrPatch([{ id: this.documentation.id, - topic: this.topic, + ...topic, + ...homework, + ...groupNote, }]); + this.topic = ""; + this.homework = ""; + this.groupNote = ""; } }, - truncate(str) { - return str ? - (str.length > 30) ? str.slice(0, 29) + '…' : str - : ""; + saveAndBlur(event) { + this.save(); + event.target.blur(); }, }, }; -- GitLab