From a11b2a056876d66e372e61f6b22a350178bbd145 Mon Sep 17 00:00:00 2001 From: Patrick Toal Date: Fri, 21 Jun 2024 23:44:34 -0400 Subject: [PATCH] fix: reactivity bug with ListReservationsPage --- .../ResourceScheduleViewerComponent.vue | 2 +- .../boat/BoatScheduleTableComponent.vue | 2 +- src/pages/schedule/BoatScheduleView.vue | 10 +-- src/pages/schedule/ListReservationsPage.vue | 8 +- src/stores/reservation.ts | 78 ++++++------------- 5 files changed, 36 insertions(+), 64 deletions(-) diff --git a/src/components/ResourceScheduleViewerComponent.vue b/src/components/ResourceScheduleViewerComponent.vue index 50414ce..329ca98 100644 --- a/src/components/ResourceScheduleViewerComponent.vue +++ b/src/components/ResourceScheduleViewerComponent.vue @@ -184,7 +184,7 @@ function getEvents(scope: ResourceIntervalScope) { scope.resource.$id ); - return resourceEvents.map((event) => { + return resourceEvents.value.map((event) => { return { left: scope.timeStartPosX(parsed(event.start)), width: scope.timeDurationWidth( diff --git a/src/components/scheduling/boat/BoatScheduleTableComponent.vue b/src/components/scheduling/boat/BoatScheduleTableComponent.vue index 6e10187..64e9253 100644 --- a/src/components/scheduling/boat/BoatScheduleTableComponent.vue +++ b/src/components/scheduling/boat/BoatScheduleTableComponent.vue @@ -207,7 +207,7 @@ function selectBlock(event: MouseEvent, scope: DayBodyScope, block: Interval) { const boatReservations = computed((): Record => { return reservationStore .getReservationsByDate(selectedDate.value) - .reduce((result, reservation) => { + .value.reduce((result, reservation) => { if (!result[reservation.resource]) result[reservation.resource] = []; result[reservation.resource].push(reservation); return result; diff --git a/src/pages/schedule/BoatScheduleView.vue b/src/pages/schedule/BoatScheduleView.vue index aae61d0..d0169b1 100644 --- a/src/pages/schedule/BoatScheduleView.vue +++ b/src/pages/schedule/BoatScheduleView.vue @@ -134,16 +134,16 @@ const createReservationFromInterval = (interval: Interval | Reservation) => { function handleSwipe({ ...event }) { event.direction === 'right' ? calendar.value?.prev() : calendar.value?.next(); } -function boatReservationEvents( +const boatReservationEvents = ( timestamp: Timestamp, resource: Boat | undefined -) { - if (!resource) return []; +): Reservation[] => { + if (!resource) return [] as Reservation[]; return reservationStore.getReservationsByDate( getDate(timestamp), (resource as Boat).$id - ); -} + ).value; +}; function onToday() { calendar.value.moveToToday(); } diff --git a/src/pages/schedule/ListReservationsPage.vue b/src/pages/schedule/ListReservationsPage.vue index ca11856..25199f6 100644 --- a/src/pages/schedule/ListReservationsPage.vue +++ b/src/pages/schedule/ListReservationsPage.vue @@ -22,7 +22,7 @@ class="q-pa-none"> + v-if="!reservationStore.futureUserReservations.length">
You don't have any upcoming bookings!
Why don't you go make one?
@@ -41,7 +41,7 @@
@@ -51,7 +51,7 @@ name="past" class="q-pa-none">
@@ -63,7 +63,7 @@ import { useReservationStore } from 'src/stores/reservation'; import ReservationCardComponent from 'src/components/scheduling/ReservationCardComponent.vue'; import { onMounted, ref } from 'vue'; -const { futureUserReservations, pastUserReservations } = useReservationStore(); +const reservationStore = useReservationStore(); onMounted(() => useReservationStore().fetchUserReservations()); diff --git a/src/stores/reservation.ts b/src/stores/reservation.ts index e4d6ac5..c5094e8 100644 --- a/src/stores/reservation.ts +++ b/src/stores/reservation.ts @@ -1,6 +1,6 @@ import { defineStore } from 'pinia'; import type { Reservation } from './schedule.types'; -import { computed, ref, watch } from 'vue'; +import { ComputedRef, computed, reactive } from 'vue'; import { AppwriteIds, databases } from 'src/boot/appwrite'; import { ID, Query } from 'appwrite'; import { date, useQuasar } from 'quasar'; @@ -11,10 +11,10 @@ import { isPast } from 'src/utils/schedule'; import { useRealtimeStore } from './realtime'; export const useReservationStore = defineStore('reservation', () => { - const reservations = ref>(new Map()); - const datesLoaded = ref>({}); - const userReservations = ref>(new Map()); - // TODO: Come up with a better way of storing reservations by date & reservations for user + const reservations = reactive>(new Map()); + const datesLoaded = reactive>({}); + const userReservations = reactive>(new Map()); + const authStore = useAuthStore(); const $q = useQuasar(); const realtimeStore = useRealtimeStore(); @@ -29,12 +29,12 @@ export const useReservationStore = defineStore('reservation', () => { 'databases.*.collections.*.documents.*.delete' ) ) { - reservations.value.delete(payload.$id); - userReservations.value.delete(payload.$id); + reservations.delete(payload.$id); + userReservations.delete(payload.$id); } else { - reservations.value.set(payload.$id, payload); + reservations.set(payload.$id, payload); if (payload.user === authStore.currentUser?.$id) - userReservations.value.set(payload.$id, payload); + userReservations.set(payload.$id, payload); } } } @@ -62,7 +62,7 @@ export const useReservationStore = defineStore('reservation', () => { ); response.documents.forEach((d) => - reservations.value.set(d.$id, d as Reservation) + reservations.set(d.$id, d as Reservation) ); setDateLoaded(startDate, endDate, 'loaded'); } catch (error) { @@ -103,8 +103,8 @@ export const useReservationStore = defineStore('reservation', () => { reservation ); } - reservations.value.set(response.$id, response as Reservation); - userReservations.value.set(response.$id, response as Reservation); + reservations.set(response.$id, response as Reservation); + userReservations.set(response.$id, response as Reservation); console.info('Reservation booked: ', response); return response as Reservation; } catch (e) { @@ -117,14 +117,8 @@ export const useReservationStore = defineStore('reservation', () => { reservation: string | Reservation | null | undefined ) => { if (!reservation) return false; - let id; - if (typeof reservation === 'string') { - id = reservation; - } else if ('$id' in reservation && typeof reservation.$id === 'string') { - id = reservation.$id; - } else { - return false; - } + const id = typeof reservation === 'string' ? reservation : reservation.$id; + if (!id) return false; const status = $q.notify({ color: 'secondary', @@ -142,8 +136,8 @@ export const useReservationStore = defineStore('reservation', () => { AppwriteIds.collection.reservation, id ); - reservations.value.delete(id); - userReservations.value.delete(id); + reservations.delete(id); + userReservations.delete(id); console.info(`Deleted reservation: ${id}`); status({ color: 'warning', @@ -168,7 +162,7 @@ export const useReservationStore = defineStore('reservation', () => { if (start > end) return []; let curDate = start; while (curDate < end) { - datesLoaded.value[(parseDate(curDate) as Timestamp).date] = state; + datesLoaded[(parseDate(curDate) as Timestamp).date] = state; curDate = date.addToDate(curDate, { days: 1 }); } }; @@ -179,8 +173,7 @@ export const useReservationStore = defineStore('reservation', () => { const unloaded = []; while (curDate < end) { const parsedDate = (parseDate(curDate) as Timestamp).date; - if (datesLoaded.value[parsedDate] === undefined) - unloaded.push(parsedDate); + if (datesLoaded[parsedDate] === undefined) unloaded.push(parsedDate); curDate = date.addToDate(curDate, { days: 1 }); } return unloaded; @@ -190,15 +183,15 @@ export const useReservationStore = defineStore('reservation', () => { const getReservationsByDate = ( searchDate: string, boat?: string - ): Reservation[] => { - if (!datesLoaded.value[searchDate]) { + ): ComputedRef => { + if (!datesLoaded[searchDate]) { fetchReservationsForDateRange(searchDate); } const dayStart = new Date(searchDate + 'T00:00'); const dayEnd = new Date(searchDate + 'T23:59'); return computed(() => { - return Array.from(reservations.value.values()).filter((reservation) => { + return Array.from(reservations.values()).filter((reservation) => { const reservationStart = new Date(reservation.start); const reservationEnd = new Date(reservation.end); @@ -207,7 +200,7 @@ export const useReservationStore = defineStore('reservation', () => { const matchesBoat = boat ? boat === reservation.resource : true; return isWithinDay && matchesBoat; }); - }).value; + }); }; // Get conflicting reservations for a resource within a time range @@ -216,7 +209,7 @@ export const useReservationStore = defineStore('reservation', () => { start: Date, end: Date ): Reservation[] => { - return Array.from(reservations.value.values()).filter( + return Array.from(reservations.values()).filter( (entry) => entry.resource === resource && new Date(entry.start) < end && @@ -251,7 +244,7 @@ export const useReservationStore = defineStore('reservation', () => { [Query.equal('user', authStore.currentUser.$id)] ); response.documents.forEach((d) => - userReservations.value.set(d.$id, d as Reservation) + userReservations.set(d.$id, d as Reservation) ); } catch (error) { console.error('Failed to fetch reservations for user: ', error); @@ -259,7 +252,7 @@ export const useReservationStore = defineStore('reservation', () => { }; const sortedUserReservations = computed((): Reservation[] => - [...userReservations.value?.values()].sort( + [...userReservations.values()].sort( (a, b) => new Date(b.start).getTime() - new Date(a.start).getTime() ) ); @@ -274,27 +267,6 @@ export const useReservationStore = defineStore('reservation', () => { return sortedUserReservations.value?.filter((b) => isPast(b.end)); }); - // Ensure reactivity for computed properties when Map is modified - watch( - reservations, - () => { - sortedUserReservations.value; - futureUserReservations.value; - pastUserReservations.value; - }, - { deep: true } - ); - - watch( - userReservations, - () => { - sortedUserReservations.value; - futureUserReservations.value; - pastUserReservations.value; - }, - { deep: true } - ); - return { getReservationsByDate, getReservationById,