<script setup> // eslint-disable-next-line no-unused-vars import CreateSubject from "aleksis.apps.cursus/components/CreateSubject.vue"; import ForeignKeyField from "aleksis.core/components/generic/forms/ForeignKeyField.vue"; import SubjectChip from "aleksis.apps.cursus/components/SubjectChip.vue"; import InlineCRUDList from "aleksis.core/components/generic/InlineCRUDList.vue"; </script> <template> <inline-c-r-u-d-list :headers="headers" :i18n-key="i18nKey" :create-item-i18n-key="createItemI18nKey" :gql-query="gqlQuery" :gql-create-mutation="gqlCreateMutation" :gql-patch-mutation="gqlPatchMutation" :gql-delete-mutation="gqlDeleteMutation" :default-item="defaultItem" :get-create-data="getCreateData" :get-patch-data="getPatchData" filter > <template #breakSlot="{ item }"> <div class="body-1">{{ formatBreakSlotItem(item.breakSlot) }}</div> <div class="caption"> {{ formatTimeGridItem(item.breakSlot.timeGrid) }} </div> </template> <!-- eslint-disable-next-line vue/valid-v-slot --> <template #breakSlot.field="{ attrs, on }"> <div aria-required="true"> <v-autocomplete return-object :items="internalBreakSlots" :item-text="formatBreakSlotItem" item-value="id" :loading="$apollo.queries.internalBreakSlots.loading" v-bind="attrs" v-on="on" > <template #item="data"> <v-list-item-content> <v-list-item-title>{{ formatBreakSlotItem(data.item) }}</v-list-item-title> <v-list-item-subtitle>{{ formatTimeGridItem(data.item.timeGrid) }}</v-list-item-subtitle> </v-list-item-content> </template> </v-autocomplete> </div> </template> <template #rooms="{ item }"> <v-chip v-for="room in item.rooms" dense class="mx-1" :key="room.id">{{ room.shortName }}</v-chip> </template> <!-- eslint-disable-next-line vue/valid-v-slot --> <template #rooms.field="{ attrs, on }"> <div aria-required="true"> <v-autocomplete multiple return-object :items="internalRooms" item-text="name" item-value="id" :loading="$apollo.queries.internalRooms.loading" v-bind="attrs" v-on="on" /> </div> </template> <template #teachers="{ item }"> <v-chip v-for="teacher in item.teachers" dense class="mx-1" :key="teacher.id" >{{ teacher.fullName }}</v-chip > </template> <!-- eslint-disable-next-line vue/valid-v-slot --> <template #teachers.field="{ attrs, on }"> <div aria-required="true"> <v-autocomplete multiple return-object :items="persons" item-text="fullName" item-value="id" v-bind="attrs" v-on="on" :loading="$apollo.queries.persons.loading" > <template #item="data"> <v-list-item-action> <v-checkbox v-model="data.attrs.inputValue" /> </v-list-item-action> <v-list-item-content> <v-list-item-title>{{ data.item.fullName }}</v-list-item-title> <v-list-item-subtitle v-if="data.item.shortName">{{ data.item.shortName }}</v-list-item-subtitle> </v-list-item-content> </template> </v-autocomplete> </div> </template> <template #subject="{ item }"> <subject-chip v-if="item.subject" :subject="item.subject" /> </template> <!-- eslint-disable-next-line vue/valid-v-slot --> <template #subject.field="{ attrs, on }"> <foreign-key-field v-bind="attrs" v-on="on" :fields="subject.fields" :default-item="subject.defaultItem" :gql-query="subject.gqlQuery" :gql-patch-mutation="{}" :gql-create-mutation="subject.gqlCreateMutation" :get-create-data="subject.transformCreateData" create-item-i18n-key="cursus.subject.create" return-object > <template #createComponent="{ attrs: attrs2, on: on2 }"> <create-subject v-bind="attrs2" v-on="on2"></create-subject> </template> </foreign-key-field> </template> <!--<template #filters="{ attrs, on }">--> <!-- <time-grid-field--> <!-- outlined--> <!-- filled--> <!-- v-bind="attrs('break_slot__time_grid__exact')"--> <!-- v-on="on('break_slot__time_grid__exact')"--> <!-- :label="$t('lesrooster.labels.select_validity_range')"--> <!-- hide-details--> <!-- />--> <!--</template>--> </inline-c-r-u-d-list> </template> <script> import { supervisions, createSupervisions, deleteSupervisions, updateSupervisions, } from "./supervision.graphql"; import { gqlTeachers } from "../helper.graphql"; import { rooms } from "aleksis.core/components/room/room.graphql"; import { breakSlots } from "../breaks_and_slots/break.graphql"; import { subjects, createSubjects, } from "aleksis.apps.cursus/components/subject.graphql"; import { RRule } from "rrule"; export default { name: "LesroosterSupervision", data() { return { headers: [ { text: this.$t("lesrooster.supervision.break_slot"), value: "breakSlot", }, { text: this.$t("lesrooster.supervision.rooms"), value: "rooms", }, { text: this.$t("lesrooster.supervision.teachers"), value: "teachers", }, { text: this.$t("lesrooster.supervision.subject"), value: "subject", }, ], i18nKey: "lesrooster.supervision", createItemI18nKey: "lesrooster.supervision.create_supervision", gqlQuery: supervisions, gqlCreateMutation: createSupervisions, gqlPatchMutation: updateSupervisions, gqlDeleteMutation: deleteSupervisions, defaultItem: { breakSlot: null, teachers: [], rooms: [], }, subject: { gqlQuery: subjects, gqlCreateMutation: createSubjects, transformCreateData(item) { return { ...item, parent: item.parent?.id }; }, defaultItem: { name: "", shortName: "", parent: null, colourFg: "", colourBg: "", }, fields: [ { text: this.$t("cursus.subject.fields.name"), value: "name", }, { text: this.$t("cursus.subject.fields.short_name"), value: "shortName", }, { text: this.$t("cursus.subject.fields.parent"), value: "parent", }, { text: this.$t("cursus.subject.fields.colour_fg"), value: "colourFg", }, { text: this.$t("cursus.subject.fields.colour_bg"), value: "colourBg", }, { text: this.$t("cursus.subject.fields.teachers"), value: "teachers", }, ], }, rules: { required: [(value) => !!value || this.$t("forms.errors.required")], subject: [ (subject) => !!subject || this.$t("cursus.errors.subject_required"), ], }, }; }, apollo: { persons: { query: gqlTeachers, }, internalRooms: { query: rooms, update: (data) => data.items, }, internalBreakSlots: { query: breakSlots, update: (data) => data.items, }, }, methods: { formatTimeGridItem(item) { if (item.group === null) { return this.$t( "lesrooster.validity_range.time_grid.repr.generic", item.validityRange, ); } return this.$t("lesrooster.validity_range.time_grid.repr.default", [ item.validityRange.name, item.group.name, ]); }, formatBreakSlotItem(item) { return this.$t("lesrooster.break.repr.weekday_short", { weekday: this.$t("weekdays." + item.weekday), timeStart: item.timeStart, timeEnd: item.timeEnd, }); }, getRRule(timeGrid) { const rule = new RRule({ freq: RRule.WEEKLY, // TODO: Make this configurable dtstart: new Date(timeGrid.validityRange.dateStart), // FIXME: check if this is correct with timezones etc. until: new Date(timeGrid.validityRange.dateEnd), // FIXME: check if this is correct with timezones etc. }); return rule; }, getCreateData(item) { return { breakSlot: item.breakSlot.id, rooms: item.rooms.map((r) => r.id), teachers: item.teachers.map((t) => t.id), subject: item.subject?.id, recurrence: this.getRRule(item.breakSlot.timeGrid).toString(), }; }, getPatchData(item) { item = { id: item.id, breakSlot: item.breakSlot?.id, rooms: item.rooms?.map((r) => r.id), teachers: item.teachers?.map((t) => t.id), subject: item.subject?.id, recurrence: this.getRRule(item.breakSlot.timeGrid).toString(), }; return Object.fromEntries( Object.entries(item).filter(([key, value]) => value !== undefined), ); }, }, }; </script> <style scoped></style>