Compare commits
9 Commits
64ee8f4fea
...
devel
| Author | SHA1 | Date | |
|---|---|---|---|
|
a11b2a0568
|
|||
|
ff8e54449a
|
|||
|
64a59e856f
|
|||
|
5e8c5a1631
|
|||
|
e97949cab3
|
|||
|
b7a3608e67
|
|||
|
bbb544c029
|
|||
|
da42f6ed22
|
|||
|
8016e20451
|
@@ -1,2 +0,0 @@
|
||||
VITE_APPWRITE_API_ENDPOINT='http://localhost:4000/api/v1'
|
||||
VITE_APPWRITE_API_PROJECT='65ede55a213134f2b688'
|
||||
@@ -1,2 +0,0 @@
|
||||
VITE_APPWRITE_API_ENDPOINT='https://appwrite.oys.undock.ca/v1'
|
||||
VITE_APPWRITE_API_PROJECT='bab'
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -34,4 +34,4 @@ yarn-error.log*
|
||||
*.sln
|
||||
|
||||
# local .env files
|
||||
.env.local*
|
||||
.env*
|
||||
|
||||
@@ -108,12 +108,19 @@ module.exports = configure(function ({ dev }) {
|
||||
secure: false,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
},
|
||||
'/function': {
|
||||
target: 'https://6640382951eacb568371.f.appwrite.toal.ca/',
|
||||
'/api/v1/realtime': {
|
||||
target: 'wss://apidev.bab.toal.ca',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
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
|
||||
// hmr: {
|
||||
|
||||
@@ -43,7 +43,11 @@ type 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 = {
|
||||
databaseId: '65ee1cbf9c2493faf15f',
|
||||
collection: {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
v-for="block in getAvailableIntervals(
|
||||
scope.timestamp,
|
||||
boats[scope.columnIndex]
|
||||
)"
|
||||
).value"
|
||||
:key="block.$id">
|
||||
<div
|
||||
class="timeblock"
|
||||
@@ -207,7 +207,7 @@ function selectBlock(event: MouseEvent, scope: DayBodyScope, block: Interval) {
|
||||
const boatReservations = computed((): Record<string, Reservation[]> => {
|
||||
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;
|
||||
|
||||
@@ -92,7 +92,7 @@ const currentUser = useAuthStore().currentUser;
|
||||
|
||||
const getSortedIntervals = (timestamp: Timestamp, boat?: Boat): Interval[] => {
|
||||
return getAvailableIntervals(timestamp, boat)
|
||||
.concat(boatReservationEvents(timestamp, boat))
|
||||
.value.concat(boatReservationEvents(timestamp, boat))
|
||||
.sort((a, b) => Date.parse(a.start) - Date.parse(b.start));
|
||||
};
|
||||
// Method declarations
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
class="q-pa-none">
|
||||
<q-card
|
||||
clas="q-ma-md"
|
||||
v-if="!futureUserReservations.length">
|
||||
v-if="!reservationStore.futureUserReservations.length">
|
||||
<q-card-section>
|
||||
<div class="text-h6">You don't have any upcoming bookings!</div>
|
||||
<div class="text-h8">Why don't you go make one?</div>
|
||||
@@ -41,7 +41,7 @@
|
||||
</q-card>
|
||||
<div v-else>
|
||||
<div
|
||||
v-for="reservation in futureUserReservations"
|
||||
v-for="reservation in reservationStore.futureUserReservations"
|
||||
:key="reservation.$id">
|
||||
<ReservationCardComponent :modelValue="reservation" />
|
||||
</div>
|
||||
@@ -51,7 +51,7 @@
|
||||
name="past"
|
||||
class="q-pa-none">
|
||||
<div
|
||||
v-for="reservation in pastUserReservations"
|
||||
v-for="reservation in reservationStore.pastUserReservations"
|
||||
:key="reservation.$id">
|
||||
<ReservationCardComponent :modelValue="reservation" />
|
||||
</div>
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
cell-width="150px">
|
||||
<template #day="{ scope }">
|
||||
<div
|
||||
v-if="filteredIntervals(scope.timestamp, scope.resource).length"
|
||||
v-if="
|
||||
filteredIntervals(scope.timestamp, scope.resource).value.length
|
||||
"
|
||||
style="
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -35,10 +37,8 @@
|
||||
font-size: 12px;
|
||||
">
|
||||
<template
|
||||
v-for="block in sortedIntervals(
|
||||
scope.timestamp,
|
||||
scope.resource
|
||||
)"
|
||||
v-for="block in sortedIntervals(scope.timestamp, scope.resource)
|
||||
.value"
|
||||
:key="block.id">
|
||||
<q-chip class="cursor-pointer">
|
||||
{{ date.formatDate(block.start, 'HH:mm') }} -
|
||||
@@ -163,7 +163,7 @@ import {
|
||||
} from '@quasar/quasar-ui-qcalendar';
|
||||
import { Boat, useBoatStore } from 'src/stores/boat';
|
||||
import { useIntervalStore } from 'src/stores/interval';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import type {
|
||||
Interval,
|
||||
IntervalTemplate,
|
||||
@@ -208,8 +208,10 @@ const filteredIntervals = (date: Timestamp, boat: Boat) => {
|
||||
};
|
||||
|
||||
const sortedIntervals = (date: Timestamp, boat: Boat) => {
|
||||
return filteredIntervals(date, boat).sort(
|
||||
(a, b) => Date.parse(a.start) - Date.parse(b.start)
|
||||
return computed(() =>
|
||||
filteredIntervals(date, boat).value.sort(
|
||||
(a, b) => Date.parse(a.start) - Date.parse(b.start)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -293,7 +295,7 @@ function onDrop(
|
||||
overlapped.value = boatsToApply
|
||||
.map((boat) =>
|
||||
intervalsOverlapped(
|
||||
existingIntervals.concat(
|
||||
existingIntervals.value.concat(
|
||||
intervalsFromTemplate(boat, templateId, date)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -2,25 +2,44 @@ import { defineStore } from 'pinia';
|
||||
import { computed, ref } from 'vue';
|
||||
import { Boat } from './boat';
|
||||
import { Timestamp, today } from '@quasar/quasar-ui-qcalendar';
|
||||
|
||||
import { Interval, IntervalRecord } from './schedule.types';
|
||||
import { Interval } from './schedule.types';
|
||||
import { AppwriteIds, databases } from 'src/boot/appwrite';
|
||||
import { ID, Query } from 'appwrite';
|
||||
import { useReservationStore } from './reservation';
|
||||
import { LoadingTypes } from 'src/utils/misc';
|
||||
import { useRealtimeStore } from './realtime';
|
||||
|
||||
export const useIntervalStore = defineStore('interval', () => {
|
||||
// TODO: Implement functions to dynamically pull this data.
|
||||
const intervals = ref<Map<string, Interval>>(new Map());
|
||||
const intervalDates = ref<IntervalRecord>({});
|
||||
const reservationStore = useReservationStore();
|
||||
const intervals = ref(new Map<string, Interval>()); // Intervals by DocID
|
||||
const dateStatus = ref(new Map<string, LoadingTypes>()); // State of load by date
|
||||
|
||||
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 dayStart = new Date(searchDate + 'T00:00');
|
||||
const dayEnd = new Date(searchDate + 'T23:59');
|
||||
if (!intervalDates.value[searchDate]) {
|
||||
intervalDates.value[searchDate] = 'pending';
|
||||
if (dateStatus.value.get(searchDate) === undefined) {
|
||||
dateStatus.value.set(searchDate, 'pending');
|
||||
fetchIntervals(searchDate);
|
||||
}
|
||||
return computed(() => {
|
||||
@@ -32,22 +51,19 @@ export const useIntervalStore = defineStore('interval', () => {
|
||||
const matchesBoat = boat ? boat.$id === interval.resource : true;
|
||||
return isWithinDay && matchesBoat;
|
||||
});
|
||||
}).value;
|
||||
});
|
||||
};
|
||||
|
||||
const getAvailableIntervals = (
|
||||
date: Timestamp | string,
|
||||
boat?: Boat
|
||||
): Interval[] => {
|
||||
return computed(() => {
|
||||
return getIntervals(date, boat).filter((interval) => {
|
||||
const getAvailableIntervals = (date: Timestamp | string, boat?: Boat) => {
|
||||
return computed(() =>
|
||||
getIntervals(date, boat).value.filter((interval) => {
|
||||
return !reservationStore.isResourceTimeOverlapped(
|
||||
interval.resource,
|
||||
new Date(interval.start),
|
||||
new Date(interval.end)
|
||||
);
|
||||
});
|
||||
}).value;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
async function fetchInterval(id: string): Promise<Interval> {
|
||||
@@ -78,11 +94,11 @@ export const useIntervalStore = defineStore('interval', () => {
|
||||
response.documents.forEach((d) =>
|
||||
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`);
|
||||
} catch (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,
|
||||
deleteInterval,
|
||||
selectedDate,
|
||||
intervals,
|
||||
};
|
||||
});
|
||||
|
||||
21
src/stores/realtime.ts
Normal file
21
src/stores/realtime.ts
Normal 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,
|
||||
};
|
||||
});
|
||||
@@ -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';
|
||||
@@ -8,15 +8,37 @@ import { Timestamp, parseDate, today } from '@quasar/quasar-ui-qcalendar';
|
||||
import { LoadingTypes } from 'src/utils/misc';
|
||||
import { useAuthStore } from './auth';
|
||||
import { isPast } from 'src/utils/schedule';
|
||||
import { useRealtimeStore } from './realtime';
|
||||
|
||||
export const useReservationStore = defineStore('reservation', () => {
|
||||
const reservations = ref<Map<string, Reservation>>(new Map());
|
||||
const datesLoaded = ref<Record<string, LoadingTypes>>({});
|
||||
const userReservations = ref<Map<string, Reservation>>(new Map());
|
||||
// TODO: Come up with a better way of storing reservations by date & reservations for user
|
||||
const reservations = reactive<Map<string, Reservation>>(new Map());
|
||||
const datesLoaded = reactive<Record<string, LoadingTypes>>({});
|
||||
const userReservations = reactive<Map<string, Reservation>>(new Map());
|
||||
|
||||
const authStore = useAuthStore();
|
||||
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
|
||||
const fetchReservationsForDateRange = async (
|
||||
start: string = today(),
|
||||
@@ -40,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) {
|
||||
@@ -81,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) {
|
||||
@@ -95,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',
|
||||
@@ -120,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',
|
||||
@@ -146,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 });
|
||||
}
|
||||
};
|
||||
@@ -157,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;
|
||||
@@ -168,15 +183,15 @@ export const useReservationStore = defineStore('reservation', () => {
|
||||
const getReservationsByDate = (
|
||||
searchDate: string,
|
||||
boat?: string
|
||||
): Reservation[] => {
|
||||
if (!datesLoaded.value[searchDate]) {
|
||||
): ComputedRef<Reservation[]> => {
|
||||
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);
|
||||
|
||||
@@ -185,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
|
||||
@@ -194,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 &&
|
||||
@@ -229,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);
|
||||
@@ -237,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()
|
||||
)
|
||||
);
|
||||
@@ -252,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,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Models } from 'appwrite';
|
||||
import { LoadingTypes } from 'src/utils/misc';
|
||||
|
||||
export type StatusTypes = 'tentative' | 'confirmed' | 'pending' | undefined;
|
||||
export type Reservation = Interval & {
|
||||
@@ -29,7 +28,3 @@ export type IntervalTemplate = Partial<Models.Document> & {
|
||||
name: string;
|
||||
timeTuples: TimeTuple[];
|
||||
};
|
||||
|
||||
export interface IntervalRecord {
|
||||
[key: string]: LoadingTypes;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user