mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender.git
synced 2025-07-24 13:38:48 +02:00
199 lines
5.4 KiB
Vue
199 lines
5.4 KiB
Vue
<script lang="ts" setup>
|
|
import FullCalendar from "@fullcalendar/vue3";
|
|
import dayGridPlugin from "@fullcalendar/daygrid";
|
|
import interactionPlugin from "@fullcalendar/interaction";
|
|
import timeGridPlugin from "@fullcalendar/timegrid";
|
|
import { computed, ComputedRef, inject, ref, Ref, watch } from "vue";
|
|
import { CalendarOptions, DatesSetArg, EventInput } from "@fullcalendar/core";
|
|
import { fetchEventsByRoomAndDuration } from "../api/fetchRoom.ts";
|
|
import { useI18n } from "vue-i18n";
|
|
import allLocales from "@fullcalendar/core/locales-all";
|
|
import router from "@/router";
|
|
import { formatYearMonthDay } from "@/helpers/dates";
|
|
const { t } = useI18n({ useScope: "global" });
|
|
|
|
const props = defineProps({
|
|
room: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
type CalenderEvent = {
|
|
id: number;
|
|
start: string;
|
|
end: string;
|
|
showFree: boolean;
|
|
};
|
|
|
|
const date: Ref<Date> = ref(new Date());
|
|
|
|
// Watch for changes in URL parameter
|
|
router.afterEach(setDateFromQuery);
|
|
|
|
// Set the selected date from the URL
|
|
function setDateFromQuery() {
|
|
const queryDate = router.currentRoute.value.query.date;
|
|
if (typeof queryDate === "string") {
|
|
if (queryDate === formatYearMonthDay(date.value)) {
|
|
return;
|
|
}
|
|
// date is in format like YYYYMMDD
|
|
// TODO check if date is valid
|
|
const year = queryDate.substring(0, 4);
|
|
const month = queryDate.substring(4, 6);
|
|
const day = queryDate.substring(6, 8);
|
|
date.value = new Date(`${year}-${month}-${day}`);
|
|
}
|
|
}
|
|
|
|
setDateFromQuery();
|
|
|
|
const currentDateFrom: Ref<string> = ref("");
|
|
const currentDateTo: Ref<string> = ref("");
|
|
const occupations: Ref<CalenderEvent[]> = ref([]);
|
|
|
|
const mobilePage = inject("mobilePage") as Ref<boolean>;
|
|
|
|
const selectedRoom = computed(() => props.room);
|
|
|
|
watch(selectedRoom, () => {
|
|
getOccupation();
|
|
});
|
|
|
|
const fullCalendar = ref<InstanceType<typeof FullCalendar>>();
|
|
|
|
async function getOccupation() {
|
|
if (selectedRoom.value === "") {
|
|
return;
|
|
}
|
|
fetchEventsByRoomAndDuration(
|
|
selectedRoom.value,
|
|
currentDateFrom.value,
|
|
currentDateTo.value,
|
|
)
|
|
.then((events) => {
|
|
occupations.value = events?.map((event, index) => {
|
|
return {
|
|
id: index,
|
|
start: event.start.replace(/\s\+\d{4}\s\w+$/, "").replace(" ", "T"),
|
|
end: event.end.replace(/\s\+\d{4}\s\w+$/, "").replace(" ", "T"),
|
|
showFree: event.free,
|
|
};
|
|
});
|
|
|
|
const calendar = fullCalendar.value?.getApi();
|
|
calendar?.refetchEvents();
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
});
|
|
}
|
|
|
|
const calendarOptions: ComputedRef<CalendarOptions> = computed(() => ({
|
|
locales: allLocales,
|
|
locale: t("languageCode"),
|
|
plugins: [dayGridPlugin, interactionPlugin, timeGridPlugin],
|
|
// local debugging of mobilePage variable in object creation on ternary expression
|
|
initialView: mobilePage.value ? "Day" : "week",
|
|
initialDate: date.value,
|
|
dayHeaderFormat: { weekday: "short", omitCommas: true },
|
|
slotDuration: "00:15:00",
|
|
eventTimeFormat: {
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
hour12: false,
|
|
},
|
|
height: "auto",
|
|
views: {
|
|
week: {
|
|
type: "timeGrid",
|
|
slotLabelFormat: {
|
|
hour: "numeric",
|
|
minute: "2-digit",
|
|
omitZeroMinute: false,
|
|
meridiem: false,
|
|
hour12: false,
|
|
},
|
|
dateAlignment: "week",
|
|
titleFormat: { month: "short", day: "numeric" },
|
|
slotMinTime: "06:00:00",
|
|
slotMaxTime: "22:00:00",
|
|
duration: { days: 7 },
|
|
firstDay: 1,
|
|
allDaySlot: false,
|
|
hiddenDays: [0],
|
|
},
|
|
Day: {
|
|
type: "timeGrid",
|
|
slotLabelFormat: {
|
|
hour: "numeric",
|
|
minute: "2-digit",
|
|
omitZeroMinute: false,
|
|
meridiem: false,
|
|
hour12: false,
|
|
},
|
|
titleFormat: { month: "short", day: "numeric" },
|
|
slotMinTime: "06:00:00",
|
|
slotMaxTime: "22:00:00",
|
|
duration: { days: 1 },
|
|
allDaySlot: false,
|
|
hiddenDays: [0],
|
|
},
|
|
},
|
|
headerToolbar: {
|
|
end: "prev,next today",
|
|
center: "title",
|
|
start: "week,Day",
|
|
},
|
|
|
|
datesSet: function (dateInfo: DatesSetArg) {
|
|
const view = dateInfo.view;
|
|
const offset = new Date().getTimezoneOffset();
|
|
const startDate = new Date(view.activeStart.getTime() - offset * 60 * 1000);
|
|
const endDate = new Date(view.activeEnd.getTime() - offset * 60 * 1000);
|
|
currentDateFrom.value = startDate.toISOString().split("T")[0];
|
|
currentDateTo.value = endDate.toISOString().split("T")[0];
|
|
router.replace({
|
|
query: {
|
|
...router.currentRoute.value.query,
|
|
date: formatYearMonthDay(startDate),
|
|
},
|
|
});
|
|
getOccupation();
|
|
},
|
|
events: function (
|
|
_info: unknown,
|
|
successCallback: (events: EventInput[]) => void,
|
|
) {
|
|
successCallback(
|
|
occupations.value.map((event) => {
|
|
return {
|
|
id: event.id.toString(),
|
|
start: event.start,
|
|
end: event.end,
|
|
color: event.showFree ? "var(--green-800)" : "var(--primary-color)",
|
|
textColor: event.showFree
|
|
? "var(--green-50)"
|
|
: "var(--primary-color-text)",
|
|
title: event.showFree
|
|
? t("roomFinderPage.available")
|
|
: t("roomFinderPage.occupied"),
|
|
} as EventInput;
|
|
}),
|
|
);
|
|
},
|
|
}));
|
|
</script>
|
|
<template>
|
|
<FullCalendar ref="fullCalendar" :options="calendarOptions" />
|
|
</template>
|
|
|
|
<style scoped>
|
|
:deep(.fc-toolbar.fc-header-toolbar) {
|
|
flex-wrap: wrap;
|
|
justify-content: space-between;
|
|
gap: 0.5rem;
|
|
}
|
|
</style>
|