9 Commits

Author SHA1 Message Date
a11b2a0568 fix: reactivity bug with ListReservationsPage
All checks were successful
Build BAB Application Deployment Artifact / build (push) Successful in 2m32s
2024-06-21 23:44:34 -04:00
ff8e54449a feat: add realtime updates of interval and reservation 2024-06-21 23:13:30 -04:00
64a59e856f feat: rudimentary realtime update of intervals 2024-06-20 23:36:05 -04:00
5e8c5a1631 feat: enable websocket proxy for dev 2024-06-20 23:14:20 -04:00
e97949cab3 fix: Improve reactivity in intervals 2024-06-20 21:52:00 -04:00
b7a3608e67 fix: dev targets 2024-06-19 23:02:01 -04:00
bbb544c029 chore: bump version
All checks were successful
Build BAB Application Deployment Artifact / build (push) Successful in 2m26s
2024-06-19 19:13:33 -04:00
da42f6ed22 chore: Update gitignore
All checks were successful
Build BAB Application Deployment Artifact / build (push) Successful in 2m8s
2024-06-17 16:31:29 -04:00
8016e20451 fix: remove dotenv files from repo 2024-06-17 16:30:59 -04:00
14 changed files with 141 additions and 105 deletions

View File

@@ -1,2 +0,0 @@
VITE_APPWRITE_API_ENDPOINT='http://localhost:4000/api/v1'
VITE_APPWRITE_API_PROJECT='65ede55a213134f2b688'

View File

@@ -1,2 +0,0 @@
VITE_APPWRITE_API_ENDPOINT='https://appwrite.oys.undock.ca/v1'
VITE_APPWRITE_API_PROJECT='bab'

2
.gitignore vendored
View File

@@ -34,4 +34,4 @@ yarn-error.log*
*.sln *.sln
# local .env files # local .env files
.env.local* .env*

View File

@@ -108,12 +108,19 @@ module.exports = configure(function ({ dev }) {
secure: false, secure: false,
rewrite: (path) => path.replace(/^\/api/, ''), rewrite: (path) => path.replace(/^\/api/, ''),
}, },
'/function': { '/api/v1/realtime': {
target: 'https://6640382951eacb568371.f.appwrite.toal.ca/', target: 'wss://apidev.bab.toal.ca',
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
secure: false, secure: false,
rewrite: (path) => path.replace(/^\/function/, ''), ws: true,
}, },
// '/function': {
// target: 'https://6640382951eacb568371.f.appwrite.toal.ca/',
// changeOrigin: true,
// secure: false,
// rewrite: (path) => path.replace(/^\/function/, ''),
// },
}, },
// For reverse-proxying via haproxy // For reverse-proxying via haproxy
// hmr: { // hmr: {

View File

