mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender-pwa.git
synced 2025-07-24 13:38:50 +02:00
feat:#4 updated router and views
This commit is contained in:
34
frontend/package-lock.json
generated
34
frontend/package-lock.json
generated
@@ -16,6 +16,7 @@
|
|||||||
"@fullcalendar/vue3": "^6.1.11",
|
"@fullcalendar/vue3": "^6.1.11",
|
||||||
"@tanstack/vue-query": "^5.28.9",
|
"@tanstack/vue-query": "^5.28.9",
|
||||||
"@tanstack/vue-query-devtools": "^5.28.10",
|
"@tanstack/vue-query-devtools": "^5.28.10",
|
||||||
|
"@types/ical": "^0.8.3",
|
||||||
"@vueuse/core": "^10.9.0",
|
"@vueuse/core": "^10.9.0",
|
||||||
"country-flag-emoji-polyfill": "^0.1.8",
|
"country-flag-emoji-polyfill": "^0.1.8",
|
||||||
"ical.js": "^1.5.0",
|
"ical.js": "^1.5.0",
|
||||||
@@ -3081,6 +3082,14 @@
|
|||||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/@types/json-schema": {
|
||||||
"version": "7.0.12",
|
"version": "7.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
|
||||||
@@ -6361,6 +6370,15 @@
|
|||||||
"node": ">=10"
|
"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": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.30.5",
|
"version": "0.30.5",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
|
||||||
@@ -7200,6 +7218,17 @@
|
|||||||
"fsevents": "~2.3.2"
|
"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": {
|
"node_modules/run-parallel": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||||
@@ -7881,6 +7910,11 @@
|
|||||||
"typescript": ">=4.2.0"
|
"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": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
"@fullcalendar/vue3": "^6.1.11",
|
"@fullcalendar/vue3": "^6.1.11",
|
||||||
"@tanstack/vue-query": "^5.28.9",
|
"@tanstack/vue-query": "^5.28.9",
|
||||||
"@tanstack/vue-query-devtools": "^5.28.10",
|
"@tanstack/vue-query-devtools": "^5.28.10",
|
||||||
|
"@types/ical": "^0.8.3",
|
||||||
"@vueuse/core": "^10.9.0",
|
"@vueuse/core": "^10.9.0",
|
||||||
"country-flag-emoji-polyfill": "^0.1.8",
|
"country-flag-emoji-polyfill": "^0.1.8",
|
||||||
"ical.js": "^1.5.0",
|
"ical.js": "^1.5.0",
|
||||||
|
23
frontend/src/api/loadICal.ts
Normal file
23
frontend/src/api/loadICal.ts
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
@@ -11,12 +11,30 @@ import iCalenderPlugin from "@fullcalendar/icalendar";
|
|||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { formatYearMonthDay } from "@/helpers/dates.ts";
|
import { formatYearMonthDay } from "@/helpers/dates.ts";
|
||||||
import { useI18n } from "vue-i18n";
|
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 { t } = useI18n({ useScope: "global" });
|
||||||
|
|
||||||
const mobilePage = inject("mobilePage") as Ref<boolean>;
|
const mobilePage = inject("mobilePage") as Ref<boolean>;
|
||||||
const date: Ref<Date> = ref(new Date());
|
const date: Ref<Date> = ref(new Date());
|
||||||
const feedUrl: Ref<string> = 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<InstanceType<typeof FullCalendar>>();
|
const fullCalendar = ref<InstanceType<typeof FullCalendar>>();
|
||||||
|
|
||||||
@@ -88,13 +106,7 @@ const calendarOptions: ComputedRef<CalendarOptions> = computed(() => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
events: {
|
events: parseICalData(calendar.value),
|
||||||
url: feedUrl.value,
|
|
||||||
format: "ics",
|
|
||||||
failure: function () {
|
|
||||||
alert("There was an error while fetching the calendar events!");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
watch(mobilePage, () => {
|
watch(mobilePage, () => {
|
||||||
|
@@ -27,14 +27,26 @@ const isDark = ref(true);
|
|||||||
|
|
||||||
const items = computed(() => [
|
const items = computed(() => [
|
||||||
{
|
{
|
||||||
label: t("createCalendar"),
|
label: t("calendar"),
|
||||||
icon: "pi pi-fw pi-plus",
|
icon: "pi pi-fw pi-angle-down",
|
||||||
route: "/",
|
info: "calendar",
|
||||||
},
|
items: [
|
||||||
{
|
{
|
||||||
label: t("editCalendar"),
|
label: t("createCalendar"),
|
||||||
icon: "pi pi-fw pi-pencil",
|
icon: "pi pi-fw pi-plus",
|
||||||
route: "/edit",
|
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"),
|
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"),
|
label: t("faq"),
|
||||||
icon: "pi pi-fw pi-book",
|
icon: "pi pi-fw pi-book",
|
||||||
|
@@ -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
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
@@ -3,6 +3,7 @@
|
|||||||
"createCalendar": "Kalender erstellen",
|
"createCalendar": "Kalender erstellen",
|
||||||
"editCalendar": "Kalender bearbeiten",
|
"editCalendar": "Kalender bearbeiten",
|
||||||
"userCalendar": "Dein Kalender",
|
"userCalendar": "Dein Kalender",
|
||||||
|
"calendar": "Kalender",
|
||||||
"rooms": "Räume",
|
"rooms": "Räume",
|
||||||
"faq": "FAQ",
|
"faq": "FAQ",
|
||||||
"imprint": "Impressum",
|
"imprint": "Impressum",
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
"createCalendar": "create calendar",
|
"createCalendar": "create calendar",
|
||||||
"editCalendar": "edit calendar",
|
"editCalendar": "edit calendar",
|
||||||
"userCalendar": "user calendar",
|
"userCalendar": "user calendar",
|
||||||
|
"calendar": "calendar",
|
||||||
"rooms": "rooms",
|
"rooms": "rooms",
|
||||||
"faq": "faq",
|
"faq": "faq",
|
||||||
"imprint": "imprint",
|
"imprint": "imprint",
|
||||||
|
@@ -36,7 +36,12 @@ const router = createRouter({
|
|||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
name: "course-selection",
|
name: "home",
|
||||||
|
component: CourseSelection,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/calendar/create",
|
||||||
|
name: "calendar-create",
|
||||||
component: CourseSelection,
|
component: CourseSelection,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -50,8 +55,8 @@ const router = createRouter({
|
|||||||
component: FreeRooms,
|
component: FreeRooms,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/user/calendar",
|
path: "/calendar/view",
|
||||||
name: "user-calendar",
|
name: "calendar-view",
|
||||||
component: CalenderViewer,
|
component: CalenderViewer,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -80,7 +85,7 @@ const router = createRouter({
|
|||||||
component: CalendarLink,
|
component: CalendarLink,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/edit",
|
path: "/calendar/edit",
|
||||||
name: "edit",
|
name: "edit",
|
||||||
component: EditCalendarView,
|
component: EditCalendarView,
|
||||||
},
|
},
|
||||||
|
@@ -1,10 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import CalendarViewer from "@/components/CalendarViewer.vue";
|
import CalendarViewer from "@/components/CalendarViewer.vue";
|
||||||
|
import DynamicPage from "@/view/DynamicPage.vue";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CalendarViewer />
|
<DynamicPage
|
||||||
|
:hide-content="false"
|
||||||
|
:headline="$t('freeRooms.freeRooms')"
|
||||||
|
:sub-title="$t('freeRooms.detail')"
|
||||||
|
>
|
||||||
|
<template #selection="{ flexSpecs }">
|
||||||
|
<CalendarViewer
|
||||||
|
:class="flexSpecs"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</DynamicPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
Reference in New Issue
Block a user