Compare commits

2 Commits

Author SHA1 Message Date
dd631b71bb Refactor Reservations into new store
All checks were successful
Build BAB Application Deployment Artifact / build (push) Successful in 2m2s
2024-05-13 12:42:10 -04:00
b0921ccf32 refactor utils 2024-05-13 12:31:27 -04:00
9 changed files with 111 additions and 106 deletions

View File

@@ -7,6 +7,7 @@ import { defineComponent, onMounted } from 'vue';
import { useScheduleStore } from './stores/schedule'; import { useScheduleStore } from './stores/schedule';
import { useBoatStore } from './stores/boat'; import { useBoatStore } from './stores/boat';
import { useAuthStore } from './stores/auth'; import { useAuthStore } from './stores/auth';
import { useReservationStore } from './stores/reservation';
defineComponent({ defineComponent({
name: 'OYS Borrow-a-Boat', name: 'OYS Borrow-a-Boat',
@@ -16,7 +17,7 @@ onMounted(async () => {
await useAuthStore().init(); await useAuthStore().init();
await useScheduleStore().fetchIntervalTemplates(); await useScheduleStore().fetchIntervalTemplates();
await useScheduleStore().fetchIntervals(); await useScheduleStore().fetchIntervals();
await useScheduleStore().fetchReservations(); await useReservationStore().fetchReservations();
await useBoatStore().fetchBoats(); await useBoatStore().fetchBoats();
}); });
</script> </script>

View File

@@ -114,7 +114,7 @@ import {
parsed, parsed,
} from '@quasar/quasar-ui-qcalendar'; } from '@quasar/quasar-ui-qcalendar';
import { Boat, useBoatStore } from 'src/stores/boat'; import { Boat, useBoatStore } from 'src/stores/boat';
import { useScheduleStore } from 'src/stores/schedule'; import { useReservationStore } from 'src/stores/reservation';
import { date } from 'quasar'; import { date } from 'quasar';
import { computed } from 'vue'; import { computed } from 'vue';
import type { StatusTypes } from 'src/stores/schedule.types'; import type { StatusTypes } from 'src/stores/schedule.types';
@@ -146,7 +146,7 @@ const statusLookup = {
const calendar = ref(); const calendar = ref();
const boatStore = useBoatStore(); const boatStore = useBoatStore();
const scheduleStore = useScheduleStore(); const reservationStore = useReservationStore();
const selectedDate = ref(today()); const selectedDate = ref(today());
const duration = ref(1); const duration = ref(1);
@@ -172,7 +172,7 @@ function monthFormatter() {
} }
function getEvents(scope: ResourceIntervalScope) { function getEvents(scope: ResourceIntervalScope) {
const resourceEvents = scheduleStore.getBoatReservations( const resourceEvents = reservationStore.getBoatReservations(
parseDate(date.extractDate(selectedDate.value, 'YYYY-MM-DD')) as Timestamp, parseDate(date.extractDate(selectedDate.value, 'YYYY-MM-DD')) as Timestamp,
scope.resource.$id scope.resource.$id
); );

View File

@@ -79,8 +79,10 @@ import { useScheduleStore } from 'src/stores/schedule';
import { useAuthStore } from 'src/stores/auth'; import { useAuthStore } from 'src/stores/auth';
import { Interval, Reservation } from 'src/stores/schedule.types'; import { Interval, Reservation } from 'src/stores/schedule.types';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useReservationStore } from 'src/stores/reservation';
const scheduleStore = useScheduleStore(); const scheduleStore = useScheduleStore();
const reservationStore = useReservationStore();
const { boats } = storeToRefs(useBoatStore()); const { boats } = storeToRefs(useBoatStore());
const selectedBlock = defineModel<Interval | null>(); const selectedBlock = defineModel<Interval | null>();
const selectedDate = ref(today()); const selectedDate = ref(today());
@@ -187,7 +189,7 @@ function getBoatBlocks(scope: DayBodyScope): Interval[] {
function getBoatReservations(scope: DayBodyScope): Reservation[] { function getBoatReservations(scope: DayBodyScope): Reservation[] {
const boat = boats.value[scope.columnIndex]; const boat = boats.value[scope.columnIndex];
return boat return boat
? scheduleStore.getBoatReservations(scope.timestamp, boat.$id) ? reservationStore.getBoatReservations(scope.timestamp, boat.$id)
: []; : [];
} }

View File

@@ -101,9 +101,9 @@ import { ref, computed, watch } from 'vue';
import { useAuthStore } from 'src/stores/auth'; import { useAuthStore } from 'src/stores/auth';
import { Boat, useBoatStore } from 'src/stores/boat'; import { Boat, useBoatStore } from 'src/stores/boat';
import { date } from 'quasar'; import { date } from 'quasar';
import { useScheduleStore } from 'src/stores/schedule';
import { Interval } from 'src/stores/schedule.types'; import { Interval } from 'src/stores/schedule.types';
import BoatScheduleTableComponent from 'src/components/scheduling/boat/BoatScheduleTableComponent.vue'; import BoatScheduleTableComponent from 'src/components/scheduling/boat/BoatScheduleTableComponent.vue';
import { getNewId } from 'src/utils/misc';
interface BookingForm { interface BookingForm {
bookingId: string; bookingId: string;
@@ -118,10 +118,9 @@ interface BookingForm {
const auth = useAuthStore(); const auth = useAuthStore();
const dateFormat = 'MMM D, YYYY h:mm A'; const dateFormat = 'MMM D, YYYY h:mm A';
const resourceView = ref(true); const resourceView = ref(true);
const scheduleStore = useScheduleStore();
const timeblock = ref<Interval>(); const timeblock = ref<Interval>();
const bookingForm = ref<BookingForm>({ const bookingForm = ref<BookingForm>({
bookingId: scheduleStore.getNewId(), bookingId: getNewId(),
name: auth.currentUser?.name, name: auth.currentUser?.name,
boat: <Boat | undefined>undefined, boat: <Boat | undefined>undefined,
startDate: date.formatDate(new Date(), dateFormat), startDate: date.formatDate(new Date(), dateFormat),

View File

@@ -52,10 +52,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useScheduleStore } from 'src/stores/schedule'; import { useReservationStore } from 'src/stores/reservation';
import { Reservation } from 'src/stores/schedule.types'; import { Reservation } from 'src/stores/schedule.types';
import { ref } from 'vue'; import { ref } from 'vue';
const scheduleStore = useScheduleStore(); const reservationStore = useReservationStore();
import { TimestampOrNull, parsed, today } from '@quasar/quasar-ui-qcalendar'; import { TimestampOrNull, parsed, today } from '@quasar/quasar-ui-qcalendar';
import { QCalendarDay } from '@quasar/quasar-ui-qcalendar'; import { QCalendarDay } from '@quasar/quasar-ui-qcalendar';
import { date } from 'quasar'; import { date } from 'quasar';
@@ -87,7 +87,7 @@ function slotStyle(
} }
function reservationEvents(timestamp: Timestamp) { function reservationEvents(timestamp: Timestamp) {
return scheduleStore.getBoatReservations(timestamp); return reservationStore.getBoatReservations(timestamp);
} }
function onMoved(data: Event) { function onMoved(data: Event) {
console.log('onMoved', data); console.log('onMoved', data);

View File

@@ -145,9 +145,9 @@ import {
blocksOverlapped, blocksOverlapped,
buildInterval, buildInterval,
useScheduleStore, useScheduleStore,
buildISODate,
} from 'src/stores/schedule'; } from 'src/stores/schedule';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { buildISODate } from 'src/utils/misc';
import type { import type {
Interval, Interval,
IntervalTemplate, IntervalTemplate,

84
src/stores/reservation.ts Normal file
View File

@@ -0,0 +1,84 @@
import { defineStore } from 'pinia';
import type { Reservation } from './schedule.types';
import { ref } from 'vue';
import { AppwriteIds, databases } from 'src/boot/appwrite';
import { Timestamp, parsed } from '@quasar/quasar-ui-qcalendar';
export const useReservationStore = defineStore('reservation', () => {
const reservations = ref<Reservation[]>([]);
const getConflictingReservations = (
resource: string,
start: Date,
end: Date
): Reservation[] => {
const overlapped = reservations.value.filter(
(entry: Reservation) =>
entry.resource == resource &&
new Date(entry.start) < end &&
new Date(entry.end) > start
);
return overlapped;
};
const isResourceTimeOverlapped = (
resource: string,
start: Date,
end: Date
): boolean => {
return getConflictingReservations(resource, start, end).length > 0;
};
const isReservationOverlapped = (res: Reservation): boolean => {
return isResourceTimeOverlapped(
res.resource,
new Date(res.start),
new Date(res.end)
);
};
const addOrCreateReservation = (reservation: Reservation) => {
const index = reservations.value.findIndex(
(res) => res.id == reservation.id
);
index != -1
? (reservations.value[index] = reservation)
: reservations.value.push(reservation);
};
async function fetchReservations() {
try {
const response = await databases.listDocuments(
AppwriteIds.databaseId,
AppwriteIds.collection.reservation
);
reservations.value = response.documents as Reservation[];
} catch (error) {
console.error('Failed to fetch timeblocks', error);
}
}
const getBoatReservations = (
searchDate: Timestamp,
boat?: string
): Reservation[] => {
const result = reservations.value.filter((x) => {
return (
((parsed(x.start)?.date == searchDate.date ||
parsed(x.end)?.date == searchDate.date) && // Part of reservation falls on day
x.resource != undefined && // A boat is defined
!boat) ||
x.resource == boat // A specific boat has been passed, and matches
);
});
return result;
};
return {
getBoatReservations,
fetchReservations,
addOrCreateReservation,
isReservationOverlapped,
isResourceTimeOverlapped,
getConflictingReservations,
};
});

View File

@@ -8,14 +8,10 @@ import {
compareDate, compareDate,
} from '@quasar/quasar-ui-qcalendar'; } from '@quasar/quasar-ui-qcalendar';
import { import { IntervalTemplate, TimeTuple, Interval } from './schedule.types';
Reservation,
IntervalTemplate,
TimeTuple,
Interval,
} from './schedule.types';
import { AppwriteIds, databases } from 'src/boot/appwrite'; import { AppwriteIds, databases } from 'src/boot/appwrite';
import { ID, Models } from 'appwrite'; import { ID, Models } from 'appwrite';
import { buildISODate } from 'src/utils/misc';
export function arrayToTimeTuples(arr: string[]) { export function arrayToTimeTuples(arr: string[]) {
const timeTuples: TimeTuple[] = []; const timeTuples: TimeTuple[] = [];
@@ -65,10 +61,6 @@ export function copyIntervalTemplate(
}; };
} }
export function buildISODate(date: string, time: string | null): string {
return new Date(date + 'T' + time || '00:00').toISOString();
}
export function buildInterval( export function buildInterval(
resource: Boat, resource: Boat,
time: TimeTuple, time: TimeTuple,
@@ -86,7 +78,6 @@ export function buildInterval(
export const useScheduleStore = defineStore('schedule', () => { export const useScheduleStore = defineStore('schedule', () => {
// TODO: Implement functions to dynamically pull this data. // TODO: Implement functions to dynamically pull this data.
const reservations = ref<Reservation[]>([]);
const timeblocks = ref<Interval[]>([]); const timeblocks = ref<Interval[]>([]);
const timeblockTemplates = ref<IntervalTemplate[]>([]); const timeblockTemplates = ref<IntervalTemplate[]>([]);
@@ -108,34 +99,6 @@ export const useScheduleStore = defineStore('schedule', () => {
}); });
}; };
async function fetchReservations() {
try {
const response = await databases.listDocuments(
AppwriteIds.databaseId,
AppwriteIds.collection.reservation
);
reservations.value = response.documents as Reservation[];
} catch (error) {
console.error('Failed to fetch timeblocks', error);
}
}
const getBoatReservations = (
searchDate: Timestamp,
boat?: string
): Reservation[] => {
const result = reservations.value.filter((x) => {
return (
((parsed(x.start)?.date == searchDate.date ||
parsed(x.end)?.date == searchDate.date) && // Part of reservation falls on day
x.resource != undefined && // A boat is defined
!boat) ||
x.resource == boat // A specific boat has been passed, and matches
);
});
return result;
};
async function fetchIntervals() { async function fetchIntervals() {
try { try {
const response = await databases.listDocuments( const response = await databases.listDocuments(
@@ -182,53 +145,6 @@ export const useScheduleStore = defineStore('schedule', () => {
// return scheduleStore.getConflictingReservations(boat, start, end); // return scheduleStore.getConflictingReservations(boat, start, end);
// }; // };
const getConflictingReservations = (
resource: string,
start: Date,
end: Date
): Reservation[] => {
const overlapped = reservations.value.filter(
(entry: Reservation) =>
entry.resource == resource &&
new Date(entry.start) < end &&
new Date(entry.end) > start
);
return overlapped;
};
const isResourceTimeOverlapped = (
resource: string,
start: Date,
end: Date
): boolean => {
return getConflictingReservations(resource, start, end).length > 0;
};
const isReservationOverlapped = (res: Reservation): boolean => {
return isResourceTimeOverlapped(
res.resource,
new Date(res.start),
new Date(res.end)
);
};
const getNewId = (): string => {
return [...Array(20)]
.map(() => Math.floor(Math.random() * 16).toString(16))
.join('');
// Trivial placeholder
//return Math.max(...reservations.value.map((item) => item.id)) + 1;
};
const addOrCreateReservation = (reservation: Reservation) => {
const index = reservations.value.findIndex(
(res) => res.id == reservation.id
);
index != -1
? (reservations.value[index] = reservation)
: reservations.value.push(reservation);
};
const createInterval = async (interval: Interval) => { const createInterval = async (interval: Interval) => {
try { try {
const response = await databases.createDocument( const response = await databases.createDocument(
@@ -326,20 +242,12 @@ export const useScheduleStore = defineStore('schedule', () => {
}; };
return { return {
reservations,
timeblocks, timeblocks,
timeblockTemplates, timeblockTemplates,
getBoatReservations,
getConflictingReservations,
addOrCreateReservation,
isReservationOverlapped,
isResourceTimeOverlapped,
fetchReservations,
getIntervalsForDate, getIntervalsForDate,
getIntervals, getIntervals,
fetchIntervals, fetchIntervals,
fetchIntervalTemplates, fetchIntervalTemplates,
getNewId,
createInterval, createInterval,
updateInterval, updateInterval,
deleteInterval, deleteInterval,

11
src/utils/misc.ts Normal file
View File

@@ -0,0 +1,11 @@
export function buildISODate(date: string, time: string | null): string {
return new Date(date + 'T' + time || '00:00').toISOString();
}
export function getNewId(): string {
return [...Array(20)]
.map(() => Math.floor(Math.random() * 16).toString(16))
.join('');
// Trivial placeholder
//return Math.max(...reservations.value.map((item) => item.id)) + 1;
}