From 97db35edab6863d02b6591064b958d37670c049f Mon Sep 17 00:00:00 2001 From: Elmar Kresse Date: Sun, 19 May 2024 13:24:00 +0200 Subject: [PATCH 01/17] feat:#4 added packages --- frontend/package-lock.json | 16 ++++++++++++++++ frontend/package.json | 2 ++ 2 files changed, 18 insertions(+) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 26d126a..1ec4da8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@fullcalendar/core": "^6.1.11", "@fullcalendar/daygrid": "^6.1.11", + "@fullcalendar/icalendar": "^6.1.11", "@fullcalendar/interaction": "^6.1.11", "@fullcalendar/timegrid": "^6.1.11", "@fullcalendar/vue3": "^6.1.11", @@ -17,6 +18,7 @@ "@tanstack/vue-query-devtools": "^5.28.10", "@vueuse/core": "^10.9.0", "country-flag-emoji-polyfill": "^0.1.8", + "ical.js": "^1.5.0", "pinia": "^2.1.7", "primeflex": "^3.3.1", "primeicons": "^6.0.1", @@ -2331,6 +2333,15 @@ "@fullcalendar/core": "~6.1.11" } }, + "node_modules/@fullcalendar/icalendar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/@fullcalendar/icalendar/-/icalendar-6.1.11.tgz", + "integrity": "sha512-a1kFIUs/G1ic9kkblL08n8Vwqw+jkBExhgFjbARVQrvyTwx0/SDmRtt0crqlkUYUOnu5nofj3xXPNupdxgPSwg==", + "peerDependencies": { + "@fullcalendar/core": "~6.1.11", + "ical.js": "^1.4.0" + } + }, "node_modules/@fullcalendar/interaction": { "version": "6.1.11", "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.11.tgz", @@ -5691,6 +5702,11 @@ "node": ">=16.17.0" } }, + "node_modules/ical.js": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/ical.js/-/ical.js-1.5.0.tgz", + "integrity": "sha512-7ZxMkogUkkaCx810yp0ZGKvq1ZpRgJeornPttpoxe6nYZ3NLesZe1wWMXDdwTkj/b5NtXT+Y16Aakph/ao98ZQ==" + }, "node_modules/idb": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index c001738..27f6925 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,6 +15,7 @@ "dependencies": { "@fullcalendar/core": "^6.1.11", "@fullcalendar/daygrid": "^6.1.11", + "@fullcalendar/icalendar": "^6.1.11", "@fullcalendar/interaction": "^6.1.11", "@fullcalendar/timegrid": "^6.1.11", "@fullcalendar/vue3": "^6.1.11", @@ -22,6 +23,7 @@ "@tanstack/vue-query-devtools": "^5.28.10", "@vueuse/core": "^10.9.0", "country-flag-emoji-polyfill": "^0.1.8", + "ical.js": "^1.5.0", "pinia": "^2.1.7", "primeflex": "^3.3.1", "primeicons": "^6.0.1", From 9a9b405910017cce2674ef7bf8ca71bd412edab2 Mon Sep 17 00:00:00 2001 From: Elmar Kresse Date: Sun, 19 May 2024 13:24:21 +0200 Subject: [PATCH 02/17] feat:#4 view, calendar import, component --- frontend/src/components/CalendarViewer.vue | 115 +++++++++++++++++++++ frontend/src/components/MenuBar.vue | 5 + frontend/src/helpers/ical.ts | 0 frontend/src/i18n/translations/de.json | 1 + frontend/src/i18n/translations/en.json | 1 + frontend/src/router/index.ts | 6 ++ frontend/src/view/UserCalendar.vue | 12 +++ 7 files changed, 140 insertions(+) create mode 100644 frontend/src/components/CalendarViewer.vue create mode 100644 frontend/src/helpers/ical.ts create mode 100644 frontend/src/view/UserCalendar.vue diff --git a/frontend/src/components/CalendarViewer.vue b/frontend/src/components/CalendarViewer.vue new file mode 100644 index 0000000..c54b41d --- /dev/null +++ b/frontend/src/components/CalendarViewer.vue @@ -0,0 +1,115 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/components/MenuBar.vue b/frontend/src/components/MenuBar.vue index 9b44a7d..0de1280 100644 --- a/frontend/src/components/MenuBar.vue +++ b/frontend/src/components/MenuBar.vue @@ -53,6 +53,11 @@ const items = computed(() => [ }, ], }, + { + label: t("userCalendar"), + icon: "pi pi-fw pi-calendar", + route: "/user/calendar", + }, { label: t("faq"), icon: "pi pi-fw pi-book", diff --git a/frontend/src/helpers/ical.ts b/frontend/src/helpers/ical.ts new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/i18n/translations/de.json b/frontend/src/i18n/translations/de.json index 2f2ac46..567f440 100644 --- a/frontend/src/i18n/translations/de.json +++ b/frontend/src/i18n/translations/de.json @@ -2,6 +2,7 @@ "languageCode": "de", "createCalendar": "Kalender erstellen", "editCalendar": "Kalender bearbeiten", + "userCalendar": "Dein Kalender", "rooms": "Räume", "faq": "FAQ", "imprint": "Impressum", diff --git a/frontend/src/i18n/translations/en.json b/frontend/src/i18n/translations/en.json index 590a673..b1edb9f 100644 --- a/frontend/src/i18n/translations/en.json +++ b/frontend/src/i18n/translations/en.json @@ -2,6 +2,7 @@ "languageCode": "en", "createCalendar": "create calendar", "editCalendar": "edit calendar", + "userCalendar": "user calendar", "rooms": "rooms", "faq": "faq", "imprint": "imprint", diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 1de0165..a50391a 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -27,6 +27,7 @@ const EditAdditionalModules = () => const EditModules = () => import("../view/editCalendar/EditModules.vue"); const CourseSelection = () => import("../view/CourseSelection.vue"); const FreeRooms = () => import("../view/FreeRooms.vue"); +const CalenderViewer = () => import("../view/UserCalendar.vue"); import i18n from "../i18n"; @@ -48,6 +49,11 @@ const router = createRouter({ name: "free-rooms", component: FreeRooms, }, + { + path: "/user/calendar", + name: "user-calendar", + component: CalenderViewer, + }, { path: "/faq", name: "faq", diff --git a/frontend/src/view/UserCalendar.vue b/frontend/src/view/UserCalendar.vue new file mode 100644 index 0000000..ce1cffa --- /dev/null +++ b/frontend/src/view/UserCalendar.vue @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file From 1c22c2c227e60c39b083ad1bb203f23a83888c6c Mon Sep 17 00:00:00 2001 From: Elmar Kresse Date: Sun, 19 May 2024 21:29:39 +0200 Subject: [PATCH 03/17] feat:#4 updated cache and workbox --- frontend/index.html | 3 ++- frontend/src/vite-env.d.ts | 2 ++ frontend/vite.config.ts | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index b4cdc0c..354a812 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -11,7 +11,8 @@ - + . /// + +declare module 'ical.js'; \ No newline at end of file diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 0e9baec..85f1c19 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -67,7 +67,21 @@ export default defineConfig({ registerType: 'autoUpdate', workbox: { globPatterns: ['**/*.{js,css,html,ico,png,svg,json,vue,txt,woff2}'], - cleanupOutdatedCaches: true + cleanupOutdatedCaches: true, + runtimeCaching: [ + { + urlPattern: /^https?.*/, + handler: 'NetworkFirst', + options: { + cacheName: 'https-calls', + expiration: { + maxEntries: 150, + maxAgeSeconds: 30 * 12 * 60 * 60, // 1 month + }, + networkTimeoutSeconds: 10, // fall back to cache if api does not response within 10 seconds + }, + }, + ], }, devOptions: { enabled: true, From 6e9dfdba31d29b12c00c70cb12a87ed0db14da33 Mon Sep 17 00:00:00 2001 From: Elmar Kresse Date: Sun, 19 May 2024 21:29:59 +0200 Subject: [PATCH 04/17] feat:#4 updated router and views --- frontend/package-lock.json | 34 ++++++++++++++++++++++ frontend/package.json | 1 + frontend/src/api/loadICal.ts | 23 +++++++++++++++ frontend/src/components/CalendarViewer.vue | 28 +++++++++++++----- frontend/src/components/MenuBar.vue | 33 ++++++++++++--------- frontend/src/helpers/ical.ts | 24 +++++++++++++++ frontend/src/i18n/translations/de.json | 1 + frontend/src/i18n/translations/en.json | 1 + frontend/src/router/index.ts | 13 ++++++--- frontend/src/view/UserCalendar.vue | 17 ++++++++++- 10 files changed, 149 insertions(+), 26 deletions(-) create mode 100644 frontend/src/api/loadICal.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1ec4da8..85eb207 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,6 +16,7 @@ "@fullcalendar/vue3": "^6.1.11", "@tanstack/vue-query": "^5.28.9", "@tanstack/vue-query-devtools": "^5.28.10", + "@types/ical": "^0.8.3", "@vueuse/core": "^10.9.0", "country-flag-emoji-polyfill": "^0.1.8", "ical.js": "^1.5.0", @@ -3081,6 +3082,14 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/ical": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@types/ical/-/ical-0.8.3.tgz", + "integrity": "sha512-qPejGORaXOstmqyKzp0Qw9nXDPiWiahiJJcx4zMB0zJVg0rLfJ6bDip/naqagEqYTjKl/LI91399hR8zFwRJ5A==", + "dependencies": { + "rrule": "2.6.4" + } + }, "node_modules/@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -6361,6 +6370,15 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz", + "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==", + "optional": true, + "engines": { + "node": "*" + } + }, "node_modules/magic-string": { "version": "0.30.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", @@ -7200,6 +7218,17 @@ "fsevents": "~2.3.2" } }, + "node_modules/rrule": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.6.4.tgz", + "integrity": "sha512-sLdnh4lmjUqq8liFiOUXD5kWp/FcnbDLPwq5YAc/RrN6120XOPb86Ae5zxF7ttBVq8O3LxjjORMEit1baluahA==", + "dependencies": { + "tslib": "^1.10.0" + }, + "optionalDependencies": { + "luxon": "^1.21.3" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -7881,6 +7910,11 @@ "typescript": ">=4.2.0" } }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 27f6925..5dacd9c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,6 +21,7 @@ "@fullcalendar/vue3": "^6.1.11", "@tanstack/vue-query": "^5.28.9", "@tanstack/vue-query-devtools": "^5.28.10", + "@types/ical": "^0.8.3", "@vueuse/core": "^10.9.0", "country-flag-emoji-polyfill": "^0.1.8", "ical.js": "^1.5.0", diff --git a/frontend/src/api/loadICal.ts b/frontend/src/api/loadICal.ts new file mode 100644 index 0000000..e835dd9 --- /dev/null +++ b/frontend/src/api/loadICal.ts @@ -0,0 +1,23 @@ +//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format. +//Copyright (C) 2024 HTWKalender support@htwkalender.de + +//This program is free software: you can redistribute it and/or modify +//it under the terms of the GNU Affero General Public License as published by +//the Free Software Foundation, either version 3 of the License, or +//(at your option) any later version. + +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU Affero General Public License for more details. + +//You should have received a copy of the GNU Affero General Public License +//along with this program. If not, see . + +export async function fetchICalendarEvents() { + const response = await fetch("https://cal.htwk-leipzig.de/api/feed?token=rk47mvraeb43t3g"); + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.text(); +} \ No newline at end of file diff --git a/frontend/src/components/CalendarViewer.vue b/frontend/src/components/CalendarViewer.vue index c54b41d..8d36be1 100644 --- a/frontend/src/components/CalendarViewer.vue +++ b/frontend/src/components/CalendarViewer.vue @@ -11,12 +11,30 @@ import iCalenderPlugin from "@fullcalendar/icalendar"; import router from "@/router"; import { formatYearMonthDay } from "@/helpers/dates.ts"; import { useI18n } from "vue-i18n"; +import { useQuery } from "@tanstack/vue-query"; +import tokenStore from "@/store/tokenStore.ts"; +import { parseICalData } from "@/helpers/ical.ts"; +import { fetchICalendarEvents } from "@/api/loadICal.ts"; const { t } = useI18n({ useScope: "global" }); const mobilePage = inject("mobilePage") as Ref; const date: Ref = ref(new Date()); -const feedUrl: Ref = ref("https://cal.htwk-leipzig.de/api/feed?token=rk47mvraeb43t3g"); + +tokenStore().setToken("3rz8vb3974tr2b") + + +const { data: calendar } = useQuery({ + queryKey: ["userCalendar", tokenStore().token], + queryFn: () => + fetchICalendarEvents(), + select: (data) => { + return data; + }, + networkMode: "offlineFirst", + enabled: () => tokenStore().token !== "", + staleTime: 5000000, // 500 seconds +}); const fullCalendar = ref>(); @@ -88,13 +106,7 @@ const calendarOptions: ComputedRef = computed(() => ({ }, }); }, - events: { - url: feedUrl.value, - format: "ics", - failure: function () { - alert("There was an error while fetching the calendar events!"); - }, - }, + events: parseICalData(calendar.value), })); watch(mobilePage, () => { diff --git a/frontend/src/components/MenuBar.vue b/frontend/src/components/MenuBar.vue index 0de1280..995d208 100644 --- a/frontend/src/components/MenuBar.vue +++ b/frontend/src/components/MenuBar.vue @@ -27,14 +27,26 @@ const isDark = ref(true); const items = computed(() => [ { - label: t("createCalendar"), - icon: "pi pi-fw pi-plus", - route: "/", - }, - { - label: t("editCalendar"), - icon: "pi pi-fw pi-pencil", - route: "/edit", + label: t("calendar"), + icon: "pi pi-fw pi-angle-down", + info: "calendar", + items: [ + { + label: t("createCalendar"), + icon: "pi pi-fw pi-plus", + route: "/calendar/create", + }, + { + label: t("editCalendar"), + icon: "pi pi-fw pi-pencil", + route: "/calendar/edit", + }, + { + label: t("userCalendar"), + icon: "pi pi-fw pi-calendar", + route: "/calendar/view", + }, + ], }, { label: t("rooms"), @@ -53,11 +65,6 @@ const items = computed(() => [ }, ], }, - { - label: t("userCalendar"), - icon: "pi pi-fw pi-calendar", - route: "/user/calendar", - }, { label: t("faq"), icon: "pi pi-fw pi-book", diff --git a/frontend/src/helpers/ical.ts b/frontend/src/helpers/ical.ts index e69de29..7af483a 100644 --- a/frontend/src/helpers/ical.ts +++ b/frontend/src/helpers/ical.ts @@ -0,0 +1,24 @@ +import ICAL from 'ical.js'; +import { CalendarComponent } from 'ical'; + +export function parseICalData(icalData: string | undefined) { + if (icalData === undefined || !icalData) { + return []; + } + + const jCalData = ICAL.parse(icalData); + const comp = new ICAL.Component(jCalData); + const vEvents = comp.getAllSubcomponents('vevent'); + + return vEvents.map((vevent: CalendarComponent) => { + const event = new ICAL.Event(vevent); + + return { + title: event.summary, + start: event.startDate.toJSDate(), + end: event.endDate.toJSDate(), + allDay: event.startDate.isDate, + // Include other properties as needed + }; + }); +} \ No newline at end of file diff --git a/frontend/src/i18n/translations/de.json b/frontend/src/i18n/translations/de.json index 567f440..f6862ad 100644 --- a/frontend/src/i18n/translations/de.json +++ b/frontend/src/i18n/translations/de.json @@ -3,6 +3,7 @@ "createCalendar": "Kalender erstellen", "editCalendar": "Kalender bearbeiten", "userCalendar": "Dein Kalender", + "calendar": "Kalender", "rooms": "Räume", "faq": "FAQ", "imprint": "Impressum", diff --git a/frontend/src/i18n/translations/en.json b/frontend/src/i18n/translations/en.json index b1edb9f..e843cef 100644 --- a/frontend/src/i18n/translations/en.json +++ b/frontend/src/i18n/translations/en.json @@ -3,6 +3,7 @@ "createCalendar": "create calendar", "editCalendar": "edit calendar", "userCalendar": "user calendar", + "calendar": "calendar", "rooms": "rooms", "faq": "faq", "imprint": "imprint", diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index a50391a..8e107bd 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -36,7 +36,12 @@ const router = createRouter({ routes: [ { path: "/", - name: "course-selection", + name: "home", + component: CourseSelection, + }, + { + path: "/calendar/create", + name: "calendar-create", component: CourseSelection, }, { @@ -50,8 +55,8 @@ const router = createRouter({ component: FreeRooms, }, { - path: "/user/calendar", - name: "user-calendar", + path: "/calendar/view", + name: "calendar-view", component: CalenderViewer, }, { @@ -80,7 +85,7 @@ const router = createRouter({ component: CalendarLink, }, { - path: "/edit", + path: "/calendar/edit", name: "edit", component: EditCalendarView, }, diff --git a/frontend/src/view/UserCalendar.vue b/frontend/src/view/UserCalendar.vue index ce1cffa..e7f5e7a 100644 --- a/frontend/src/view/UserCalendar.vue +++ b/frontend/src/view/UserCalendar.vue @@ -1,10 +1,25 @@