From 219507ffa3ed17cef35dc16995452c630efbb604 Mon Sep 17 00:00:00 2001 From: chfhtw Date: Fri, 1 Aug 2025 15:22:34 +0200 Subject: [PATCH] Shareable calendar components --- public/js/components/Calendar/LvPlan.js | 164 ++++++++++++++++++ public/js/components/Calendar/Widget.js | 106 +++++++++++ public/js/components/Cis/LvPlan/LvPlan.js | 129 ++------------ .../js/components/Cis/Mylv/RoomInformation.js | 126 +------------- .../js/components/DashboardWidget/LvPlan.js | 100 +---------- 5 files changed, 302 insertions(+), 323 deletions(-) create mode 100644 public/js/components/Calendar/LvPlan.js create mode 100644 public/js/components/Calendar/Widget.js diff --git a/public/js/components/Calendar/LvPlan.js b/public/js/components/Calendar/LvPlan.js new file mode 100644 index 000000000..c1cffb5be --- /dev/null +++ b/public/js/components/Calendar/LvPlan.js @@ -0,0 +1,164 @@ +import FhcCalendar from "./Base.js"; + +import ApiLvPlan from '../../api/factory/lvPlan.js'; + +import { useEventLoader } from '../../composables/EventLoader.js'; + +import ModeDay from './Mode/Day.js'; +import ModeWeek from './Mode/Week.js'; +import ModeMonth from './Mode/Month.js'; + +export default { + name: "CalendarLvPlan", + components: { + FhcCalendar + }, + inject: [ + "renderers" + ], + props: { + timezone: { + type: String, + required: true + }, + date: { + type: [Date, String, Number, luxon.DateTime], + default: luxon.DateTime.local() + }, + mode: { + type: String, + default: 'Week' + }, + getPromiseFunc: { + type: Function, + required: true + } + }, + emits: [ + "update:date", + "update:mode", + "update:range" + ], + data() { + return { + modes: { + day: Vue.markRaw(ModeDay), + week: Vue.markRaw(ModeWeek), + month: Vue.markRaw(ModeMonth) + }, + modeOptions: { + day: { + emptyMessage: Vue.computed(() => this.$p.t('lehre/noLvFound')), + emptyMessageDetails: Vue.computed(() => this.$p.t('lehre/noLvFound')) + }, + week: { + collapseEmptyDays: false + } + }, + teachingunits: null + }; + }, + computed: { + backgrounds() { + let now = luxon.DateTime.now().setZone(this.timezone); + + if (this.mode == 'Month') + return [ + { + class: 'background-past', + end: now.startOf('day') + } + ]; + + return [ + { + class: 'background-past', + end: now, + label: now.startOf('minute').toISOTime({ suppressSeconds: true, includeOffset: false }) + } + ]; + } + }, + methods: { + eventStyle(event) { + if (!event.farbe) + return undefined; + return '--event-bg:#' + event.farbe; + }, + updateRange(rangeInterval) { + this.rangeInterval = rangeInterval; + this.$emit('update:range', rangeInterval); + } + }, + setup(props, context) { + const rangeInterval = Vue.ref(null); + + const { events, lv } = useEventLoader(rangeInterval, props.getPromiseFunc); + + Vue.watch(lv, newValue => { + context.emit('update:lv', newValue); + }); + + return { + rangeInterval, + events, + lv + }; + }, + created() { + this.$api + .call(ApiLvPlan.getStunden()) + .then(res => { + return this.teachingunits = res.data.map(el => ({ + id: el.stunde, + start: el.beginn, + end: el.ende + })); + }); + }, + template: /* html */` + + + + ` +} diff --git a/public/js/components/Calendar/Widget.js b/public/js/components/Calendar/Widget.js new file mode 100644 index 000000000..f9d641d4e --- /dev/null +++ b/public/js/components/Calendar/Widget.js @@ -0,0 +1,106 @@ +import FhcCalendar from "./Base.js"; + +import { useEventLoader } from '../../composables/EventLoader.js'; + +import ModeList from '../Calendar/Mode/List.js'; + +export default { + name: "CalendarWidget", + components: { + FhcCalendar + }, + inject: [ + "renderers" + ], + props: { + timezone: { + type: String, + required: true + }, + getPromiseFunc: { + type: Function, + required: true + } + }, + data() { + return { + now: luxon.DateTime.now().setZone(this.timezone), + modes: { + list: Vue.markRaw(ModeList) + }, + modeOptions: { + list: { + length: 7 + } + } + }; + }, + methods: { + eventStyle(event) { + const styles = {}; + if (event.farbe) + styles['--event-bg'] = '#' + event.farbe; + else if (event.type == 'reservierung') + styles['--event-bg'] = '#ffffff'; + else + styles['--event-bg'] = '#cccccc'; + + const eventEnd = luxon.DateTime.fromISO(event.isoend, { zone: this.timezone }); + if (eventEnd < this.now) + styles['opacity'] = .5; + + return styles; + }, + updateRange(rangeInterval) { + this.rangeInterval = rangeInterval; + } + }, + setup(props) { + const rangeInterval = Vue.ref(null); + + const { events } = useEventLoader(rangeInterval, props.getPromiseFunc); + + return { + rangeInterval, + events + }; + }, + template: /* html */` + + + ` +} diff --git a/public/js/components/Cis/LvPlan/LvPlan.js b/public/js/components/Cis/LvPlan/LvPlan.js index 73c91734c..2fbac0e3a 100644 --- a/public/js/components/Cis/LvPlan/LvPlan.js +++ b/public/js/components/Cis/LvPlan/LvPlan.js @@ -1,14 +1,8 @@ -import FhcCalendar from "../../Calendar/Base.js"; +import FhcCalendar from "../../Calendar/LvPlan.js"; import ApiLvPlan from '../../../api/factory/lvPlan.js'; import ApiAuthinfo from '../../../api/factory/authinfo.js'; -import { useEventLoader } from '../../../composables/EventLoader.js'; - -import ModeDay from '../../Calendar/Mode/Day.js'; -import ModeWeek from '../../Calendar/Mode/Week.js'; -import ModeMonth from '../../Calendar/Mode/Month.js'; - export const DEFAULT_MODE_LVPLAN = 'Week' export default { @@ -16,9 +10,6 @@ export default { components: { FhcCalendar }, - inject: [ - "renderers" - ], props: { viewData: Object, // NOTE(chris): this is inherited from router-view propsViewData: Object @@ -26,25 +17,11 @@ export default { data() { const now = luxon.DateTime.now().setZone(this.viewData.timezone); return { - modes: { - day: Vue.markRaw(ModeDay), - week: Vue.markRaw(ModeWeek), - month: Vue.markRaw(ModeMonth) - }, - modeOptions: { - day: { - emptyMessage: Vue.computed(() => this.$p.t('lehre/noLvFound')), - emptyMessageDetails: Vue.computed(() => this.$p.t('lehre/noLvFound')) - }, - week: { - collapseEmptyDays: false - } - }, studiensemester_kurzbz: null, studiensemester_start: null, studiensemester_ende: null, uid: null, - teachingunits: null + lv: null }; }, computed:{ @@ -54,25 +31,6 @@ export default { currentMode() { return this.propsViewData?.mode || DEFAULT_MODE_LVPLAN; }, - backgrounds() { - let now = luxon.DateTime.now().setZone(this.viewData.timezone); - - if (this.currentMode == 'Month') - return [ - { - class: 'background-past', - end: now.startOf('day') - } - ]; - - return [ - { - class: 'background-past', - end: now, - label: now.startOf('minute').toISOTime({ suppressSeconds: true, includeOffset: false }) - } - ]; - }, downloadLinks() { if (!this.studiensemester_start || !this.studiensemester_ende || !this.uid) return false; @@ -101,11 +59,6 @@ export default { } }, methods: { - eventStyle(event) { - if (!event.farbe) - return undefined; - return '--event-bg:#' + event.farbe; - }, handleChangeDate(day, newMode) { return this.handleChangeMode(newMode, day); }, @@ -123,35 +76,22 @@ export default { }); }, updateRange(rangeInterval) { - this.rangeInterval = rangeInterval; this.$api .call(ApiLvPlan.studiensemesterDateInterval( - this.rangeInterval.end.startOf('week').toISODate() + rangeInterval.end.startOf('week').toISODate() )) .then(res => { this.studiensemester_kurzbz = res.data.studiensemester_kurzbz; this.studiensemester_start = res.data.start; this.studiensemester_ende = res.data.ende; }); - } - }, - setup(props) { - const $api = Vue.inject('$api'); - - const rangeInterval = Vue.ref(null); - - const { events, lv } = useEventLoader(rangeInterval, (start, end) => { + }, + getPromiseFunc(start, end) { return [ - $api.call(ApiLvPlan.LvPlanEvents(start.toISODate(), end.toISODate(), props.propsViewData.lv_id)), - $api.call(ApiLvPlan.getLvPlanReservierungen(start.toISODate(), end.toISODate())) + this.$api.call(ApiLvPlan.LvPlanEvents(start.toISODate(), end.toISODate(), this.propsViewData.lv_id)), + this.$api.call(ApiLvPlan.getLvPlanReservierungen(start.toISODate(), end.toISODate())) ]; - }); - - return { - rangeInterval, - events, - lv - }; + } }, created() { this.$api @@ -159,19 +99,10 @@ export default { .then(res => { this.uid = res.data.uid; }); - this.$api - .call(ApiLvPlan.getStunden()) - .then(res => { - return this.teachingunits = res.data.map(el => ({ - id: el.stunde, - start: el.beginn, - end: el.ende - })); - }); }, - template:/*html*/` -
-

+ template: /*html*/` +
+

{{ $p.t('lehre/stundenplan') }} {{ studiensemester_kurzbz }} @@ -183,45 +114,17 @@ export default {
- -