diff --git a/docker-compose.yml b/docker-compose.yml index 6e3e589..c3ec523 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: - "8090:8090" volumes: - pb_data:/htwkalender/data # for production with volume - # - ./backend/pb_data:/pb_data # for development with bind mount from project directory + # - ./backend:/htwkalender/data # for development with bind mount from project directory htwkalender-frontend: build: diff --git a/frontend/src/api/createFeed.ts b/frontend/src/api/createFeed.ts index 2c89049..126f87b 100644 --- a/frontend/src/api/createFeed.ts +++ b/frontend/src/api/createFeed.ts @@ -10,7 +10,11 @@ export async function createIndividualFeed(modules: Module[]): Promise { body: JSON.stringify(modules), }); - if (response.status === 429 || response.status === 500 || response.status != 200) { + if ( + response.status === 429 || + response.status === 500 || + response.status != 200 + ) { return Promise.reject(response.statusText); } diff --git a/frontend/src/components/RenameModules.vue b/frontend/src/components/RenameModules.vue index 17f2eee..dfbadbc 100644 --- a/frontend/src/components/RenameModules.vue +++ b/frontend/src/components/RenameModules.vue @@ -37,7 +37,9 @@ const columns = computed(() => [ const toast = useToast(); async function finalStep() { - const createFeed: Promise= createIndividualFeed(store.getAllModules()); + const createFeed: Promise = createIndividualFeed( + store.getAllModules(), + ); // Check if createFeed Promise is resolved createFeed.then(async (token: string) => { diff --git a/frontend/src/components/RoomOccupation.vue b/frontend/src/components/RoomOccupation.vue index 1f13108..5acb041 100644 --- a/frontend/src/components/RoomOccupation.vue +++ b/frontend/src/components/RoomOccupation.vue @@ -7,6 +7,9 @@ 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({ @@ -23,6 +26,29 @@ type CalenderEvent = { showFree: boolean; }; +const date: Ref = 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 = ref(""); const currentDateTo: Ref = ref(""); const occupations: Ref = ref([]); @@ -64,14 +90,13 @@ async function getOccupation() { }); } -import allLocales from "@fullcalendar/core/locales-all"; - const calendarOptions: ComputedRef = 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: { @@ -129,6 +154,12 @@ const calendarOptions: ComputedRef = computed(() => ({ 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 ( diff --git a/frontend/src/helpers/dates.ts b/frontend/src/helpers/dates.ts new file mode 100644 index 0000000..48c3527 --- /dev/null +++ b/frontend/src/helpers/dates.ts @@ -0,0 +1,8 @@ +/** + * Format a date to a string in the format "YYYYMMDD". + * @param date - The date to format + * @returns string - The formatted date + */ +export function formatYearMonthDay(date: Date): string { + return date.toISOString().split("T")[0].replace(/-/g, ""); +} diff --git a/frontend/src/i18n/translations/de.json b/frontend/src/i18n/translations/de.json index f073849..0094cfb 100644 --- a/frontend/src/i18n/translations/de.json +++ b/frontend/src/i18n/translations/de.json @@ -33,7 +33,8 @@ "searchByRoom": "Suche nach Räumen", "pleaseSelectDate": "Bitte wähle ein Datum aus", "room": "Raum", - "search": "Suchen" + "search": "Suchen", + "viewOccupancy": "Belegung anzeigen" }, "moduleSelection": { "selectAll": "Alle anwählen", diff --git a/frontend/src/i18n/translations/en.json b/frontend/src/i18n/translations/en.json index d082f39..7498f40 100644 --- a/frontend/src/i18n/translations/en.json +++ b/frontend/src/i18n/translations/en.json @@ -33,7 +33,8 @@ "searchByRoom": "search by room", "pleaseSelectDate": "please select a date", "room": "room", - "search": "search" + "search": "search", + "viewOccupancy": "View Occupancy" }, "moduleSelection": { "selectAll": "select all", diff --git a/frontend/src/view/FreeRooms.vue b/frontend/src/view/FreeRooms.vue index 5a0539a..4740528 100644 --- a/frontend/src/view/FreeRooms.vue +++ b/frontend/src/view/FreeRooms.vue @@ -110,6 +110,17 @@ @input="filterCallback()" /> + @@ -122,12 +133,25 @@ import DynamicPage from "@/view/DynamicPage.vue"; import { requestFreeRooms } from "@/api/requestFreeRooms.ts"; import { FilterMatchMode } from "primevue/api"; import { padStart } from "@fullcalendar/core/internal"; +import router from "@/router"; +import { formatYearMonthDay } from "@/helpers/dates"; const mobilePage = inject("mobilePage") as Ref; const filters = ref({ room: { value: null, matchMode: FilterMatchMode.CONTAINS, label: "Room" }, }); +function occupationRoute(room: string): void { + // date is in format like YYYYMMDD + router.push({ + name: "room-schedule", + query: { + room: room, + date: formatYearMonthDay(date.value), + }, + }); +} + const date: Ref = ref(new Date(Date.now())); const start: Ref = ref(new Date(0)); const end: Ref = ref(new Date(0)); diff --git a/frontend/src/view/RoomFinder.vue b/frontend/src/view/RoomFinder.vue index 9abbf36..54cd924 100644 --- a/frontend/src/view/RoomFinder.vue +++ b/frontend/src/view/RoomFinder.vue @@ -1,18 +1,67 @@