Added reservation and username lookup
All checks were successful
Build BAB Application Deployment Artifact / build (push) Successful in 2m13s
All checks were successful
Build BAB Application Deployment Artifact / build (push) Successful in 2m13s
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
"@quasar/quasar-app-extension-qcalendar": "https://github.com/ptoal/quasar-ui-qcalendar/releases/download/v4.0.0-beta.19/app-extension.tgz",
|
"@quasar/quasar-app-extension-qcalendar": "https://github.com/ptoal/quasar-ui-qcalendar/releases/download/v4.0.0-beta.19/app-extension.tgz",
|
||||||
"@quasar/quasar-ui-qcalendar": "https://github.com/ptoal/quasar-ui-qcalendar/releases/download/v4.0.0-beta.19/qcalendar-ui.tgz",
|
"@quasar/quasar-ui-qcalendar": "https://github.com/ptoal/quasar-ui-qcalendar/releases/download/v4.0.0-beta.19/qcalendar-ui.tgz",
|
||||||
"appwrite": "^14.0.1",
|
"appwrite": "^14.0.1",
|
||||||
|
"axios": "^1.6.8",
|
||||||
"file": "^0.2.2",
|
"file": "^0.2.2",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"vue": "3",
|
"vue": "3",
|
||||||
|
|||||||
@@ -102,6 +102,12 @@ module.exports = configure(function (/* ctx */) {
|
|||||||
secure: false,
|
secure: false,
|
||||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||||
},
|
},
|
||||||
|
'/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: {
|
||||||
|
|||||||
@@ -16,6 +16,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 useBoatStore().fetchBoats();
|
await useBoatStore().fetchBoats();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { boot } from 'quasar/wrappers';
|
import { boot } from 'quasar/wrappers';
|
||||||
import { Client, Account, Databases, ID } from 'appwrite';
|
import { Client, Account, Databases, Functions, ID } from 'appwrite';
|
||||||
import { useAuthStore } from 'src/stores/auth';
|
import { useAuthStore } from 'src/stores/auth';
|
||||||
import { Dialog, Notify } from 'quasar';
|
import { Dialog, Notify } from 'quasar';
|
||||||
import type { Router } from 'vue-router';
|
import type { Router } from 'vue-router';
|
||||||
@@ -22,10 +22,11 @@ if (process.env.APPWRITE_API_ENDPOINT && process.env.APPWRITE_API_PROJECT)
|
|||||||
const AppwriteIds = {
|
const AppwriteIds = {
|
||||||
databaseId: '65ee1cbf9c2493faf15f',
|
databaseId: '65ee1cbf9c2493faf15f',
|
||||||
collection: {
|
collection: {
|
||||||
|
boat: '66341910003e287cd71c',
|
||||||
|
reservation: '663f8847000b8f5e29bb',
|
||||||
|
skillTags: '66072582a74d94a4bd01',
|
||||||
task: '65ee1cd5b550023fae4f',
|
task: '65ee1cd5b550023fae4f',
|
||||||
taskTags: '65ee21d72d5c8007c34c',
|
taskTags: '65ee21d72d5c8007c34c',
|
||||||
skillTags: '66072582a74d94a4bd01',
|
|
||||||
boat: '66341910003e287cd71c',
|
|
||||||
timeBlock: '66361869002883fb4c4b',
|
timeBlock: '66361869002883fb4c4b',
|
||||||
timeBlockTemplate: '66361f480007fdd639af',
|
timeBlockTemplate: '66361f480007fdd639af',
|
||||||
},
|
},
|
||||||
@@ -33,6 +34,8 @@ const AppwriteIds = {
|
|||||||
|
|
||||||
const account = new Account(client);
|
const account = new Account(client);
|
||||||
const databases = new Databases(client);
|
const databases = new Databases(client);
|
||||||
|
const functions = new Functions(client);
|
||||||
|
|
||||||
let appRouter: Router;
|
let appRouter: Router;
|
||||||
|
|
||||||
export default boot(async ({ router }) => {
|
export default boot(async ({ router }) => {
|
||||||
@@ -98,4 +101,13 @@ function login(email: string, password: string) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
export { client, account, databases, ID, AppwriteIds, login, logout };
|
export {
|
||||||
|
client,
|
||||||
|
account,
|
||||||
|
databases,
|
||||||
|
functions,
|
||||||
|
ID,
|
||||||
|
AppwriteIds,
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
};
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ import {
|
|||||||
parseTimestamp,
|
parseTimestamp,
|
||||||
addToDate,
|
addToDate,
|
||||||
Timestamp,
|
Timestamp,
|
||||||
|
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 { useScheduleStore } from 'src/stores/schedule';
|
||||||
@@ -178,7 +179,7 @@ function getEvents(scope: ResourceIntervalScope) {
|
|||||||
|
|
||||||
return resourceEvents.map((event) => {
|
return resourceEvents.map((event) => {
|
||||||
return {
|
return {
|
||||||
left: scope.timeStartPosX(parseDate(event.start)),
|
left: scope.timeStartPosX(parsed(event.start)),
|
||||||
width: scope.timeDurationWidth(
|
width: scope.timeDurationWidth(
|
||||||
date.getDateDiff(event.end, event.start, 'minutes')
|
date.getDateDiff(event.end, event.start, 'minutes')
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -155,7 +155,6 @@ function onDragStart(e: DragEvent, template: IntervalTemplate) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const saveTemplate = (evt: Event, template: IntervalTemplate | undefined) => {
|
const saveTemplate = (evt: Event, template: IntervalTemplate | undefined) => {
|
||||||
console.log(template);
|
|
||||||
if (!template) return false;
|
if (!template) return false;
|
||||||
overlapped.value = timeTuplesOverlapped(template.timeTuples);
|
overlapped.value = timeTuplesOverlapped(template.timeTuples);
|
||||||
if (overlapped.value.length > 0) {
|
if (overlapped.value.length > 0) {
|
||||||
@@ -163,7 +162,6 @@ const saveTemplate = (evt: Event, template: IntervalTemplate | undefined) => {
|
|||||||
} else {
|
} else {
|
||||||
edit.value = false;
|
edit.value = false;
|
||||||
if (template.$id && template.$id !== 'unsaved') {
|
if (template.$id && template.$id !== 'unsaved') {
|
||||||
console.log(template.$id);
|
|
||||||
scheduleStore.updateIntervalTemplate(template, template.$id);
|
scheduleStore.updateIntervalTemplate(template, template.$id);
|
||||||
} else {
|
} else {
|
||||||
scheduleStore.createIntervalTemplate(template);
|
scheduleStore.createIntervalTemplate(template);
|
||||||
|
|||||||
@@ -38,23 +38,23 @@
|
|||||||
{{ selectedBlock?.$id === block.$id ? 'Selected' : 'Available' }}
|
{{ selectedBlock?.$id === block.$id ? 'Selected' : 'Available' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div
|
<div
|
||||||
v-for="r in boats[scope.columnIndex].reservations"
|
v-for="reservation in getBoatReservations(scope)"
|
||||||
:key="r.id"
|
:key="reservation.$id"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="reservation"
|
class="reservation"
|
||||||
:style="
|
:style="
|
||||||
reservationStyles(
|
reservationStyles(
|
||||||
r,
|
reservation,
|
||||||
scope.timeStartPos,
|
scope.timeStartPos,
|
||||||
scope.timeDurationHeight
|
scope.timeDurationHeight
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ r.user }}
|
{{ getUserName(reservation.user) || 'loading...' }}
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</QCalendarDay>
|
</QCalendarDay>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,7 +76,8 @@ import CalendarHeaderComponent from './CalendarHeaderComponent.vue';
|
|||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useBoatStore } from 'src/stores/boat';
|
import { useBoatStore } from 'src/stores/boat';
|
||||||
import { useScheduleStore } from 'src/stores/schedule';
|
import { useScheduleStore } from 'src/stores/schedule';
|
||||||
import { Interval } from 'src/stores/schedule.types';
|
import { useAuthStore } from 'src/stores/auth';
|
||||||
|
import { Interval, Reservation } from 'src/stores/schedule.types';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
const scheduleStore = useScheduleStore();
|
const scheduleStore = useScheduleStore();
|
||||||
@@ -89,18 +90,22 @@ const calendar = ref<QCalendarDay | null>(null);
|
|||||||
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 reservationStyles(
|
function reservationStyles(
|
||||||
// reservation: Reservation,
|
reservation: Reservation,
|
||||||
// timeStartPos: (t: string) => string,
|
timeStartPos: (t: string) => string,
|
||||||
// timeDurationHeight: (d: number) => string
|
timeDurationHeight: (d: number) => string
|
||||||
// ) {
|
) {
|
||||||
// return genericBlockStyle(
|
return genericBlockStyle(
|
||||||
// parseDate(reservation.start) as Timestamp,
|
parseDate(new Date(reservation.start)) as Timestamp,
|
||||||
// parseDate(reservation.end) as Timestamp,
|
parseDate(new Date(reservation.end)) as Timestamp,
|
||||||
// timeStartPos,
|
timeStartPos,
|
||||||
// timeDurationHeight
|
timeDurationHeight
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
function getUserName(userid: string) {
|
||||||
|
return useAuthStore().getUserNameById(userid);
|
||||||
|
}
|
||||||
|
|
||||||
function blockStyles(
|
function blockStyles(
|
||||||
block: Interval,
|
block: Interval,
|
||||||
@@ -176,8 +181,13 @@ const boatBlocks = computed((): BoatBlocks => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function getBoatBlocks(scope: DayBodyScope): Interval[] {
|
function getBoatBlocks(scope: DayBodyScope): Interval[] {
|
||||||
return boats.value[scope.columnIndex]
|
const boat = boats.value[scope.columnIndex];
|
||||||
? boatBlocks.value[boats.value[scope.columnIndex].$id]
|
return boat ? boatBlocks.value[boat.$id] : [];
|
||||||
|
}
|
||||||
|
function getBoatReservations(scope: DayBodyScope): Reservation[] {
|
||||||
|
const boat = boats.value[scope.columnIndex];
|
||||||
|
return boat
|
||||||
|
? scheduleStore.getBoatReservations(scope.timestamp, boat.$id)
|
||||||
: [];
|
: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -252,14 +252,11 @@ const dateRule = (val: string) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
//console.log(modifiedTask);
|
|
||||||
try {
|
try {
|
||||||
if (modifiedTask.$id) {
|
if (modifiedTask.$id) {
|
||||||
await taskStore.updateTask(modifiedTask);
|
await taskStore.updateTask(modifiedTask);
|
||||||
console.log('Updated Task: ' + modifiedTask.$id);
|
|
||||||
} else {
|
} else {
|
||||||
await taskStore.addTask(modifiedTask);
|
await taskStore.addTask(modifiedTask);
|
||||||
console.log('Created Task');
|
|
||||||
}
|
}
|
||||||
router.go(-1);
|
router.go(-1);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ watch(timeblock, (tb_new) => {
|
|||||||
);
|
);
|
||||||
bookingForm.value.startDate = date.formatDate(tb_new?.start, dateFormat);
|
bookingForm.value.startDate = date.formatDate(tb_new?.start, dateFormat);
|
||||||
bookingForm.value.endDate = date.formatDate(tb_new?.end, dateFormat);
|
bookingForm.value.endDate = date.formatDate(tb_new?.end, dateFormat);
|
||||||
console.log(tb_new);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// //TODO: Turn this into a validator.
|
// //TODO: Turn this into a validator.
|
||||||
|
|||||||
@@ -37,7 +37,9 @@
|
|||||||
<span class="title q-calendar__ellipsis">
|
<span class="title q-calendar__ellipsis">
|
||||||
{{ event.user }}
|
{{ event.user }}
|
||||||
<q-tooltip>{{
|
<q-tooltip>{{
|
||||||
event.start + ' - ' + event.resource.name
|
event.start +
|
||||||
|
' - ' +
|
||||||
|
boatStore.getBoatById(event.resource)?.name
|
||||||
}}</q-tooltip>
|
}}</q-tooltip>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,12 +56,14 @@ import { useScheduleStore } from 'src/stores/schedule';
|
|||||||
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 scheduleStore = useScheduleStore();
|
||||||
import { TimestampOrNull, parseDate, 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';
|
||||||
import { Timestamp } from '@quasar/quasar-ui-qcalendar';
|
import { Timestamp } from '@quasar/quasar-ui-qcalendar';
|
||||||
|
import { useBoatStore } from 'src/stores/boat';
|
||||||
|
|
||||||
const selectedDate = ref(today());
|
const selectedDate = ref(today());
|
||||||
|
const boatStore = useBoatStore();
|
||||||
|
|
||||||
// Method declarations
|
// Method declarations
|
||||||
|
|
||||||
@@ -74,7 +78,7 @@ function slotStyle(
|
|||||||
'align-items': 'flex-start',
|
'align-items': 'flex-start',
|
||||||
};
|
};
|
||||||
if (timeStartPos && timeDurationHeight) {
|
if (timeStartPos && timeDurationHeight) {
|
||||||
s.top = timeStartPos(parseDate(event.start)) + 'px';
|
s.top = timeStartPos(parsed(event.start)) + 'px';
|
||||||
s.height =
|
s.height =
|
||||||
timeDurationHeight(date.getDateDiff(event.end, event.start, 'minutes')) +
|
timeDurationHeight(date.getDateDiff(event.end, event.start, 'minutes')) +
|
||||||
'px';
|
'px';
|
||||||
|
|||||||
@@ -260,7 +260,6 @@ function onDrop(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
console.log(overlapped);
|
|
||||||
if (overlapped.value.length === 0) {
|
if (overlapped.value.length === 0) {
|
||||||
boats.value.map((b) => createIntervals(b, templateId, date));
|
boats.value.map((b) => createIntervals(b, templateId, date));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { ID, account } from 'boot/appwrite';
|
import { ID, account, functions } from 'boot/appwrite';
|
||||||
import { OAuthProvider, type Models } from 'appwrite';
|
import { ExecutionMethod, OAuthProvider, type Models } from 'appwrite';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
export const useAuthStore = defineStore('auth', () => {
|
export const useAuthStore = defineStore('auth', () => {
|
||||||
const currentUser = ref<Models.User<Models.Preferences> | null>(null);
|
const currentUser = ref<Models.User<Models.Preferences> | null>(null);
|
||||||
|
const userNames = ref<Record<string, string>>({});
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
try {
|
try {
|
||||||
@@ -31,9 +32,39 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
currentUser.value = await account.get();
|
currentUser.value = await account.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUserNameById(id: string) {
|
||||||
|
try {
|
||||||
|
if (!userNames.value[id]) {
|
||||||
|
userNames.value[id] = '';
|
||||||
|
functions
|
||||||
|
.createExecution(
|
||||||
|
'664038294b5473ef0c8d',
|
||||||
|
'',
|
||||||
|
false,
|
||||||
|
'/userinfo/' + id,
|
||||||
|
ExecutionMethod.GET
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
(res) => (userNames.value[id] = JSON.parse(res.responseBody).name)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Failed to get username. Error: ' + e);
|
||||||
|
}
|
||||||
|
return userNames.value[id];
|
||||||
|
}
|
||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
return account.deleteSession('current').then((currentUser.value = null));
|
return account.deleteSession('current').then((currentUser.value = null));
|
||||||
}
|
}
|
||||||
|
|
||||||
return { currentUser, register, login, googleLogin, logout, init };
|
return {
|
||||||
|
currentUser,
|
||||||
|
getUserNameById,
|
||||||
|
register,
|
||||||
|
login,
|
||||||
|
googleLogin,
|
||||||
|
logout,
|
||||||
|
init,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -39,5 +39,9 @@ export const useBoatStore = defineStore('boat', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { boats, fetchBoats };
|
const getBoatById = (id: string): Boat | null => {
|
||||||
|
return boats.value.find((b) => b.$id === id) || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return { boats, fetchBoats, getBoatById };
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export function getSampleReservations(): Reservation[] {
|
|||||||
user: 'John Smith',
|
user: 'John Smith',
|
||||||
start: '7:00',
|
start: '7:00',
|
||||||
end: '10:00',
|
end: '10:00',
|
||||||
boat: '1',
|
boat: '66359729003825946ae1',
|
||||||
status: 'confirmed',
|
status: 'confirmed',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -77,7 +77,7 @@ export function getSampleReservations(): Reservation[] {
|
|||||||
user: 'Bob Barker',
|
user: 'Bob Barker',
|
||||||
start: '16:00',
|
start: '16:00',
|
||||||
end: '19:00',
|
end: '19:00',
|
||||||
boat: '1',
|
boat: '66359729003825946ae1',
|
||||||
status: 'confirmed',
|
status: 'confirmed',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -85,7 +85,7 @@ export function getSampleReservations(): Reservation[] {
|
|||||||
user: 'Peter Parker',
|
user: 'Peter Parker',
|
||||||
start: '7:00',
|
start: '7:00',
|
||||||
end: '13:00',
|
end: '13:00',
|
||||||
boat: '4',
|
boat: '663597030029b71c7a9b',
|
||||||
status: 'tentative',
|
status: 'tentative',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -93,7 +93,7 @@ export function getSampleReservations(): Reservation[] {
|
|||||||
user: 'Vince McMahon',
|
user: 'Vince McMahon',
|
||||||
start: '10:00',
|
start: '10:00',
|
||||||
end: '13:00',
|
end: '13:00',
|
||||||
boat: '2',
|
boat: '663597030029b71c7a9b',
|
||||||
status: 'pending',
|
status: 'pending',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -101,7 +101,7 @@ export function getSampleReservations(): Reservation[] {
|
|||||||
user: 'Heather Graham',
|
user: 'Heather Graham',
|
||||||
start: '13:00',
|
start: '13:00',
|
||||||
end: '19:00',
|
end: '19:00',
|
||||||
boat: '4',
|
boat: '663596b9000235ffea55',
|
||||||
status: 'confirmed',
|
status: 'confirmed',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -109,7 +109,7 @@ export function getSampleReservations(): Reservation[] {
|
|||||||
user: 'Lawrence Fishburne',
|
user: 'Lawrence Fishburne',
|
||||||
start: '13:00',
|
start: '13:00',
|
||||||
end: '16:00',
|
end: '16:00',
|
||||||
boat: '3',
|
boat: '663596b9000235ffea55',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const boatStore = useBoatStore();
|
const boatStore = useBoatStore();
|
||||||
@@ -131,9 +131,11 @@ export function getSampleReservations(): Reservation[] {
|
|||||||
return {
|
return {
|
||||||
id: entry.id,
|
id: entry.id,
|
||||||
user: entry.user,
|
user: entry.user,
|
||||||
start: date.adjustDate(now, makeOpts(splitTime(entry.start))),
|
start: date
|
||||||
end: date.adjustDate(now, makeOpts(splitTime(entry.end))),
|
.adjustDate(now, makeOpts(splitTime(entry.start)))
|
||||||
resource: boat,
|
.toISOString(),
|
||||||
|
end: date.adjustDate(now, makeOpts(splitTime(entry.end))).toISOString(),
|
||||||
|
resource: boat.$id,
|
||||||
reservationDate: now,
|
reservationDate: now,
|
||||||
status: entry.status as StatusTypes,
|
status: entry.status as StatusTypes,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -108,19 +108,32 @@ 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 = (
|
const getBoatReservations = (
|
||||||
searchDate: Timestamp,
|
searchDate: Timestamp,
|
||||||
boat?: string
|
boat?: string
|
||||||
): Reservation[] => {
|
): Reservation[] => {
|
||||||
return reservations.value.filter((x) => {
|
const result = reservations.value.filter((x) => {
|
||||||
return (
|
return (
|
||||||
((parseDate(x.start)?.date == searchDate.date ||
|
((parsed(x.start)?.date == searchDate.date ||
|
||||||
parseDate(x.end)?.date == searchDate.date) && // Part of reservation falls on day
|
parsed(x.end)?.date == searchDate.date) && // Part of reservation falls on day
|
||||||
x.resource != undefined && // A boat is defined
|
x.resource != undefined && // A boat is defined
|
||||||
!boat) ||
|
!boat) ||
|
||||||
x.resource.$id == boat // A specific boat has been passed, and matches
|
x.resource == boat // A specific boat has been passed, and matches
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function fetchIntervals() {
|
async function fetchIntervals() {
|
||||||
@@ -170,21 +183,21 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
const getConflictingReservations = (
|
const getConflictingReservations = (
|
||||||
resource: Boat,
|
resource: string,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date
|
end: Date
|
||||||
): Reservation[] => {
|
): Reservation[] => {
|
||||||
const overlapped = reservations.value.filter(
|
const overlapped = reservations.value.filter(
|
||||||
(entry: Reservation) =>
|
(entry: Reservation) =>
|
||||||
entry.resource.$id == resource.$id &&
|
entry.resource == resource &&
|
||||||
entry.start < end &&
|
new Date(entry.start) < end &&
|
||||||
entry.end > start
|
new Date(entry.end) > start
|
||||||
);
|
);
|
||||||
return overlapped;
|
return overlapped;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isResourceTimeOverlapped = (
|
const isResourceTimeOverlapped = (
|
||||||
resource: Boat,
|
resource: string,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date
|
end: Date
|
||||||
): boolean => {
|
): boolean => {
|
||||||
@@ -192,7 +205,11 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isReservationOverlapped = (res: Reservation): boolean => {
|
const isReservationOverlapped = (res: Reservation): boolean => {
|
||||||
return isResourceTimeOverlapped(res.resource, res.start, res.end);
|
return isResourceTimeOverlapped(
|
||||||
|
res.resource,
|
||||||
|
new Date(res.start),
|
||||||
|
new Date(res.end)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNewId = (): string => {
|
const getNewId = (): string => {
|
||||||
@@ -235,7 +252,6 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
{ ...interval, $id: undefined }
|
{ ...interval, $id: undefined }
|
||||||
);
|
);
|
||||||
timeblocks.value.push(response as Interval);
|
timeblocks.value.push(response as Interval);
|
||||||
console.log(interval, response);
|
|
||||||
} else {
|
} else {
|
||||||
console.error('Update interval called without an ID');
|
console.error('Update interval called without an ID');
|
||||||
}
|
}
|
||||||
@@ -315,19 +331,20 @@ export const useScheduleStore = defineStore('schedule', () => {
|
|||||||
timeblockTemplates,
|
timeblockTemplates,
|
||||||
getBoatReservations,
|
getBoatReservations,
|
||||||
getConflictingReservations,
|
getConflictingReservations,
|
||||||
|
addOrCreateReservation,
|
||||||
|
isReservationOverlapped,
|
||||||
|
isResourceTimeOverlapped,
|
||||||
|
fetchReservations,
|
||||||
getIntervalsForDate,
|
getIntervalsForDate,
|
||||||
getIntervals,
|
getIntervals,
|
||||||
fetchIntervals,
|
fetchIntervals,
|
||||||
fetchIntervalTemplates,
|
fetchIntervalTemplates,
|
||||||
getNewId,
|
getNewId,
|
||||||
addOrCreateReservation,
|
|
||||||
createInterval,
|
createInterval,
|
||||||
updateInterval,
|
updateInterval,
|
||||||
deleteInterval,
|
deleteInterval,
|
||||||
createIntervalTemplate,
|
createIntervalTemplate,
|
||||||
deleteIntervalTemplate,
|
deleteIntervalTemplate,
|
||||||
updateIntervalTemplate,
|
updateIntervalTemplate,
|
||||||
isReservationOverlapped,
|
|
||||||
isResourceTimeOverlapped,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import { Models } from 'appwrite';
|
import { Models } from 'appwrite';
|
||||||
import type { Boat } from './boat';
|
|
||||||
|
|
||||||
export type StatusTypes = 'tentative' | 'confirmed' | 'pending' | undefined;
|
export type StatusTypes = 'tentative' | 'confirmed' | 'pending' | undefined;
|
||||||
export interface Reservation {
|
export type Reservation = Partial<Models.Document> & {
|
||||||
id: string;
|
|
||||||
user: string;
|
user: string;
|
||||||
start: Date;
|
start: string; // ISODate
|
||||||
end: Date;
|
end: string; //ISODate
|
||||||
resource: Boat;
|
resource: string; // Boat ID
|
||||||
reservationDate: Date;
|
|
||||||
status?: StatusTypes;
|
status?: StatusTypes;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 24 hrs in advance only 2 weekday, and 1 weekend slot
|
// 24 hrs in advance only 2 weekday, and 1 weekend slot
|
||||||
// Within 24 hrs, any available slot
|
// Within 24 hrs, any available slot
|
||||||
/* TODO: Figure out how best to separate out where qcalendar bits should be.
|
/* TODO: Figure out how best to separate out where qcalendar bits should be.
|
||||||
|
|||||||
30
yarn.lock
30
yarn.lock
@@ -1808,6 +1808,15 @@ available-typed-arrays@^1.0.7:
|
|||||||
dependencies:
|
dependencies:
|
||||||
possible-typed-array-names "^1.0.0"
|
possible-typed-array-names "^1.0.0"
|
||||||
|
|
||||||
|
axios@^1.6.8:
|
||||||
|
version "1.6.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66"
|
||||||
|
integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "^1.15.6"
|
||||||
|
form-data "^4.0.0"
|
||||||
|
proxy-from-env "^1.1.0"
|
||||||
|
|
||||||
babel-plugin-polyfill-corejs2@^0.4.10:
|
babel-plugin-polyfill-corejs2@^0.4.10:
|
||||||
version "0.4.11"
|
version "0.4.11"
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33"
|
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33"
|
||||||
@@ -2086,7 +2095,7 @@ color-name@~1.1.4:
|
|||||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||||
|
|
||||||
combined-stream@^1.0.6:
|
combined-stream@^1.0.6, combined-stream@^1.0.8:
|
||||||
version "1.0.8"
|
version "1.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||||
@@ -3079,6 +3088,11 @@ flatted@^3.2.9:
|
|||||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
|
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
|
||||||
integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
|
integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
|
||||||
|
|
||||||
|
follow-redirects@^1.15.6:
|
||||||
|
version "1.15.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
|
||||||
|
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
|
||||||
|
|
||||||
for-each@^0.3.3:
|
for-each@^0.3.3:
|
||||||
version "0.3.3"
|
version "0.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
|
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
|
||||||
@@ -3095,6 +3109,15 @@ form-data@^2.3.2:
|
|||||||
combined-stream "^1.0.6"
|
combined-stream "^1.0.6"
|
||||||
mime-types "^2.1.12"
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
|
form-data@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||||
|
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||||
|
dependencies:
|
||||||
|
asynckit "^0.4.0"
|
||||||
|
combined-stream "^1.0.8"
|
||||||
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
forwarded@0.2.0:
|
forwarded@0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||||
@@ -4282,6 +4305,11 @@ proxy-addr@~2.0.7:
|
|||||||
forwarded "0.2.0"
|
forwarded "0.2.0"
|
||||||
ipaddr.js "1.9.1"
|
ipaddr.js "1.9.1"
|
||||||
|
|
||||||
|
proxy-from-env@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
|
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||||
|
|
||||||
punycode@^2.1.0:
|
punycode@^2.1.0:
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
|
||||||
|
|||||||
Reference in New Issue
Block a user