diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue index 0e6b96ea6c6318b57dcf08ec41b88e427e183c90..d136fa81b32b63ca5d448915fe6414698a971def 100644 --- a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue +++ b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue @@ -18,10 +18,7 @@ </template> <template #item="{ item, lastQuery }"> - <documentation-modal - :documentation="item" - :affected-query="lastQuery" - /> + <component :is="itemComponent" :documentation="item" :affectedQuery="lastQuery" /> </template> <template #loading> @@ -56,6 +53,7 @@ import CoursebookFilters from "./CoursebookFilters.vue"; import CoursebookLoader from "./CoursebookLoader.vue"; import CoursebookEmptyMessage from "./CoursebookEmptyMessage.vue"; import DocumentationModal from "./documentation/DocumentationModal.vue"; +import DocumentationAbsencesModal from "./absences/DocumentationAbsencesModal.vue"; export default { name: "Coursebook", @@ -64,6 +62,7 @@ export default { CoursebookFilters, CoursebookLoader, DocumentationModal, + DocumentationAbsencesModal, InfiniteScrollingDateSortedCRUDIterator, }, props: { @@ -81,6 +80,11 @@ export default { required: false, default: null, }, + pageType: { + type: String, + required: false, + default: "documentations", + }, /** * Number of consecutive to load at once * This number of days is initially loaded and loaded @@ -136,6 +140,7 @@ export default { objId: this.objId, filterType: this.filterType, incomplete: this.incomplete, + pageType: this.pageType, }; }, set(selectedFilters) { @@ -144,7 +149,8 @@ export default { } else if ( Object.hasOwn(selectedFilters, "filterType") || Object.hasOwn(selectedFilters, "objId") || - Object.hasOwn(selectedFilters, "objType") + Object.hasOwn(selectedFilters, "objType") || + Object.hasOwn(selectedFilters, "pageType") ) { this.$router.push({ name: "alsijil.coursebook", @@ -154,6 +160,9 @@ export default { : this.filterType, objType: selectedFilters.objType, objId: selectedFilters.objId, + pageType: selectedFilters.pageType + ? selectedFilters.pageType + : this.pageType, }, hash: this.$route.hash, }); @@ -165,6 +174,13 @@ export default { } }, }, + itemComponent() { + if (this.pageType === 'documentations') { + return "DocumentationModal"; + } else { + return "DocumentationAbsencesModal"; + } + }, }, }; </script> diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookFilters.vue b/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookFilters.vue index b47ebbfbb1d1cd8219686f05085eb0eeb8f453d3..54f419b217c32674aa0643b9cdc7bbff90b6d40d 100644 --- a/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookFilters.vue +++ b/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookFilters.vue @@ -15,7 +15,7 @@ @click:clear="selectObject" class="max-width" /> - <div class="ml-6"> + <div class="mx-6"> <v-switch :loading="selectLoading" :label="$t('alsijil.coursebook.filter.own')" @@ -39,6 +39,14 @@ hide-details /> </div> + <v-btn + outlined + color="primary" + :loading="selectLoading" + @click="togglePageType()" + > + {{ pageTypeButtonText }} + </v-btn> </div> </template> @@ -95,6 +103,13 @@ export default { o.id === this.value.objId, ); }, + pageTypeButtonText() { + if (this.value.pageType === "documentations") { + return this.$t("alsijil.coursebook.filter.page_type.absences"); + } else { + return this.$t("alsijil.coursebook.filter.page_type.documentations"); + } + }, }, methods: { selectObject(selection) { @@ -110,6 +125,13 @@ export default { objId: this.value.objId, }); }, + togglePageType() { + this.$emit("input", { + pageType: this.value.pageType === "documentations" ? "absences" : "documentations", + objType: this.value.objType, + objId: this.value.objId, + }); + }, }, }; </script> diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCard.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCard.vue new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsences.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsences.vue new file mode 100644 index 0000000000000000000000000000000000000000..de3bac643a2db0665732e84f25a204a7171a74e3 --- /dev/null +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsences.vue @@ -0,0 +1,90 @@ +<template> + <v-card :class="{ 'my-1 full-width': true, 'd-flex flex-column': !compact }"> + <v-card-title v-if="!compact"> + <lesson-information v-bind="documentationPartProps" /> + </v-card-title> + + <v-card-text + class="full-width main-body" + :class="{ + vertical: !compact || $vuetify.breakpoint.mobile, + 'pa-2': compact, + }" + > + <lesson-information v-if="compact" v-bind="documentationPartProps" /> + <div> + <div v-for="participation in documentation.participations"> + {{ participation }} + </div> + </div> + <lesson-notes v-bind="documentationPartProps" /> + </v-card-text> + <v-spacer /> + <v-divider /> + <v-card-actions v-if="!compact"> + <v-spacer /> + <cancel-button + v-if="documentation.canEdit" + @click="$emit('close')" + :disabled="loading" + /> + <save-button + v-if="documentation.canEdit" + @click="save" + :loading="loading" + /> + <cancel-button + v-if="!documentation.canEdit" + i18n-key="actions.close" + @click="$emit('close')" + /> + </v-card-actions> + </v-card> +</template> + +<script> +import LessonInformation from "../documentation/LessonInformation.vue"; +import LessonNotes from "../documentation/LessonNotes.vue"; + +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"; + +import documentationPartMixin from "../documentation/documentationPartMixin"; + +export default { + name: "DocumentationAbsences", + components: { + LessonInformation, + LessonNotes, + SaveButton, + CancelButton, + }, + emits: ["open", "close"], + mixins: [documentationPartMixin], + data() { + return { + loading: false, + documentationsMutation: createOrUpdateDocumentations, + }; + }, + methods: { + save() { + this.$refs.summary.save(); + this.$emit("close"); + }, + }, +}; +</script> + +<style scoped> +.main-body { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1em; +} +.vertical { + grid-template-columns: 1fr; +} +</style> diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue new file mode 100644 index 0000000000000000000000000000000000000000..92d9d51ca2c6039fc74479e7edc8f1743ac5d5e4 --- /dev/null +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue @@ -0,0 +1,31 @@ +<!-- Wrapper around DocumentationAbsences.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="activator"> + <!-- list view -> activate dialog --> + <documentation-absences compact v-bind="$attrs" :dialog-activator="activator" /> + </template> + <!-- dialog view -> deactivate dialog --> + <!-- cancel | save (through lesson-summary) --> + <documentation-absences v-bind="$attrs" @close="popup = false" /> + </mobile-fullscreen-dialog> +</template> + +<script> +import MobileFullscreenDialog from "aleksis.core/components/generic/dialogs/MobileFullscreenDialog.vue"; +import DocumentationAbsences from "./DocumentationAbsences.vue"; + +export default { + name: "DocumentationAbsencesModal", + components: { + MobileFullscreenDialog, + DocumentationAbsences, + }, + data() { + return { + popup: false, + }; + }, +}; +</script> diff --git a/aleksis/apps/alsijil/frontend/index.js b/aleksis/apps/alsijil/frontend/index.js index 1ec79280e06ef377c4be215c27b5291c51043522..6f1ec9b3d931278b17a5f54e5303ee21df17bdc0 100644 --- a/aleksis/apps/alsijil/frontend/index.js +++ b/aleksis/apps/alsijil/frontend/index.js @@ -63,6 +63,7 @@ export default { name: "alsijil.coursebook", params: { filterType: "my", + pageType: "documentations" }, hash: "#" + DateTime.now().toISODate(), }; @@ -79,7 +80,7 @@ export default { }, children: [ { - path: ":filterType(my|all)/:objType(group|course|teacher)?/:objId(\\d+)?/", + path: ":pageType(documentations|absences)/:filterType(my|all)/:objType(group|course|teacher)?/:objId(\\d+)?/", component: () => import("./components/coursebook/Coursebook.vue"), name: "alsijil.coursebook", meta: { diff --git a/aleksis/apps/alsijil/frontend/messages/en.json b/aleksis/apps/alsijil/frontend/messages/en.json index 71a509cfec66659437760a1c2ab2fc41ad35cd3c..ec55ef953fbace7b857bd0b6081976d5aee8c59a 100644 --- a/aleksis/apps/alsijil/frontend/messages/en.json +++ b/aleksis/apps/alsijil/frontend/messages/en.json @@ -72,7 +72,11 @@ "missing": "Only show incomplete lessons", "groups": "Groups", "courses": "Courses", - "filter_for_obj": "Filter for group and course" + "filter_for_obj": "Filter for group and course", + "page_type": { + "documentations": "Show documentations", + "absences": "Show absences" + } }, "present_number": "{present}/{total} present", "no_data": "No lessons for the selected groups and courses in this period",