Update naming
This commit is contained in:
2
.env.production
Normal file
2
.env.production
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
APPWRITE_API_ENDPOINT='https://appwrite.oys.undock.ca/v1'
|
||||||
|
APPWRITE_API_PROJECT='bab'
|
||||||
@@ -17,20 +17,45 @@ if (process.env.APPWRITE_API_ENDPOINT && process.env.APPWRITE_API_PROJECT)
|
|||||||
client
|
client
|
||||||
.setEndpoint(process.env.APPWRITE_API_ENDPOINT)
|
.setEndpoint(process.env.APPWRITE_API_ENDPOINT)
|
||||||
.setProject(process.env.APPWRITE_API_PROJECT);
|
.setProject(process.env.APPWRITE_API_PROJECT);
|
||||||
|
else if (process.env.DEV) {
|
||||||
|
client
|
||||||
|
.setEndpoint('http://localhost:4000/api/v1')
|
||||||
|
.setProject('65ede55a213134f2b688');
|
||||||
|
} else {
|
||||||
|
client.setEndpoint('https://appwrite.oys.undock.ca/v1').setProject('bab');
|
||||||
|
}
|
||||||
//TODO move this to config file
|
//TODO move this to config file
|
||||||
const AppwriteIds = {
|
const AppwriteIds = process.env.DEV
|
||||||
databaseId: '65ee1cbf9c2493faf15f',
|
? {
|
||||||
collection: {
|
databaseId: '65ee1cbf9c2493faf15f',
|
||||||
boat: '66341910003e287cd71c',
|
collection: {
|
||||||
reservation: '663f8847000b8f5e29bb',
|
boat: '66341910003e287cd71c',
|
||||||
skillTags: '66072582a74d94a4bd01',
|
reservation: '663f8847000b8f5e29bb',
|
||||||
task: '65ee1cd5b550023fae4f',
|
skillTags: '66072582a74d94a4bd01',
|
||||||
taskTags: '65ee21d72d5c8007c34c',
|
task: '65ee1cd5b550023fae4f',
|
||||||
timeBlock: '66361869002883fb4c4b',
|
taskTags: '65ee21d72d5c8007c34c',
|
||||||
timeBlockTemplate: '66361f480007fdd639af',
|
interval: '66361869002883fb4c4b',
|
||||||
},
|
intervalTemplate: '66361f480007fdd639af',
|
||||||
};
|
},
|
||||||
|
function: {
|
||||||
|
userinfo: 'userinfo',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
databaseId: 'bab_prod',
|
||||||
|
collection: {
|
||||||
|
boat: 'boat',
|
||||||
|
reservation: 'reservation',
|
||||||
|
skillTags: 'skillTags',
|
||||||
|
task: 'task',
|
||||||
|
taskTags: 'taskTags',
|
||||||
|
interval: 'interval',
|
||||||
|
intervalTemplate: 'intervalTemplate',
|
||||||
|
},
|
||||||
|
function: {
|
||||||
|
userinfo: '664038294b5473ef0c8d',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const account = new Account(client);
|
const account = new Account(client);
|
||||||
const databases = new Databases(client);
|
const databases = new Databases(client);
|
||||||
|
|||||||
@@ -113,12 +113,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {
|
import { useScheduleStore } from 'src/stores/schedule';
|
||||||
copyIntervalTemplate,
|
|
||||||
timeTuplesOverlapped,
|
|
||||||
useScheduleStore,
|
|
||||||
} from 'src/stores/schedule';
|
|
||||||
import { IntervalTemplate } from 'src/stores/schedule.types';
|
import { IntervalTemplate } from 'src/stores/schedule.types';
|
||||||
|
import { copyIntervalTemplate, timeTuplesOverlapped } from 'src/utils/schedule';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
const alert = ref(false);
|
const alert = ref(false);
|
||||||
const overlapped = ref();
|
const overlapped = ref();
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ const calendar = ref<QCalendarDay | null>(null);
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await useBoatStore().fetchBoats();
|
await useBoatStore().fetchBoats();
|
||||||
await scheduleStore.fetchIntervals();
|
|
||||||
await scheduleStore.fetchIntervalTemplates();
|
await scheduleStore.fetchIntervalTemplates();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -177,7 +176,7 @@ function selectBlock(event: MouseEvent, scope: DayBodyScope, block: Interval) {
|
|||||||
|
|
||||||
const boatBlocks = computed((): Record<string, Interval[]> => {
|
const boatBlocks = computed((): Record<string, Interval[]> => {
|
||||||
return scheduleStore
|
return scheduleStore
|
||||||
.getIntervalsForDate(selectedDate.value)
|
.getIntervals(selectedDate.value)
|
||||||
.reduce((result, interval) => {
|
.reduce((result, interval) => {
|
||||||
if (!result[interval.boatId]) result[interval.boatId] = [];
|
if (!result[interval.boatId]) result[interval.boatId] = [];
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -113,7 +113,7 @@
|
|||||||
/></q-item>
|
/></q-item>
|
||||||
<q-separator spaced />
|
<q-separator spaced />
|
||||||
<IntervalTemplateComponent
|
<IntervalTemplateComponent
|
||||||
v-for="template in timeblockTemplates"
|
v-for="template in intervalTemplates"
|
||||||
:key="template.$id"
|
:key="template.$id"
|
||||||
:model-value="template"
|
:model-value="template"
|
||||||
/>
|
/>
|
||||||
@@ -146,11 +146,7 @@ import {
|
|||||||
today,
|
today,
|
||||||
} 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 {
|
import { useScheduleStore } from 'src/stores/schedule';
|
||||||
blocksOverlapped,
|
|
||||||
buildInterval,
|
|
||||||
useScheduleStore,
|
|
||||||
} from 'src/stores/schedule';
|
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import type {
|
import type {
|
||||||
Interval,
|
Interval,
|
||||||
@@ -161,12 +157,13 @@ import { date } from 'quasar';
|
|||||||
import IntervalTemplateComponent from 'src/components/scheduling/IntervalTemplateComponent.vue';
|
import IntervalTemplateComponent from 'src/components/scheduling/IntervalTemplateComponent.vue';
|
||||||
import NavigationBar from 'src/components/scheduling/NavigationBar.vue';
|
import NavigationBar from 'src/components/scheduling/NavigationBar.vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { buildInterval, intervalsOverlapped } from 'src/utils/schedule';
|
||||||
|
|
||||||
const selectedDate = ref(today());
|
const selectedDate = ref(today());
|
||||||
const { fetchBoats } = useBoatStore();
|
const { fetchBoats } = useBoatStore();
|
||||||
const scheduleStore = useScheduleStore();
|
const scheduleStore = useScheduleStore();
|
||||||
const { boats } = storeToRefs(useBoatStore());
|
const { boats } = storeToRefs(useBoatStore());
|
||||||
const { timeblockTemplates } = storeToRefs(useScheduleStore());
|
const intervalTemplates = scheduleStore.getIntervalTemplates();
|
||||||
const calendar = ref();
|
const calendar = ref();
|
||||||
const overlapped = ref();
|
const overlapped = ref();
|
||||||
const alert = ref(false);
|
const alert = ref(false);
|
||||||
@@ -185,12 +182,11 @@ const newTemplate = ref<IntervalTemplate>({
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchBoats();
|
await fetchBoats();
|
||||||
await scheduleStore.fetchIntervals();
|
|
||||||
await scheduleStore.fetchIntervalTemplates();
|
await scheduleStore.fetchIntervalTemplates();
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredIntervals = (date: Timestamp, boat: Boat) => {
|
const filteredIntervals = (date: Timestamp, boat: Boat) => {
|
||||||
return scheduleStore.getIntervals(date, boat).value;
|
return scheduleStore.getIntervals(date, boat);
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortedIntervals = (date: Timestamp, boat: Boat) => {
|
const sortedIntervals = (date: Timestamp, boat: Boat) => {
|
||||||
@@ -210,7 +206,7 @@ function createTemplate() {
|
|||||||
newTemplate.value.$id = 'unsaved';
|
newTemplate.value.$id = 'unsaved';
|
||||||
}
|
}
|
||||||
function createIntervals(boat: Boat, templateId: string, date: string) {
|
function createIntervals(boat: Boat, templateId: string, date: string) {
|
||||||
const intervals = timeBlocksFromTemplate(boat, templateId, date);
|
const intervals = intervalsFromTemplate(boat, templateId, date);
|
||||||
intervals.forEach((interval) => scheduleStore.createInterval(interval));
|
intervals.forEach((interval) => scheduleStore.createInterval(interval));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,12 +214,14 @@ function getIntervals(date: Timestamp, boat: Boat) {
|
|||||||
return scheduleStore.getIntervals(date, boat);
|
return scheduleStore.getIntervals(date, boat);
|
||||||
}
|
}
|
||||||
|
|
||||||
function timeBlocksFromTemplate(
|
function intervalsFromTemplate(
|
||||||
boat: Boat,
|
boat: Boat,
|
||||||
templateId: string,
|
templateId: string,
|
||||||
date: string
|
date: string
|
||||||
): Interval[] {
|
): Interval[] {
|
||||||
const template = timeblockTemplates.value.find((t) => t.$id === templateId);
|
const template = scheduleStore
|
||||||
|
.getIntervalTemplates()
|
||||||
|
.value.find((t) => t.$id === templateId);
|
||||||
return template
|
return template
|
||||||
? template.timeTuples.map((timeTuple: TimeTuple) =>
|
? template.timeTuples.map((timeTuple: TimeTuple) =>
|
||||||
buildInterval(boat, timeTuple, date)
|
buildInterval(boat, timeTuple, date)
|
||||||
@@ -280,13 +278,13 @@ function onDrop(
|
|||||||
const templateId = e.dataTransfer.getData('ID');
|
const templateId = e.dataTransfer.getData('ID');
|
||||||
const date = scope.timestamp.date;
|
const date = scope.timestamp.date;
|
||||||
const resource = scope.resource;
|
const resource = scope.resource;
|
||||||
const existingIntervals = getIntervals(scope.timestamp, resource).value;
|
const existingIntervals = getIntervals(scope.timestamp, resource);
|
||||||
const boatsToApply = type === 'head-day' ? boats.value : [resource];
|
const boatsToApply = type === 'head-day' ? boats.value : [resource];
|
||||||
overlapped.value = boatsToApply
|
overlapped.value = boatsToApply
|
||||||
.map((boat) =>
|
.map((boat) =>
|
||||||
blocksOverlapped(
|
intervalsOverlapped(
|
||||||
existingIntervals.concat(
|
existingIntervals.concat(
|
||||||
timeBlocksFromTemplate(boat, templateId, date)
|
intervalsFromTemplate(boat, templateId, date)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
userNames.value[id] = '';
|
userNames.value[id] = '';
|
||||||
functions
|
functions
|
||||||
.createExecution(
|
.createExecution(
|
||||||
'664038294b5473ef0c8d',
|
'userinfo',
|
||||||
'',
|
'',
|
||||||
false,
|
false,
|
||||||
'/userinfo/' + id,
|
'/userinfo/' + id,
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { AppwriteIds, databases } from 'src/boot/appwrite';
|
|||||||
import { ID, Query } from 'appwrite';
|
import { ID, Query } from 'appwrite';
|
||||||
import { date } from 'quasar';
|
import { date } from 'quasar';
|
||||||
import { Timestamp, parseDate, today } from '@quasar/quasar-ui-qcalendar';
|
import { Timestamp, parseDate, today } from '@quasar/quasar-ui-qcalendar';
|
||||||
|
import { LoadingTypes } from 'src/utils/misc';
|
||||||
|
|
||||||
export const useReservationStore = defineStore('reservation', () => {
|
export const useReservationStore = defineStore('reservation', () => {
|
||||||
type LoadingTypes = 'loaded' | 'pending' | undefined;
|
|
||||||
const reservations = ref<Map<string, Reservation>>(new Map());
|
const reservations = ref<Map<string, Reservation>>(new Map());
|
||||||
const datesLoaded = ref<Record<string, LoadingTypes>>({});
|
const datesLoaded = ref<Record<string, LoadingTypes>>({});
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ export const useReservationStore = defineStore('reservation', () => {
|
|||||||
setDateLoaded(startDate, endDate, 'loaded');
|
setDateLoaded(startDate, endDate, 'loaded');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch reservations', error);
|
console.error('Failed to fetch reservations', error);
|
||||||
setDateLoaded(startDate, endDate, undefined);
|
setDateLoaded(startDate, endDate, 'error');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const createReservation = async (reservation: Reservation) => {
|
const createReservation = async (reservation: Reservation) => {
|
||||||
|
|||||||
@@ -1,127 +1,78 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { ComputedRef, computed, ref } from 'vue';
|
import { Ref, computed, ref } from 'vue';
|
||||||
import { Boat } from './boat';
|
import { Boat } from './boat';
|
||||||
import {
|
import { Timestamp } from '@quasar/quasar-ui-qcalendar';
|
||||||
Timestamp,
|
|
||||||
parseDate,
|
|
||||||
parsed,
|
|
||||||
compareDate,
|
|
||||||
} from '@quasar/quasar-ui-qcalendar';
|
|
||||||
|
|
||||||
import { IntervalTemplate, TimeTuple, Interval } from './schedule.types';
|
import { IntervalTemplate, Interval, IntervalRecord } 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, Query } from 'appwrite';
|
||||||
|
import { arrayToTimeTuples } from 'src/utils/schedule';
|
||||||
export function arrayToTimeTuples(arr: string[]) {
|
|
||||||
const timeTuples: TimeTuple[] = [];
|
|
||||||
for (let i = 0; i < arr.length; i += 2) {
|
|
||||||
timeTuples.push([arr[i], arr[i + 1]]);
|
|
||||||
}
|
|
||||||
return timeTuples;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function timeTuplesOverlapped(tuples: TimeTuple[]): Interval[] {
|
|
||||||
return blocksOverlapped(
|
|
||||||
tuples.map((tuples) => {
|
|
||||||
return {
|
|
||||||
boatId: '',
|
|
||||||
start: '01/01/2001 ' + tuples[0],
|
|
||||||
end: '01/01/2001 ' + tuples[1],
|
|
||||||
};
|
|
||||||
})
|
|
||||||
).map((t) => {
|
|
||||||
return { ...t, start: t.start.split(' ')[1], end: t.end.split(' ')[1] };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function blocksOverlapped(blocks: Interval[] | Interval[]): Interval[] {
|
|
||||||
return Array.from(
|
|
||||||
new Set(
|
|
||||||
blocks
|
|
||||||
.sort((a, b) => Date.parse(a.start) - Date.parse(b.start))
|
|
||||||
.reduce((acc: Interval[], block, i, arr) => {
|
|
||||||
if (i > 0 && block.start < arr[i - 1].end)
|
|
||||||
acc.push(arr[i - 1], block);
|
|
||||||
return acc;
|
|
||||||
}, [])
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function copyTimeTuples(tuples: TimeTuple[]): TimeTuple[] {
|
|
||||||
return tuples.map((t) => Object.assign([], t));
|
|
||||||
}
|
|
||||||
export function copyIntervalTemplate(
|
|
||||||
template: IntervalTemplate
|
|
||||||
): IntervalTemplate {
|
|
||||||
return {
|
|
||||||
...template,
|
|
||||||
timeTuples: copyTimeTuples(template.timeTuples || []),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildInterval(
|
|
||||||
resource: Boat,
|
|
||||||
time: TimeTuple,
|
|
||||||
blockDate: string
|
|
||||||
): Interval {
|
|
||||||
/* When the time zone offset is absent, date-only forms are interpreted
|
|
||||||
as a UTC time and date-time forms are interpreted as local time. */
|
|
||||||
const result = {
|
|
||||||
boatId: resource.$id,
|
|
||||||
start: new Date(blockDate + 'T' + time[0]).toISOString(),
|
|
||||||
end: new Date(blockDate + 'T' + time[1]).toISOString(),
|
|
||||||
};
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 intervals = ref<Interval[]>([]);
|
const intervals = ref<Map<string, Interval>>(new Map());
|
||||||
|
const intervalDates = ref<IntervalRecord>({});
|
||||||
const intervalTemplates = ref<IntervalTemplate[]>([]);
|
const intervalTemplates = ref<IntervalTemplate[]>([]);
|
||||||
|
|
||||||
const getIntervals = (
|
const getIntervals = (date: Timestamp | string, boat?: Boat): Interval[] => {
|
||||||
date: Timestamp,
|
const searchDate = typeof date === 'string' ? date : date.date;
|
||||||
boat: Boat
|
const dayStart = new Date(searchDate + 'T00:00');
|
||||||
): ComputedRef<Interval[]> => {
|
const dayEnd = new Date(searchDate + 'T23:59');
|
||||||
return computed(() =>
|
if (!intervalDates.value[searchDate]) {
|
||||||
intervals.value.filter((block) => {
|
intervalDates.value[searchDate] = 'pending';
|
||||||
return (
|
fetchIntervals(searchDate);
|
||||||
compareDate(parseDate(new Date(block.start)) as Timestamp, date) &&
|
}
|
||||||
block.boatId === boat.$id
|
return computed(() => {
|
||||||
);
|
return Array.from(intervals.value.values()).filter((interval) => {
|
||||||
})
|
const intervalStart = new Date(interval.start);
|
||||||
);
|
const intervalEnd = new Date(interval.end);
|
||||||
|
|
||||||
|
const isWithinDay = intervalStart < dayEnd && intervalEnd > dayStart;
|
||||||
|
const matchesBoat = boat ? boat.$id === interval.boatId : true;
|
||||||
|
return isWithinDay && matchesBoat;
|
||||||
|
});
|
||||||
|
}).value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getIntervalsForDate = (date: string): Interval[] => {
|
async function fetchIntervals(dateString: string) {
|
||||||
// TODO: This needs to actually make sure we have the dates we need, stay in sync, etc.
|
|
||||||
|
|
||||||
return intervals.value.filter((b) => {
|
|
||||||
return compareDate(
|
|
||||||
parseDate(new Date(b.start)) as Timestamp,
|
|
||||||
parsed(date) as Timestamp
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
async function fetchIntervals() {
|
|
||||||
try {
|
try {
|
||||||
const response = await databases.listDocuments(
|
const response = await databases.listDocuments(
|
||||||
AppwriteIds.databaseId,
|
AppwriteIds.databaseId,
|
||||||
AppwriteIds.collection.timeBlock
|
AppwriteIds.collection.interval,
|
||||||
|
[
|
||||||
|
Query.greaterThanEqual(
|
||||||
|
'end',
|
||||||
|
new Date(dateString + 'T00:00').toISOString()
|
||||||
|
),
|
||||||
|
Query.lessThanEqual(
|
||||||
|
'start',
|
||||||
|
new Date(dateString + 'T23:59').toISOString()
|
||||||
|
),
|
||||||
|
Query.limit(50), // We are asuming that we won't have more than 50 intervals per day.
|
||||||
|
]
|
||||||
);
|
);
|
||||||
intervals.value = response.documents as Interval[];
|
response.documents.forEach((d) =>
|
||||||
|
intervals.value.set(d.$id, d as Interval)
|
||||||
|
);
|
||||||
|
intervalDates.value[dateString] = 'loaded';
|
||||||
|
console.info(`Loaded ${response.documents.length} intervals from server`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch timeblocks', error);
|
console.error('Failed to fetch intervals', error);
|
||||||
|
intervalDates.value[dateString] = 'error';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getIntervalTemplates = (): Ref<IntervalTemplate[]> => {
|
||||||
|
// Should subscribe to get new intervaltemplates when they are created
|
||||||
|
if (!intervalTemplates.value) fetchIntervalTemplates();
|
||||||
|
return intervalTemplates;
|
||||||
|
};
|
||||||
|
|
||||||
async function fetchIntervalTemplates() {
|
async function fetchIntervalTemplates() {
|
||||||
try {
|
try {
|
||||||
const response = await databases.listDocuments(
|
const response = await databases.listDocuments(
|
||||||
AppwriteIds.databaseId,
|
AppwriteIds.databaseId,
|
||||||
AppwriteIds.collection.timeBlockTemplate
|
AppwriteIds.collection.intervalTemplate
|
||||||
);
|
);
|
||||||
intervalTemplates.value = response.documents.map(
|
intervalTemplates.value = response.documents.map(
|
||||||
(d: Models.Document): IntervalTemplate => {
|
(d: Models.Document): IntervalTemplate => {
|
||||||
@@ -140,11 +91,11 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
try {
|
try {
|
||||||
const response = await databases.createDocument(
|
const response = await databases.createDocument(
|
||||||
AppwriteIds.databaseId,
|
AppwriteIds.databaseId,
|
||||||
AppwriteIds.collection.timeBlock,
|
AppwriteIds.collection.interval,
|
||||||
ID.unique(),
|
ID.unique(),
|
||||||
interval
|
interval
|
||||||
);
|
);
|
||||||
intervals.value.push(response as Interval);
|
intervals.value.set(response.$id, response as Interval);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error creating Interval: ' + e);
|
console.error('Error creating Interval: ' + e);
|
||||||
}
|
}
|
||||||
@@ -154,12 +105,12 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
if (interval.$id) {
|
if (interval.$id) {
|
||||||
const response = await databases.updateDocument(
|
const response = await databases.updateDocument(
|
||||||
AppwriteIds.databaseId,
|
AppwriteIds.databaseId,
|
||||||
AppwriteIds.collection.timeBlock,
|
AppwriteIds.collection.interval,
|
||||||
interval.$id,
|
interval.$id,
|
||||||
{ ...interval, $id: undefined }
|
{ ...interval, $id: undefined }
|
||||||
);
|
);
|
||||||
intervals.value.push(response as Interval);
|
intervals.value.set(response.$id, response as Interval);
|
||||||
console.log(`Saved Interval: ${interval.$id}`);
|
console.info(`Saved Interval: ${interval.$id}`);
|
||||||
} else {
|
} else {
|
||||||
console.error('Update interval called without an ID');
|
console.error('Update interval called without an ID');
|
||||||
}
|
}
|
||||||
@@ -171,10 +122,11 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
try {
|
try {
|
||||||
await databases.deleteDocument(
|
await databases.deleteDocument(
|
||||||
AppwriteIds.databaseId,
|
AppwriteIds.databaseId,
|
||||||
AppwriteIds.collection.timeBlock,
|
AppwriteIds.collection.interval,
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
intervals.value = intervals.value.filter((block) => block.$id !== id);
|
intervals.value.delete(id);
|
||||||
|
console.info(`Deleted interval: ${id}`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error deleting Interval: ' + e);
|
console.error('Error deleting Interval: ' + e);
|
||||||
}
|
}
|
||||||
@@ -183,7 +135,7 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
try {
|
try {
|
||||||
const response = await databases.createDocument(
|
const response = await databases.createDocument(
|
||||||
AppwriteIds.databaseId,
|
AppwriteIds.databaseId,
|
||||||
AppwriteIds.collection.timeBlockTemplate,
|
AppwriteIds.collection.intervalTemplate,
|
||||||
ID.unique(),
|
ID.unique(),
|
||||||
{ name: template.name, timeTuple: template.timeTuples.flat(2) }
|
{ name: template.name, timeTuple: template.timeTuples.flat(2) }
|
||||||
);
|
);
|
||||||
@@ -196,7 +148,7 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
try {
|
try {
|
||||||
await databases.deleteDocument(
|
await databases.deleteDocument(
|
||||||
AppwriteIds.databaseId,
|
AppwriteIds.databaseId,
|
||||||
AppwriteIds.collection.timeBlockTemplate,
|
AppwriteIds.collection.intervalTemplate,
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
intervalTemplates.value = intervalTemplates.value.filter(
|
intervalTemplates.value = intervalTemplates.value.filter(
|
||||||
@@ -213,7 +165,7 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
try {
|
try {
|
||||||
const response = await databases.updateDocument(
|
const response = await databases.updateDocument(
|
||||||
AppwriteIds.databaseId,
|
AppwriteIds.databaseId,
|
||||||
AppwriteIds.collection.timeBlockTemplate,
|
AppwriteIds.collection.intervalTemplate,
|
||||||
id,
|
id,
|
||||||
{
|
{
|
||||||
name: template.name,
|
name: template.name,
|
||||||
@@ -234,10 +186,8 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
timeblocks: intervals,
|
|
||||||
timeblockTemplates: intervalTemplates,
|
|
||||||
getIntervalsForDate,
|
|
||||||
getIntervals,
|
getIntervals,
|
||||||
|
getIntervalTemplates,
|
||||||
fetchIntervals,
|
fetchIntervals,
|
||||||
fetchIntervalTemplates,
|
fetchIntervalTemplates,
|
||||||
createInterval,
|
createInterval,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
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 = Partial<Models.Document> & {
|
export type Reservation = Partial<Models.Document> & {
|
||||||
@@ -27,3 +28,7 @@ export type IntervalTemplate = Partial<Models.Document> & {
|
|||||||
name: string;
|
name: string;
|
||||||
timeTuples: TimeTuple[];
|
timeTuples: TimeTuple[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface IntervalRecord {
|
||||||
|
[key: string]: LoadingTypes;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,3 +5,5 @@ export function getNewId(): string {
|
|||||||
// Trivial placeholder
|
// Trivial placeholder
|
||||||
//return Math.max(...reservations.value.map((item) => item.id)) + 1;
|
//return Math.max(...reservations.value.map((item) => item.id)) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type LoadingTypes = 'loaded' | 'pending' | 'error' | undefined;
|
||||||
|
|||||||
71
src/utils/schedule.ts
Normal file
71
src/utils/schedule.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { Boat } from 'src/stores/boat';
|
||||||
|
import {
|
||||||
|
Interval,
|
||||||
|
IntervalTemplate,
|
||||||
|
TimeTuple,
|
||||||
|
} from 'src/stores/schedule.types';
|
||||||
|
|
||||||
|
export function arrayToTimeTuples(arr: string[]) {
|
||||||
|
const timeTuples: TimeTuple[] = [];
|
||||||
|
for (let i = 0; i < arr.length; i += 2) {
|
||||||
|
timeTuples.push([arr[i], arr[i + 1]]);
|
||||||
|
}
|
||||||
|
return timeTuples;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function timeTuplesOverlapped(tuples: TimeTuple[]): Interval[] {
|
||||||
|
return intervalsOverlapped(
|
||||||
|
tuples.map((tuples) => {
|
||||||
|
return {
|
||||||
|
boatId: '',
|
||||||
|
start: '01/01/2001 ' + tuples[0],
|
||||||
|
end: '01/01/2001 ' + tuples[1],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
).map((t) => {
|
||||||
|
return { ...t, start: t.start.split(' ')[1], end: t.end.split(' ')[1] };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function intervalsOverlapped(
|
||||||
|
blocks: Interval[] | Interval[]
|
||||||
|
): Interval[] {
|
||||||
|
return Array.from(
|
||||||
|
new Set(
|
||||||
|
blocks
|
||||||
|
.sort((a, b) => Date.parse(a.start) - Date.parse(b.start))
|
||||||
|
.reduce((acc: Interval[], block, i, arr) => {
|
||||||
|
if (i > 0 && block.start < arr[i - 1].end)
|
||||||
|
acc.push(arr[i - 1], block);
|
||||||
|
return acc;
|
||||||
|
}, [])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function copyTimeTuples(tuples: TimeTuple[]): TimeTuple[] {
|
||||||
|
return tuples.map((t) => Object.assign([], t));
|
||||||
|
}
|
||||||
|
export function copyIntervalTemplate(
|
||||||
|
template: IntervalTemplate
|
||||||
|
): IntervalTemplate {
|
||||||
|
return {
|
||||||
|
...template,
|
||||||
|
timeTuples: copyTimeTuples(template.timeTuples || []),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildInterval(
|
||||||
|
resource: Boat,
|
||||||
|
time: TimeTuple,
|
||||||
|
blockDate: string
|
||||||
|
): Interval {
|
||||||
|
/* When the time zone offset is absent, date-only forms are interpreted
|
||||||
|
as a UTC time and date-time forms are interpreted as local time. */
|
||||||
|
const result = {
|
||||||
|
boatId: resource.$id,
|
||||||
|
start: new Date(blockDate + 'T' + time[0]).toISOString(),
|
||||||
|
end: new Date(blockDate + 'T' + time[1]).toISOString(),
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user