mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender-pwa.git
synced 2025-07-16 09:38:51 +02:00
feat:#22 refactor to cache room schedule and webworker config
This commit is contained in:
@ -16,7 +16,6 @@
|
||||
|
||||
import { BSON } from "bson";
|
||||
import { RoomOccupancyList } from "@/model/roomOccupancyList.ts";
|
||||
import { addMonths } from "date-fns";
|
||||
import { formatYearMonthDay } from "@/helpers/dates";
|
||||
|
||||
const END_OF_SUMMER_SEMESTER = "0930";
|
||||
@ -59,32 +58,19 @@ export function getSemesterStart(date: Date): Date {
|
||||
|
||||
/**
|
||||
* Fetches the room occupancy for a given date range.
|
||||
* @param from_date the start date of the date range
|
||||
* @param to_date the end date of the date range
|
||||
* @returns RoomOccupancyList - the room occupancy list
|
||||
* @returns RoomOccupancyList - the room occupancy list containing all rooms
|
||||
*/
|
||||
|
||||
export async function fetchRoomOccupancy(
|
||||
from_date?: string,
|
||||
to_date?: string,
|
||||
): Promise<RoomOccupancyList> {
|
||||
if (from_date == undefined) {
|
||||
const new_from_date = getSemesterStart(new Date());
|
||||
from_date = new_from_date.toISOString();
|
||||
}
|
||||
if (to_date == undefined) {
|
||||
const new_to_date = getSemesterStart(addMonths(new Date(), 6));
|
||||
to_date = new_to_date.toISOString();
|
||||
}
|
||||
|
||||
export async function fetchRoomOccupancy(): Promise<RoomOccupancyList> {
|
||||
let roomOccupancyList: RoomOccupancyList = new RoomOccupancyList(
|
||||
new Date(),
|
||||
new Date(2000, 0, 1),
|
||||
0,
|
||||
0,
|
||||
[],
|
||||
);
|
||||
|
||||
await fetch("/api/schedule/rooms?from=" + from_date + "&to=" + to_date)
|
||||
await fetch("/api/schedule/rooms")
|
||||
.then((response) => {
|
||||
return response.arrayBuffer();
|
||||
})
|
||||
|
@ -27,8 +27,6 @@ import {useI18n} from "vue-i18n";
|
||||
import allLocales from "@fullcalendar/core/locales-all";
|
||||
import router from "@/router";
|
||||
import {formatYearMonthDay} from "@/helpers/dates";
|
||||
import {useQuery} from "@tanstack/vue-query";
|
||||
import {fetchRoomOccupancy} from "@/api/fetchRoomOccupancy";
|
||||
import {isValid} from "date-fns";
|
||||
import {RoomOccupancyList} from "@/model/roomOccupancyList";
|
||||
|
||||
@ -39,6 +37,10 @@ const props = defineProps({
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
occupancy: {
|
||||
type: RoomOccupancyList,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const date: Ref<Date> = ref(new Date());
|
||||
@ -56,6 +58,7 @@ function setDateFromQuery() {
|
||||
const day = queryDate.substring(6, 8);
|
||||
date.value = new Date(`${year}-${month}-${day}`);
|
||||
if (!isValid(date.value)) {
|
||||
console.error("Invalid date in URL, using current date instead.");
|
||||
date.value = new Date();
|
||||
}
|
||||
}
|
||||
@ -77,6 +80,9 @@ const selectedRoom = computed(() => props.room);
|
||||
* @returns Anonymized occupancy events
|
||||
*/
|
||||
function transformData(data: RoomOccupancyList) {
|
||||
if (!data || !selectedRoom.value || !currentDateFrom.value || !currentDateTo.value) {
|
||||
return [];
|
||||
}
|
||||
return data
|
||||
.decodeOccupancy(
|
||||
selectedRoom.value,
|
||||
@ -89,15 +95,9 @@ function transformData(data: RoomOccupancyList) {
|
||||
}));
|
||||
}
|
||||
|
||||
const { data: occupancy } = useQuery({
|
||||
queryKey: ["roomOccupancy"], //, selectedRoom, currentDateFrom, currentDateTo],
|
||||
queryFn: () => fetchRoomOccupancy(),
|
||||
staleTime: 12 * 3600000, // 12 hours
|
||||
});
|
||||
|
||||
const occupations = computed(() => {
|
||||
if (!occupancy.value) return;
|
||||
return transformData(occupancy.value);
|
||||
if (!props.occupancy) return;
|
||||
return transformData(props.occupancy);
|
||||
});
|
||||
|
||||
watch(occupations, () => fullCalendar.value?.getApi().refetchEvents());
|
||||
|
@ -34,6 +34,56 @@ function setup() {
|
||||
de,
|
||||
ja,
|
||||
},
|
||||
datetimeFormats: {
|
||||
en: {
|
||||
short: {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
},
|
||||
long: {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
weekday: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: true,
|
||||
},
|
||||
},
|
||||
de: {
|
||||
short: {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
},
|
||||
long: {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
weekday: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: false,
|
||||
},
|
||||
},
|
||||
ja: {
|
||||
short: {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
},
|
||||
long: {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
weekday: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return _i18n;
|
||||
}
|
||||
|
@ -33,7 +33,9 @@
|
||||
"noRoomsAvailable": "Keine Räume verfügbar",
|
||||
"available": "verfügbar",
|
||||
"occupied": "belegt",
|
||||
"stub": "bitte online prüfen"
|
||||
"stub": "bitte online prüfen",
|
||||
"lastUpdate": "Zeitpunkt der letzten Aktualisierung",
|
||||
"noData": "Es konnten keine Daten geladen werden."
|
||||
},
|
||||
"freeRooms": {
|
||||
"freeRooms": "Freie Räume",
|
||||
|
@ -33,7 +33,9 @@
|
||||
"noRoomsAvailable": "no rooms listed",
|
||||
"available": "available",
|
||||
"occupied": "occupied",
|
||||
"stub": "please check online"
|
||||
"stub": "please check online",
|
||||
"lastUpdate": "time of last update",
|
||||
"noData": "could not load data"
|
||||
},
|
||||
"freeRooms": {
|
||||
"freeRooms": "free rooms",
|
||||
|
@ -33,7 +33,9 @@
|
||||
"noRoomsAvailable": "利用可能な部屋がありません",
|
||||
"available": "利用可能",
|
||||
"occupied": "占有中",
|
||||
"stub": "オンラインでご確認ください。"
|
||||
"stub": "オンラインでご確認ください。",
|
||||
"lastUpdate": "最終更新時刻",
|
||||
"noData": "データをロードできませんでした。"
|
||||
},
|
||||
"freeRooms": {
|
||||
"freeRooms": "空いている部屋",
|
||||
|
@ -65,6 +65,7 @@ class RoomOccupancy {
|
||||
export class RoomOccupancyList {
|
||||
constructor(
|
||||
public start: Date,
|
||||
public updated: Date,
|
||||
public granularity: number,
|
||||
public blocks: number,
|
||||
public rooms: RoomOccupancy[],
|
||||
@ -312,6 +313,7 @@ export class RoomOccupancyList {
|
||||
public static fromJSON(json: Document): RoomOccupancyList {
|
||||
return new RoomOccupancyList(
|
||||
json.start,
|
||||
json.updated,
|
||||
json.granularity,
|
||||
json.blocks,
|
||||
json.rooms.map(
|
||||
|
@ -18,16 +18,29 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Ref, computed, ref, watch } from "vue";
|
||||
import { fetchRoom } from "../api/fetchRoom.ts";
|
||||
import DynamicPage from "./DynamicPage.vue";
|
||||
import RoomOccupationOffline from "../components/RoomOccupationOffline.vue";
|
||||
import { computedAsync } from "@vueuse/core";
|
||||
import router from "@/router";
|
||||
import { useQuery, useQueryClient } from "@tanstack/vue-query";
|
||||
import { fetchRoomOccupancy } from "@/api/fetchRoomOccupancy.ts";
|
||||
|
||||
type Room = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data: occupancy, dataUpdatedAt: updateDate } = useQuery({
|
||||
queryKey: ["roomOccupancy"],
|
||||
queryFn: () => fetchRoomOccupancy(),
|
||||
staleTime: 12 * 3600000, // 12 hours
|
||||
});
|
||||
|
||||
// Manually refetch the room occupancy data
|
||||
function refetchRoomOccupancy() {
|
||||
queryClient.invalidateQueries({ queryKey: ["roomOccupancy"] });
|
||||
}
|
||||
|
||||
const selectedRoom: Ref<Room> = ref({ name: "" });
|
||||
|
||||
// Watch for changes in URL parameter
|
||||
@ -38,21 +51,15 @@ router.afterEach(async (to) => {
|
||||
}
|
||||
});
|
||||
|
||||
const rooms = computedAsync<Set<string>>(async () => {
|
||||
const rooms = computed<Set<string>>(() => {
|
||||
let rooms: Set<string> = new Set();
|
||||
return await fetchRoom()
|
||||
.then((data) => {
|
||||
rooms = new Set(data);
|
||||
return rooms;
|
||||
})
|
||||
.finally(() => {
|
||||
const room = router.currentRoute.value.query.room;
|
||||
if (room && typeof room === "string") {
|
||||
// check if room is available in roomsList
|
||||
setRoomFromList(room, rooms);
|
||||
}
|
||||
});
|
||||
}, new Set());
|
||||
|
||||
occupancy.value?.rooms.forEach((room) => {
|
||||
rooms.add(room.name);
|
||||
});
|
||||
|
||||
return rooms;
|
||||
});
|
||||
|
||||
const roomsList = computed(() => {
|
||||
return Array.from(rooms.value).map((room) => {
|
||||
@ -102,7 +109,17 @@ watch(selectedRoom, (newRoom: Room) => {
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<RoomOccupationOffline :room="selectedRoom.name" />
|
||||
</template>
|
||||
<RoomOccupationOffline v-if="occupancy" :room="selectedRoom.name" :occupancy="occupancy"/>
|
||||
<div v-else>
|
||||
<p>{{ $t('roomFinderPage.noData') }}</p>
|
||||
</div>
|
||||
|
||||
<!--last update date-->
|
||||
<div class="flex align-items-baseline justify-content-end text-right text-xs text-gray-500">
|
||||
<span v-if="occupancy">test: {{ $d(occupancy.updated, 'long') }}</span>
|
||||
<span>{{ $t("roomFinderPage.lastUpdate") }}: {{ $d(new Date(updateDate), 'long') }}</span>
|
||||
<Button size="small" @click="refetchRoomOccupancy" icon="pi pi-refresh" class="p-button-text p-button-sm" />
|
||||
</div>
|
||||
</template>
|
||||
</DynamicPage>
|
||||
</template>
|
||||
|
@ -82,7 +82,7 @@ export default defineConfig({
|
||||
},
|
||||
registerType: "autoUpdate",
|
||||
workbox: {
|
||||
globPatterns: ["**/*.{js,css,html,ico,png,svg,json,vue,txt,woff2}"],
|
||||
globPatterns: ["**/*.{js,css,html,ico,png,svg,json,vue,txt,woff2}", "/api/schedule/rooms"],
|
||||
cleanupOutdatedCaches: true,
|
||||
runtimeCaching: [
|
||||
{
|
||||
@ -96,6 +96,17 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
urlPattern: ("/api/schedule/rooms"),
|
||||
method: "GET",
|
||||
handler: "StaleWhileRevalidate",
|
||||
options: {
|
||||
cacheName: "room-schedule-cache",
|
||||
expiration: {
|
||||
maxAgeSeconds: 12 * 60 * 60, // 12 hours
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
urlPattern: /^https?.*/,
|
||||
handler: "NetworkFirst",
|
||||
|
Reference in New Issue
Block a user