Compare commits
2 Commits
78211a33ae
...
dd631b71bb
| Author | SHA1 | Date | |
|---|---|---|---|
|
dd631b71bb
|
|||
|
b0921ccf32
|
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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)
|
||||||
: [];
|
: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
84
src/stores/reservation.ts
Normal 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,
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -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
11
src/utils/misc.ts
Normal 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user