@@ -43,7 +43,11 @@ type AppwriteIDConfig = {
let AppwriteIds = <AppwriteIDConfig>{}; let AppwriteIds = <AppwriteIDConfig>{};
if (API_ENDPOINT === 'https://apidev.bab.toal.ca/v1') { console.log(API_ENDPOINT);
if (
API_ENDPOINT === 'https://apidev.bab.toal.ca/v1' ||
API_ENDPOINT === 'http://localhost:4000/api/v1'
) {
AppwriteIds = { AppwriteIds = {
databaseId: '65ee1cbf9c2493faf15f', databaseId: '65ee1cbf9c2493faf15f',
collection: { collection: {

View File

@@ -184,7 +184,7 @@ function getEvents(scope: ResourceIntervalScope) {
scope.resource.$id scope.resource.$id
); );
return resourceEvents.map((event) => { return resourceEvents.value.map((event) => {
return { return {
left: scope.timeStartPosX(parsed(event.start)), left: scope.timeStartPosX(parsed(event.start)),
width: scope.timeDurationWidth( width: scope.timeDurationWidth(

View File

@@ -38,7 +38,7 @@
v-for="block in getAvailableIntervals( v-for="block in getAvailableIntervals(
scope.timestamp, scope.timestamp,
boats[scope.columnIndex] boats[scope.columnIndex]
)" ).value"
:key="block.$id"> :key="block.$id">
<div <div
class="timeblock" class="timeblock"
@@ -207,7 +207,7 @@ function selectBlock(event: MouseEvent, scope: DayBodyScope, block: Interval) {
const boatReservations = computed((): Record<string, Reservation[]> => { const boatReservations = computed((): Record<string, Reservation[]> => {
return reservationStore return reservationStore
.getReservationsByDate(selectedDate.value) .getReservationsByDate(selectedDate.value)
.reduce((result, reservation) => { .value.reduce((result, reservation) => {
if (!result[reservation.resource]) result[reservation.resource] = []; if (!result[reservation.resource]) result[reservation.resource] = [];
result[reservation.resource].push(reservation); result[reservation.resource].push(reservation);
return result; return result;

View File

@@ -92,7 +92,7 @@ const currentUser = useAuthStore().currentUser;
const getSortedIntervals = (timestamp: Timestamp, boat?: Boat): Interval[] => { const getSortedIntervals = (timestamp: Timestamp, boat?: Boat): Interval[] => {
return getAvailableIntervals(timestamp, boat) return getAvailableIntervals(timestamp, boat)
.concat(boatReservationEvents(timestamp, boat)) .value.concat(boatReservationEvents(timestamp, boat))
.sort((a, b) => Date.parse(a.start) - Date.parse(b.start)); .sort((a, b) => Date.parse(a.start) - Date.parse(b.start));
}; };
// Method declarations // Method declarations
@@ -134,16 +134,16 @@ const createReservationFromInterval = (interval: Interval | Reservation) => {
function handleSwipe({ ...event }) { function handleSwipe({ ...event }) {
event.direction === 'right' ? calendar.value?.prev() : calendar.value?.next(); event.direction === 'right' ? calendar.value?.prev() : calendar.value?.next();
} }
function boatReservationEvents( const boatReservationEvents = (
timestamp: Timestamp, timestamp: Timestamp,
resource: Boat | undefined resource: Boat | undefined
) { ): Reservation[] => {
if (!resource) return []; if (!resource) return [] as Reservation[];
return reservationStore.getReservationsByDate( return reservationStore.getReservationsByDate(
getDate(timestamp), getDate(timestamp),
(resource as Boat).$id (resource as Boat).$id
); ).value;
} };
function onToday() { function onToday() {
calendar.value.moveToToday(); calendar.value.moveToToday();
} }

View File

@@ -22,7 +22,7 @@
class="q-pa-none"> class="q-pa-none">
<q-card <q-card
clas="q-ma-md" clas="q-ma-md"
v-if="!futureUserReservations.length"> v-if="!reservationStore.futureUserReservations.length">
<q-card-section> <q-card-section>
<div class="text-h6">You don't have any upcoming bookings!</div> <div class="text-h6">You don't have any upcoming bookings!</div>
<div class="text-h8">Why don't you go make one?</div> <div class="text-h8">Why don't you go make one?</div>
@@ -41,7 +41,7 @@
</q-card> </q-card>
<div v-else> <div v-else>
<div <div
v-for="reservation in futureUserReservations" v-for="reservation in reservationStore.futureUserReservations"
:key="reservation.$id"> :key="reservation.$id">
<ReservationCardComponent :modelValue="reservation" /> <ReservationCardComponent :modelValue="reservation" />
</div> </div>
@@ -51,7 +51,7 @@
name="past" name="past"
class="q-pa-none"> class="q-pa-none">
<div <div
v-for="reservation in pastUserReservations" v-for="reservation in reservationStore.pastUserReservations"
:key="reservation.$id"> :key="reservation.$id">
<ReservationCardComponent :modelValue="reservation" /> <ReservationCardComponent :modelValue="reservation" />
</div> </div>
@@ -63,7 +63,7 @@ import { useReservationStore } from 'src/stores/reservation';
import ReservationCardComponent from 'src/components/scheduling/ReservationCardComponent.vue'; import ReservationCardComponent from 'src/components/scheduling/ReservationCardComponent.vue';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
const { futureUserReservations, pastUserReservations } = useReservationStore(); const reservationStore = useReservationStore();
onMounted(() => useReservationStore().fetchUserReservations()); onMounted(() => useReservationStore().fetchUserReservations());

View File

@@ -26,7 +26,9 @@
cell-width="150px"> cell-width="150px">
<template #day="{ scope }"> <template #day="{ scope }">
<div <div
v-if="filteredIntervals(scope.timestamp, scope.resource).length" v-if="
filteredIntervals(scope.timestamp, scope.resource).value.length
"
style=" style="
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -35,10 +37,8 @@
font-size: 12px; font-size: 12px;
"> ">
<template <template
v-for="block in sortedIntervals( v-for="block in sortedIntervals(scope.timestamp, scope.resource)
scope.timestamp, .value"
scope.resource
)"
:key="block.id"> :key="block.id">
<q-chip class="cursor-pointer"> <q-chip class="cursor-pointer">
{{ date.formatDate(block.start, 'HH:mm') }} - {{ date.formatDate(block.start, 'HH:mm') }} -
@@ -163,7 +163,7 @@ import {
} 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 { useIntervalStore } from 'src/stores/interval'; import { useIntervalStore } from 'src/stores/interval';
import { onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import type { import type {
Interval, Interval,
IntervalTemplate, IntervalTemplate,
@@ -208,8 +208,10 @@ const filteredIntervals = (date: Timestamp, boat: Boat) => {
}; };
const sortedIntervals = (date: Timestamp, boat: Boat) => { const sortedIntervals = (date: Timestamp, boat: Boat) => {
return filteredIntervals(date, boat).sort( return computed(() =>
(a, b) => Date.parse(a.start) - Date.parse(b.start) filteredIntervals(date, boat).value.sort(
(a, b) => Date.parse(a.start) - Date.parse(b.start)
)
); );
}; };
@@ -293,7 +295,7 @@ function onDrop(
overlapped.value = boatsToApply overlapped.value = boatsToApply
.map((boat) => .map((boat) =>
intervalsOverlapped( intervalsOverlapped(
existingIntervals.concat( existingIntervals.value.concat(
intervalsFromTemplate(boat, templateId, date) intervalsFromTemplate(boat, templateId, date)
) )
) )

View File

@@ -2,25 +2,44 @@ import { defineStore } from 'pinia';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { Boat } from './boat'; import { Boat } from './boat';
import { Timestamp, today } from '@quasar/quasar-ui-qcalendar'; import { Timestamp, today } from '@quasar/quasar-ui-qcalendar';
import { Interval } from './schedule.types';
import { Interval, IntervalRecord } from './schedule.types';
import { AppwriteIds, databases } from 'src/boot/appwrite'; import { AppwriteIds, databases } from 'src/boot/appwrite';
import { ID, Query } from 'appwrite'; import { ID, Query } from 'appwrite';
import { useReservationStore } from './reservation'; import { useReservationStore } from './reservation';
import { LoadingTypes } from 'src/utils/misc';
import { useRealtimeStore } from './realtime';
export const useIntervalStore = defineStore('interval', () => { export const useIntervalStore = defineStore('interval', () => {
// TODO: Implement functions to dynamically pull this data. const intervals = ref(new Map<string, Interval>()); // Intervals by DocID
const intervals = ref<Map<string, Interval>>(new Map()); const dateStatus = ref(new Map<string, LoadingTypes>()); // State of load by date
const intervalDates = ref<IntervalRecord>({});
const reservationStore = useReservationStore();
const selectedDate = ref<string>(today()); const selectedDate = ref<string>(today());
const getIntervals = (date: Timestamp | string, boat?: Boat): Interval[] => { const reservationStore = useReservationStore();
const realtimeStore = useRealtimeStore();
realtimeStore.register(
`databases.${AppwriteIds.databaseId}.collections.${AppwriteIds.collection.interval}.documents`,
(response) => {
const payload = response.payload as Interval;
if (!payload.$id) return;
if (
response.events.includes('databases.*.collections.*.documents.*.delete')
) {
intervals.value.delete(payload.$id);
} else {
intervals.value.set(payload.$id, payload);
}
}
);
const getIntervals = (date: Timestamp | string, boat?: Boat) => {
const searchDate = typeof date === 'string' ? date : date.date; const searchDate = typeof date === 'string' ? date : date.date;
const dayStart = new Date(searchDate + 'T00:00'); const dayStart = new Date(searchDate + 'T00:00');
const dayEnd = new Date(searchDate + 'T23:59'); const dayEnd = new Date(searchDate + 'T23:59');
if (!intervalDates.value[searchDate]) { if (dateStatus.value.get(searchDate) === undefined) {
intervalDates.value[searchDate] = 'pending'; dateStatus.value.set(searchDate, 'pending');
fetchIntervals(searchDate); fetchIntervals(searchDate);
} }
return computed(() => { return computed(() => {
@@ -32,22 +51,19 @@ export const useIntervalStore = defineStore('interval', () => {
const matchesBoat = boat ? boat.$id === interval.resource : true; const matchesBoat = boat ? boat.$id === interval.resource : true;
return isWithinDay && matchesBoat; return isWithinDay && matchesBoat;
}); });
}).value; });
}; };
const getAvailableIntervals = ( const getAvailableIntervals = (date: Timestamp | string, boat?: Boat) => {
date: Timestamp | string, return computed(() =>
boat?: Boat getIntervals(date, boat).value.filter((interval) => {
): Interval[] => {
return computed(() => {
return getIntervals(date, boat).filter((interval) => {
return !reservationStore.isResourceTimeOverlapped( return !reservationStore.isResourceTimeOverlapped(
interval.resource, interval.resource,
new Date(interval.start), new Date(interval.start),
new Date(interval.end) new Date(interval.end)
); );
}); })
}).value; );
}; };
async function fetchInterval(id: string): Promise<Interval> { async function fetchInterval(id: string): Promise<Interval> {
@@ -78,11 +94,11 @@ export const useIntervalStore = defineStore('interval', () => {
response.documents.forEach((d) => response.documents.forEach((d) =>
intervals.value.set(d.$id, d as Interval) intervals.value.set(d.$id, d as Interval)
); );
intervalDates.value[dateString] = 'loaded'; dateStatus.value.set(dateString, 'loaded');
console.info(`Loaded ${response.documents.length} intervals from server`); console.info(`Loaded ${response.documents.length} intervals from server`);
} catch (error) { } catch (error) {
console.error('Failed to fetch intervals', error); console.error('Failed to fetch intervals', error);
intervalDates.value[dateString] = 'error'; dateStatus.value.set(dateString, 'error');
} }
} }
@@ -140,5 +156,6 @@ export const useIntervalStore = defineStore('interval', () => {
updateInterval, updateInterval,
deleteInterval, deleteInterval,
selectedDate, selectedDate,
intervals,
}; };
}); });

21
src/stores/realtime.ts Normal file
View File

@@ -0,0 +1,21 @@
import { defineStore } from 'pinia';
import { client } from 'src/boot/appwrite';
import { Interval } from './schedule.types';
import { ref } from 'vue';
import { RealtimeResponseEvent } from 'appwrite';
export const useRealtimeStore = defineStore('realtime', () => {
const subscriptions = ref<Map<string, () => void>>(new Map());
const register = (
channel: string,
fn: (response: RealtimeResponseEvent<Interval>) => void
) => {
if (subscriptions.value.has(channel)) return; // Already subscribed. But maybe different callback fn?
subscriptions.value.set(channel, client.subscribe(channel, fn));
};
return {
register,
};
});

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import type { Reservation } from './schedule.types'; 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 { AppwriteIds, databases } from 'src/boot/appwrite';
import { ID, Query } from 'appwrite'; import { ID, Query } from 'appwrite';
import { date, useQuasar } from 'quasar'; import { date, useQuasar } from 'quasar';
@@ -8,15 +8,37 @@ import { Timestamp, parseDate, today } from '@quasar/quasar-ui-qcalendar';
import { LoadingTypes } from 'src/utils/misc'; import { LoadingTypes } from 'src/utils/misc';
import { useAuthStore } from './auth'; import { useAuthStore } from './auth';
import { isPast } from 'src/utils/schedule'; import { isPast } from 'src/utils/schedule';
import { useRealtimeStore } from './realtime';
export const useReservationStore = defineStore('reservation', () => { export const useReservationStore = defineStore('reservation', () => {
const reservations = ref<Map<string, Reservation>>(new Map()); const reservations = reactive<Map<string, Reservation>>(new Map());
const datesLoaded = ref<Record<string, LoadingTypes>>({}); const datesLoaded = reactive<Record<string, LoadingTypes>>({});
const userReservations = ref<Map<string, Reservation>>(new Map()); const userReservations = reactive<Map<string, Reservation>>(new Map());
// TODO: Come up with a better way of storing reservations by date & reservations for user
const authStore = useAuthStore(); const authStore = useAuthStore();
const $q = useQuasar(); const $q = useQuasar();
const realtimeStore = useRealtimeStore();
realtimeStore.register(
`databases.${AppwriteIds.databaseId}.collections.${AppwriteIds.collection.reservation}.documents`,
(response) => {
const payload = response.payload as Reservation;
if (payload.$id) {
if (
response.events.includes(
'databases.*.collections.*.documents.*.delete'
)
) {
reservations.delete(payload.$id);
userReservations.delete(payload.$id);
} else {
reservations.set(payload.$id, payload);
if (payload.user === authStore.currentUser?.$id)
userReservations.set(payload.$id, payload);
}
}
}
);
// Fetch reservations for a specific date range // Fetch reservations for a specific date range
const fetchReservationsForDateRange = async ( const fetchReservationsForDateRange = async (
start: string = today(), start: string = today(),
@@ -40,7 +62,7 @@ export const useReservationStore = defineStore('reservation', () => {
); );
response.documents.forEach((d) => response.documents.forEach((d) =>
reservations.value.set(d.$id, d as Reservation) reservations.set(d.$id, d as Reservation)
); );
setDateLoaded(startDate, endDate, 'loaded'); setDateLoaded(startDate, endDate, 'loaded');
} catch (error) { } catch (error) {
@@ -81,8 +103,8 @@ export const useReservationStore = defineStore('reservation', () => {
reservation reservation
); );
} }
reservations.value.set(response.$id, response as Reservation); reservations.set(response.$id, response as Reservation);
userReservations.value.set(response.$id, response as Reservation); userReservations.set(response.$id, response as Reservation);
console.info('Reservation booked: ', response); console.info('Reservation booked: ', response);
return response as Reservation; return response as Reservation;
} catch (e) { } catch (e) {
@@ -95,14 +117,8 @@ export const useReservationStore = defineStore('reservation', () => {
reservation: string | Reservation | null | undefined reservation: string | Reservation | null | undefined
) => { ) => {
if (!reservation) return false; if (!reservation) return false;
let id; const id = typeof reservation === 'string' ? reservation : reservation.$id;
if (typeof reservation === 'string') { if (!id) return false;
id = reservation;
} else if ('$id' in reservation && typeof reservation.$id === 'string') {
id = reservation.$id;
} else {
return false;
}
const status = $q.notify({ const status = $q.notify({
color: 'secondary', color: 'secondary',
@@ -120,8 +136,8 @@ export const useReservationStore = defineStore('reservation', () => {
AppwriteIds.collection.reservation, AppwriteIds.collection.reservation,
id id
); );
reservations.value.delete(id); reservations.delete(id);
userReservations.value.delete(id); userReservations.delete(id);
console.info(`Deleted reservation: ${id}`); console.info(`Deleted reservation: ${id}`);
status({ status({
color: 'warning', color: 'warning',
@@ -146,7 +162,7 @@ export const useReservationStore = defineStore('reservation', () => {
if (start > end) return []; if (start > end) return [];
let curDate = start; let curDate = start;
while (curDate < end) { while (curDate < end) {
datesLoaded.value[(parseDate(curDate) as Timestamp).date] = state; datesLoaded[(parseDate(curDate) as Timestamp).date] = state;
curDate = date.addToDate(curDate, { days: 1 }); curDate = date.addToDate(curDate, { days: 1 });
} }
}; };
@@ -157,8 +173,7 @@ export const useReservationStore = defineStore('reservation', () => {
const unloaded = []; const unloaded = [];
while (curDate < end) { while (curDate < end) {
const parsedDate = (parseDate(curDate) as Timestamp).date; const parsedDate = (parseDate(curDate) as Timestamp).date;
if (datesLoaded.value[parsedDate] === undefined) if (datesLoaded[parsedDate] === undefined) unloaded.push(parsedDate);
unloaded.push(parsedDate);
curDate = date.addToDate(curDate, { days: 1 }); curDate = date.addToDate(curDate, { days: 1 });
} }
return unloaded; return unloaded;
@@ -168,15 +183,15 @@ export const useReservationStore = defineStore('reservation', () => {
const getReservationsByDate = ( const getReservationsByDate = (
searchDate: string, searchDate: string,
boat?: string boat?: string
): Reservation[] => { ): ComputedRef<Reservation[]> => {
if (!datesLoaded.value[searchDate]) { if (!datesLoaded[searchDate]) {
fetchReservationsForDateRange(searchDate); fetchReservationsForDateRange(searchDate);
} }
const dayStart = new Date(searchDate + 'T00:00'); const dayStart = new Date(searchDate + 'T00:00');
const dayEnd = new Date(searchDate + 'T23:59'); const dayEnd = new Date(searchDate + 'T23:59');
return computed(() => { return computed(() => {
return Array.from(reservations.value.values()).filter((reservation) => { return Array.from(reservations.values()).filter((reservation) => {
const reservationStart = new Date(reservation.start); const reservationStart = new Date(reservation.start);
const reservationEnd = new Date(reservation.end); const reservationEnd = new Date(reservation.end);
@@ -185,7 +200,7 @@ export const useReservationStore = defineStore('reservation', () => {
const matchesBoat = boat ? boat === reservation.resource : true; const matchesBoat = boat ? boat === reservation.resource : true;
return isWithinDay && matchesBoat; return isWithinDay && matchesBoat;
}); });
}).value; });
}; };
// Get conflicting reservations for a resource within a time range // Get conflicting reservations for a resource within a time range
@@ -194,7 +209,7 @@ export const useReservationStore = defineStore('reservation', () => {
start: Date, start: Date,
end: Date end: Date
): Reservation[] => { ): Reservation[] => {
return Array.from(reservations.value.values()).filter( return Array.from(reservations.values()).filter(
(entry) => (entry) =>
entry.resource === resource && entry.resource === resource &&
new Date(entry.start) < end && new Date(entry.start) < end &&
@@ -229,7 +244,7 @@ export const useReservationStore = defineStore('reservation', () => {
[Query.equal('user', authStore.currentUser.$id)] [Query.equal('user', authStore.currentUser.$id)]
); );
response.documents.forEach((d) => response.documents.forEach((d) =>
userReservations.value.set(d.$id, d as Reservation) userReservations.set(d.$id, d as Reservation)
); );
} catch (error) { } catch (error) {
console.error('Failed to fetch reservations for user: ', error); console.error('Failed to fetch reservations for user: ', error);
@@ -237,7 +252,7 @@ export const useReservationStore = defineStore('reservation', () => {
}; };
const sortedUserReservations = computed((): Reservation[] => const sortedUserReservations = computed((): Reservation[] =>
[...userReservations.value?.values()].sort( [...userReservations.values()].sort(
(a, b) => new Date(b.start).getTime() - new Date(a.start).getTime() (a, b) => new Date(b.start).getTime() - new Date(a.start).getTime()
) )
); );
@@ -252,27 +267,6 @@ export const useReservationStore = defineStore('reservation', () => {
return sortedUserReservations.value?.filter((b) => isPast(b.end)); 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 { return {
getReservationsByDate, getReservationsByDate,
getReservationById, getReservationById,

View File

@@ -1,5 +1,4 @@
import { Models } from 'appwrite'; import { Models } from 'appwrite';
import { LoadingTypes } from 'src/utils/misc';
export type StatusTypes = 'tentative' | 'confirmed' | 'pending' | undefined; export type StatusTypes = 'tentative' | 'confirmed' | 'pending' | undefined;
export type Reservation = Interval & { export type Reservation = Interval & {
@@ -29,7 +28,3 @@ export type IntervalTemplate = Partial<Models.Document> & {
name: string; name: string;
timeTuples: TimeTuple[]; timeTuples: TimeTuple[];
}; };
export interface IntervalRecord {
[key: string]: LoadingTypes;
}