Many improvements. Still no reactivity on List
This commit is contained in:
@@ -1,18 +1,18 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { Ref, computed, ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { Boat } from './boat';
|
||||
import { Timestamp } from '@quasar/quasar-ui-qcalendar';
|
||||
|
||||
import { IntervalTemplate, Interval, IntervalRecord } from './schedule.types';
|
||||
import { Interval, IntervalRecord } from './schedule.types';
|
||||
import { AppwriteIds, databases } from 'src/boot/appwrite';
|
||||
import { ID, Models, Query } from 'appwrite';
|
||||
import { arrayToTimeTuples } from 'src/utils/schedule';
|
||||
import { ID, Query } from 'appwrite';
|
||||
import { useReservationStore } from './reservation';
|
||||
|
||||
export const useScheduleStore = defineStore('schedule', () => {
|
||||
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 intervalTemplates = ref<IntervalTemplate[]>([]);
|
||||
const reservationStore = useReservationStore();
|
||||
|
||||
const getIntervals = (date: Timestamp | string, boat?: Boat): Interval[] => {
|
||||
const searchDate = typeof date === 'string' ? date : date.date;
|
||||
@@ -28,12 +28,29 @@ export const useScheduleStore = defineStore('schedule', () => {
|
||||
const intervalEnd = new Date(interval.end);
|
||||
|
||||
const isWithinDay = intervalStart < dayEnd && intervalEnd > dayStart;
|
||||
const matchesBoat = boat ? boat.$id === interval.boatId : true;
|
||||
const matchesBoat = boat ? boat.$id === interval.resource : true;
|
||||
return isWithinDay && matchesBoat;
|
||||
});
|
||||
}).value;
|
||||
};
|
||||
|
||||
const getAvailableIntervals = (
|
||||
date: Timestamp | string,
|
||||
boat?: Boat
|
||||
): Interval[] => {
|
||||
return computed(() => {
|
||||
console.log(boat);
|
||||
console.log(getIntervals(date, boat));
|
||||
return getIntervals(date, boat).filter((interval) => {
|
||||
return !reservationStore.isResourceTimeOverlapped(
|
||||
interval.resource,
|
||||
new Date(interval.start),
|
||||
new Date(interval.end)
|
||||
);
|
||||
});
|
||||
}).value;
|
||||
};
|
||||
|
||||
async function fetchIntervals(dateString: string) {
|
||||
try {
|
||||
const response = await databases.listDocuments(
|
||||
@@ -62,31 +79,6 @@ export const useScheduleStore = defineStore('schedule', () => {
|
||||
}
|
||||
}
|
||||
|
||||
const getIntervalTemplates = (): Ref<IntervalTemplate[]> => {
|
||||
// Should subscribe to get new intervaltemplates when they are created
|
||||
if (!intervalTemplates.value) fetchIntervalTemplates();
|
||||
return intervalTemplates;
|
||||
};
|
||||
|
||||
async function fetchIntervalTemplates() {
|
||||
try {
|
||||
const response = await databases.listDocuments(
|
||||
AppwriteIds.databaseId,
|
||||
AppwriteIds.collection.intervalTemplate
|
||||
);
|
||||
intervalTemplates.value = response.documents.map(
|
||||
(d: Models.Document): IntervalTemplate => {
|
||||
return {
|
||||
...d,
|
||||
timeTuples: arrayToTimeTuples(d.timeTuple),
|
||||
} as IntervalTemplate;
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch timeblock templates', error);
|
||||
}
|
||||
}
|
||||
|
||||
const createInterval = async (interval: Interval) => {
|
||||
try {
|
||||
const response = await databases.createDocument(
|
||||
@@ -131,70 +123,13 @@ export const useScheduleStore = defineStore('schedule', () => {
|
||||
console.error('Error deleting Interval: ' + e);
|
||||
}
|
||||
};
|
||||
const createIntervalTemplate = async (template: IntervalTemplate) => {
|
||||
try {
|
||||
const response = await databases.createDocument(
|
||||
AppwriteIds.databaseId,
|
||||
AppwriteIds.collection.intervalTemplate,
|
||||
ID.unique(),
|
||||
{ name: template.name, timeTuple: template.timeTuples.flat(2) }
|
||||
);
|
||||
intervalTemplates.value.push(response as IntervalTemplate);
|
||||
} catch (e) {
|
||||
console.error('Error updating IntervalTemplate: ' + e);
|
||||
}
|
||||
};
|
||||
const deleteIntervalTemplate = async (id: string) => {
|
||||
try {
|
||||
await databases.deleteDocument(
|
||||
AppwriteIds.databaseId,
|
||||
AppwriteIds.collection.intervalTemplate,
|
||||
id
|
||||
);
|
||||
intervalTemplates.value = intervalTemplates.value.filter(
|
||||
(template) => template.$id !== id
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('Error deleting IntervalTemplate: ' + e);
|
||||
}
|
||||
};
|
||||
const updateIntervalTemplate = async (
|
||||
template: IntervalTemplate,
|
||||
id: string
|
||||
) => {
|
||||
try {
|
||||
const response = await databases.updateDocument(
|
||||
AppwriteIds.databaseId,
|
||||
AppwriteIds.collection.intervalTemplate,
|
||||
id,
|
||||
{
|
||||
name: template.name,
|
||||
timeTuple: template.timeTuples.flat(2),
|
||||
}
|
||||
);
|
||||
intervalTemplates.value = intervalTemplates.value.map((b) =>
|
||||
b.$id !== id
|
||||
? b
|
||||
: ({
|
||||
...response,
|
||||
timeTuples: arrayToTimeTuples(response.timeTuple),
|
||||
} as IntervalTemplate)
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('Error updating IntervalTemplate: ' + e);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
getIntervals,
|
||||
getIntervalTemplates,
|
||||
getAvailableIntervals,
|
||||
fetchIntervals,
|
||||
fetchIntervalTemplates,
|
||||
createInterval,
|
||||
updateInterval,
|
||||
deleteInterval,
|
||||
createIntervalTemplate,
|
||||
deleteIntervalTemplate,
|
||||
updateIntervalTemplate,
|
||||
};
|
||||
});
|
||||
97
src/stores/intervalTemplate.ts
Normal file
97
src/stores/intervalTemplate.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Ref, ref } from 'vue';
|
||||
import { IntervalTemplate } from './schedule.types';
|
||||
import { defineStore } from 'pinia';
|
||||
import { AppwriteIds, databases } from 'src/boot/appwrite';
|
||||
import { ID, Models } from 'appwrite';
|
||||
import { arrayToTimeTuples } from 'src/utils/schedule';
|
||||
|
||||
export const useIntervalTemplateStore = defineStore('intervalTemplate', () => {
|
||||
const intervalTemplates = ref<IntervalTemplate[]>([]);
|
||||
|
||||
const getIntervalTemplates = (): Ref<IntervalTemplate[]> => {
|
||||
// Should subscribe to get new intervaltemplates when they are created
|
||||
if (!intervalTemplates.value) fetchIntervalTemplates();
|
||||
return intervalTemplates;
|
||||
};
|
||||
|
||||
async function fetchIntervalTemplates() {
|
||||
try {
|
||||
const response = await databases.listDocuments(
|
||||
AppwriteIds.databaseId,
|
||||
AppwriteIds.collection.intervalTemplate
|
||||
);
|
||||
intervalTemplates.value = response.documents.map(
|
||||
(d: Models.Document): IntervalTemplate => {
|
||||
return {
|
||||
...d,
|
||||
timeTuples: arrayToTimeTuples(d.timeTuple),
|
||||
} as IntervalTemplate;
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch timeblock templates', error);
|
||||
}
|
||||
}
|
||||
|
||||
const createIntervalTemplate = async (template: IntervalTemplate) => {
|
||||
try {
|
||||
const response = await databases.createDocument(
|
||||
AppwriteIds.databaseId,
|
||||
AppwriteIds.collection.intervalTemplate,
|
||||
ID.unique(),
|
||||
{ name: template.name, timeTuple: template.timeTuples.flat(2) }
|
||||
);
|
||||
intervalTemplates.value.push(response as IntervalTemplate);
|
||||
} catch (e) {
|
||||
console.error('Error updating IntervalTemplate: ' + e);
|
||||
}
|
||||
};
|
||||
const deleteIntervalTemplate = async (id: string) => {
|
||||
try {
|
||||
await databases.deleteDocument(
|
||||
AppwriteIds.databaseId,
|
||||
AppwriteIds.collection.intervalTemplate,
|
||||
id
|
||||
);
|
||||
intervalTemplates.value = intervalTemplates.value.filter(
|
||||
(template) => template.$id !== id
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('Error deleting IntervalTemplate: ' + e);
|
||||
}
|
||||
};
|
||||
const updateIntervalTemplate = async (
|
||||
template: IntervalTemplate,
|
||||
id: string
|
||||
) => {
|
||||
try {
|
||||
const response = await databases.updateDocument(
|
||||
AppwriteIds.databaseId,
|
||||
AppwriteIds.collection.intervalTemplate,
|
||||
id,
|
||||
{
|
||||
name: template.name,
|
||||
timeTuple: template.timeTuples.flat(2),
|
||||
}
|
||||
);
|
||||
intervalTemplates.value = intervalTemplates.value.map((b) =>
|
||||
b.$id !== id
|
||||
? b
|
||||
: ({
|
||||
...response,
|
||||
timeTuples: arrayToTimeTuples(response.timeTuple),
|
||||
} as IntervalTemplate)
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('Error updating IntervalTemplate: ' + e);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
getIntervalTemplates,
|
||||
fetchIntervalTemplates,
|
||||
createIntervalTemplate,
|
||||
deleteIntervalTemplate,
|
||||
updateIntervalTemplate,
|
||||
};
|
||||
});
|
||||
@@ -3,7 +3,7 @@ import type { Reservation } from './schedule.types';
|
||||
import { computed, ref } from 'vue';
|
||||
import { AppwriteIds, databases } from 'src/boot/appwrite';
|
||||
import { ID, Query } from 'appwrite';
|
||||
import { date } from 'quasar';
|
||||
import { date, useQuasar } from 'quasar';
|
||||
import { Timestamp, parseDate, today } from '@quasar/quasar-ui-qcalendar';
|
||||
import { LoadingTypes } from 'src/utils/misc';
|
||||
import { useAuthStore } from './auth';
|
||||
@@ -15,6 +15,7 @@ export const useReservationStore = defineStore('reservation', () => {
|
||||
const userReservations = ref<Map<string, Reservation>>(new Map());
|
||||
// TODO: Come up with a better way of storing reservations by date & reservations for user
|
||||
const authStore = useAuthStore();
|
||||
const $q = useQuasar();
|
||||
|
||||
// Fetch reservations for a specific date range
|
||||
const fetchReservationsForDateRange = async (
|
||||
@@ -60,7 +61,9 @@ export const useReservationStore = defineStore('reservation', () => {
|
||||
}
|
||||
};
|
||||
|
||||
const createReservation = async (reservation: Reservation) => {
|
||||
const createReservation = async (
|
||||
reservation: Reservation
|
||||
): Promise<Reservation> => {
|
||||
try {
|
||||
const response = await databases.createDocument(
|
||||
AppwriteIds.databaseId,
|
||||
@@ -70,8 +73,10 @@ export const useReservationStore = defineStore('reservation', () => {
|
||||
);
|
||||
reservations.value.set(response.$id, response as Reservation);
|
||||
console.info('Reservation booked: ', response);
|
||||
return response as Reservation;
|
||||
} catch (e) {
|
||||
console.error('Error creating Reservation: ' + e);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -88,6 +93,16 @@ export const useReservationStore = defineStore('reservation', () => {
|
||||
return false;
|
||||
}
|
||||
|
||||
const status = $q.notify({
|
||||
color: 'secondary',
|
||||
textColor: 'white',
|
||||
message: 'Deleting Reservation',
|
||||
spinner: true,
|
||||
closeBtn: 'Dismiss',
|
||||
position: 'top',
|
||||
timeout: 0,
|
||||
group: false,
|
||||
});
|
||||
try {
|
||||
await databases.deleteDocument(
|
||||
AppwriteIds.databaseId,
|
||||
@@ -97,8 +112,21 @@ export const useReservationStore = defineStore('reservation', () => {
|
||||
reservations.value.delete(id);
|
||||
userReservations.value.delete(id);
|
||||
console.info(`Deleted reservation: ${id}`);
|
||||
status({
|
||||
color: 'warning',
|
||||
message: 'Reservation Deleted',
|
||||
spinner: false,
|
||||
icon: 'delete',
|
||||
timeout: 4000,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Error deleting reservation: ' + e);
|
||||
status({
|
||||
color: 'negative',
|
||||
message: 'Failed to Delete Reservation',
|
||||
spinner: false,
|
||||
icon: 'error',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -197,7 +225,7 @@ export const useReservationStore = defineStore('reservation', () => {
|
||||
}
|
||||
};
|
||||
|
||||
const sortedUserReservations = computed(() =>
|
||||
const sortedUserReservations = computed((): Reservation[] =>
|
||||
[...userReservations.value?.values()].sort(
|
||||
(a, b) => new Date(b.start).getTime() - new Date(a.start).getTime()
|
||||
)
|
||||
|
||||
@@ -50,7 +50,7 @@ export function getSampleIntervals(): Interval[] {
|
||||
return template.blocks.map((t: TimeTuple): Interval => {
|
||||
return {
|
||||
$id: 'id' + Math.random().toString(32).slice(2),
|
||||
boatId: b.$id,
|
||||
resource: b.$id,
|
||||
start: addToDate(tsToday, { day: i }).date + ' ' + t[0],
|
||||
end: addToDate(tsToday, { day: i }).date + ' ' + t[1],
|
||||
};
|
||||
|
||||
@@ -2,11 +2,8 @@ import { Models } from 'appwrite';
|
||||
import { LoadingTypes } from 'src/utils/misc';
|
||||
|
||||
export type StatusTypes = 'tentative' | 'confirmed' | 'pending' | undefined;
|
||||
export type Reservation = Partial<Models.Document> & {
|
||||
export type Reservation = Interval & {
|
||||
user: string;
|
||||
start: string;
|
||||
end: string;
|
||||
resource: string; // Boat ID
|
||||
status?: StatusTypes;
|
||||
reason: string;
|
||||
comment: string;
|
||||
@@ -21,11 +18,11 @@ export type Reservation = Partial<Models.Document> & {
|
||||
objects in here? */
|
||||
|
||||
export type TimeTuple = [start: string, end: string];
|
||||
|
||||
export type Interval = Partial<Models.Document> & {
|
||||
boatId: string;
|
||||
resource: string;
|
||||
start: string;
|
||||
end: string;
|
||||
selected?: false;
|
||||
};
|
||||
|
||||
export type IntervalTemplate = Partial<Models.Document> & {
|
||||
|
||||
Reference in New Issue
Block a user