Developing Booking Form
This commit is contained in:
@@ -79,8 +79,16 @@ module.exports = configure(function (/* ctx */) {
|
|||||||
|
|
||||||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
|
||||||
devServer: {
|
devServer: {
|
||||||
// https: true
|
// https: true,
|
||||||
open: true, // opens browser window automatically
|
// open: true, // opens browser window automatically
|
||||||
|
port: 4000,
|
||||||
|
strictport: true,
|
||||||
|
// For reverse-proxying via haproxy
|
||||||
|
hmr: {
|
||||||
|
clientPort: 443,
|
||||||
|
protocol: 'wss',
|
||||||
|
timeout: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
|
||||||
|
|||||||
BIN
src/assets/projectx_avatar.png
Normal file
BIN
src/assets/projectx_avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 257 KiB |
BIN
src/assets/projectx_avatar256.png
Normal file
BIN
src/assets/projectx_avatar256.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
BIN
src/assets/take5_avatar32.png
Normal file
BIN
src/assets/take5_avatar32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
@@ -23,7 +23,7 @@ const account = new Account(client);
|
|||||||
const databases = new Databases(client);
|
const databases = new Databases(client);
|
||||||
let appRouter: Router;
|
let appRouter: Router;
|
||||||
|
|
||||||
export default boot(async ({ app, router }) => {
|
export default boot(async ({ router }) => {
|
||||||
// Initialize store
|
// Initialize store
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
await authStore.init();
|
await authStore.init();
|
||||||
|
|||||||
134
src/components/ResourceScheduleViewerComponent.vue
Normal file
134
src/components/ResourceScheduleViewerComponent.vue
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<div class="row justify-center">
|
||||||
|
<q-btn-group rounded>
|
||||||
|
<q-btn
|
||||||
|
color="primary"
|
||||||
|
rounded
|
||||||
|
icon="keyboard_arrow_left"
|
||||||
|
label="Prev"
|
||||||
|
@click="onPrev"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
color="primary"
|
||||||
|
rounded
|
||||||
|
icon="today"
|
||||||
|
label="Today"
|
||||||
|
@click="onToday"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
color="primary"
|
||||||
|
rounded
|
||||||
|
icon-right="keyboard_arrow_right"
|
||||||
|
label="Next"
|
||||||
|
@click="onNext"
|
||||||
|
/>
|
||||||
|
</q-btn-group>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-center">
|
||||||
|
<div style="display: flex; max-width: 1024px; width: 100%">
|
||||||
|
<q-calendar-resource
|
||||||
|
ref="calendar"
|
||||||
|
v-model="selectedDate"
|
||||||
|
:model-resources="boatStore.boats"
|
||||||
|
resource-key="id"
|
||||||
|
resource-label="name"
|
||||||
|
:interval-start="6"
|
||||||
|
:interval-count="12"
|
||||||
|
animated
|
||||||
|
bordered
|
||||||
|
@change="onChange"
|
||||||
|
@moved="onMoved"
|
||||||
|
@resource-expanded="onResourceExpanded"
|
||||||
|
@click-date="onClickDate"
|
||||||
|
@click-time="onClickTime"
|
||||||
|
@click-resource="onClickResource"
|
||||||
|
@click-head-resources="onClickHeadResources"
|
||||||
|
@click-interval="onClickInterval"
|
||||||
|
>
|
||||||
|
<template #resource-intervals="{ scope }">
|
||||||
|
<template v-for="(event, index) in getEvents(scope)" :key="index">
|
||||||
|
<q-badge
|
||||||
|
outline
|
||||||
|
color="primary"
|
||||||
|
:label="event.title"
|
||||||
|
:style="getStyle(event)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</q-calendar-resource>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { QCalendarResource, today } from '@quasar/quasar-ui-qcalendar';
|
||||||
|
import { Boat, useBoatStore } from 'src/stores/boat';
|
||||||
|
import { useBookingStore } from 'src/stores/booking';
|
||||||
|
|
||||||
|
const calendar = ref();
|
||||||
|
const boatStore = useBoatStore();
|
||||||
|
const bookingStore = useBookingStore();
|
||||||
|
|
||||||
|
type ResourceIntervalScope = {
|
||||||
|
resource: Boat;
|
||||||
|
intervals: [];
|
||||||
|
timeStartPosX(start: string): number;
|
||||||
|
timeDurationWidth(duration: number): number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectedDate = ref(today());
|
||||||
|
function getEvents(scope: ResourceIntervalScope) {
|
||||||
|
const resourceEvents = bookingStore.bookings[scope.resource.id];
|
||||||
|
return resourceEvents.map((event) => ({
|
||||||
|
left: scope.timeStartPosX(event.start),
|
||||||
|
width: scope.timeDurationWidth(event.duration),
|
||||||
|
title: event.title,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStyle(event: { left: number; width: number; title: string }) {
|
||||||
|
return {
|
||||||
|
position: 'absolute',
|
||||||
|
background: 'white',
|
||||||
|
left: `${event.left}px`,
|
||||||
|
width: `${event.width}px`,
|
||||||
|
height: '40px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function onToday() {
|
||||||
|
calendar.value.moveToToday();
|
||||||
|
}
|
||||||
|
function onPrev() {
|
||||||
|
calendar.value.prev();
|
||||||
|
}
|
||||||
|
function onNext() {
|
||||||
|
calendar.value.next();
|
||||||
|
}
|
||||||
|
function onMoved(data) {
|
||||||
|
console.log('onMoved', data);
|
||||||
|
}
|
||||||
|
function onChange(data) {
|
||||||
|
console.log('onChange', data);
|
||||||
|
}
|
||||||
|
function onResourceExpanded(data) {
|
||||||
|
console.log('onResourceExpanded', data);
|
||||||
|
}
|
||||||
|
function onClickDate(data) {
|
||||||
|
console.log('onClickDate', data);
|
||||||
|
}
|
||||||
|
function onClickTime(data) {
|
||||||
|
console.log('onClickTime', data);
|
||||||
|
}
|
||||||
|
function onClickResource(data) {
|
||||||
|
console.log('onClickResource', data);
|
||||||
|
}
|
||||||
|
function onClickHeadResources(data) {
|
||||||
|
console.log('onClickHeadResources', data);
|
||||||
|
}
|
||||||
|
function onClickInterval(data) {
|
||||||
|
console.log('onClickInterval', data);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
:key="link.name"
|
:key="link.name"
|
||||||
>
|
>
|
||||||
<q-btn
|
<q-btn
|
||||||
:v-model="auth.ready"
|
|
||||||
:icon="link.icon"
|
:icon="link.icon"
|
||||||
color="primary"
|
color="primary"
|
||||||
:size="`1.25em`"
|
:size="`1.25em`"
|
||||||
@@ -25,8 +24,5 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { links } from 'src/router/navlinks.js';
|
import { links } from 'src/router/navlinks.js';
|
||||||
import { useAuthStore } from 'stores/auth';
|
|
||||||
import ToolbarComponent from 'components/ToolbarComponent.vue';
|
import ToolbarComponent from 'components/ToolbarComponent.vue';
|
||||||
|
|
||||||
const auth = useAuthStore();
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,165 +1,181 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row justify-center">
|
<q-page padding>
|
||||||
<q-btn-group rounded>
|
<q-card>
|
||||||
<q-btn
|
<q-form>
|
||||||
color="primary"
|
<q-input bottom-slots v-model="bookingForm.name" label="Name" readonly>
|
||||||
rounded
|
<template v-slot:prepend>
|
||||||
icon="keyboard_arrow_left"
|
<q-icon name="person" />
|
||||||
label="Prev"
|
|
||||||
@click="onPrev"
|
|
||||||
/>
|
|
||||||
<q-btn
|
|
||||||
color="primary"
|
|
||||||
rounded
|
|
||||||
icon="today"
|
|
||||||
label="Today"
|
|
||||||
@click="onToday"
|
|
||||||
/>
|
|
||||||
<q-btn
|
|
||||||
color="primary"
|
|
||||||
rounded
|
|
||||||
icon-right="keyboard_arrow_right"
|
|
||||||
label="Next"
|
|
||||||
@click="onNext"
|
|
||||||
/>
|
|
||||||
</q-btn-group>
|
|
||||||
</div>
|
|
||||||
<div class="row justify-center">
|
|
||||||
<div style="display: flex; max-width: 1024px; width: 100%">
|
|
||||||
<q-calendar-resource
|
|
||||||
ref="calendar"
|
|
||||||
v-model="selectedDate"
|
|
||||||
:model-resources="resources"
|
|
||||||
resource-key="id"
|
|
||||||
resource-label="name"
|
|
||||||
:interval-start="6"
|
|
||||||
:interval-count="12"
|
|
||||||
animated
|
|
||||||
bordered
|
|
||||||
@change="onChange"
|
|
||||||
@moved="onMoved"
|
|
||||||
@resource-expanded="onResourceExpanded"
|
|
||||||
@click-date="onClickDate"
|
|
||||||
@click-time="onClickTime"
|
|
||||||
@click-resource="onClickResource"
|
|
||||||
@click-head-resources="onClickHeadResources"
|
|
||||||
@click-interval="onClickInterval"
|
|
||||||
>
|
|
||||||
<template #resource-intervals="{ scope }">
|
|
||||||
<template v-for="(event, index) in getEvents(scope)" :key="index">
|
|
||||||
<q-badge
|
|
||||||
outline
|
|
||||||
color="primary"
|
|
||||||
:label="event.title"
|
|
||||||
:style="getStyle(event)"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</q-input>
|
||||||
</q-calendar-resource>
|
<q-select
|
||||||
</div>
|
v-model="bookingForm.boat"
|
||||||
</div>
|
:options="boats"
|
||||||
|
option-value="id"
|
||||||
|
option-label="name"
|
||||||
|
label="Boat"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-img
|
||||||
|
v-if="bookingForm.boat?.iconsrc"
|
||||||
|
:src="bookingForm.boat?.iconsrc"
|
||||||
|
/>
|
||||||
|
<q-icon v-else name="sailing" />
|
||||||
|
</q-item-section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:option="scope">
|
||||||
|
<q-item v-bind="scope.itemProps">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-img :src="scope.opt.iconsrc" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{ scope.opt.name }}</q-item-label>
|
||||||
|
<q-item-label caption>{{ scope.opt.class }}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section avatar v-if="scope.opt.defects">
|
||||||
|
<q-icon name="warning" color="warning" />
|
||||||
|
<q-tooltip class="bg-amber text-black shadow-7"
|
||||||
|
>This boat has defects. Select it to see details.
|
||||||
|
</q-tooltip>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
<q-banner
|
||||||
|
rounded
|
||||||
|
class="bg-warning text-grey-10"
|
||||||
|
v-if="bookingForm.boat?.defects"
|
||||||
|
>
|
||||||
|
<template v-slot:avatar>
|
||||||
|
<q-icon name="warning" color="grey-10" />
|
||||||
|
</template>
|
||||||
|
This boat currently has the following defects:
|
||||||
|
<ol>
|
||||||
|
<li
|
||||||
|
v-for="defect in bookingForm.boat.defects"
|
||||||
|
:key="defect.description"
|
||||||
|
>
|
||||||
|
{{ defect.description }}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</q-banner>
|
||||||
|
<q-input v-model="bookingForm.startDate" label="Check-Out" readonly>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="event" class="cursor-pointer"> </q-icon>
|
||||||
|
</template>
|
||||||
|
<q-popup-proxy
|
||||||
|
cover
|
||||||
|
transition-show="scale"
|
||||||
|
transition-hide="scale"
|
||||||
|
@before-show="startDateOrTime = true"
|
||||||
|
>
|
||||||
|
<q-date
|
||||||
|
v-model="bookingForm.startDate"
|
||||||
|
mask="ddd MMM D, YYYY h:mm A"
|
||||||
|
:options="limitDate"
|
||||||
|
v-if="startDateOrTime"
|
||||||
|
>
|
||||||
|
<div class="row items-center justify-end">
|
||||||
|
<q-btn
|
||||||
|
label="Next"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
@click="startDateOrTime = false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-date>
|
||||||
|
<q-time
|
||||||
|
v-model="bookingForm.startDate"
|
||||||
|
mask="ddd MMM D, YYYY h:mm A"
|
||||||
|
:minute-options="minOpts"
|
||||||
|
v-else
|
||||||
|
>
|
||||||
|
<div class="row items-center justify-end">
|
||||||
|
<q-btn v-close-popup label="Close" color="primary" flat />
|
||||||
|
</div>
|
||||||
|
</q-time>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-input>
|
||||||
|
<q-input v-model="bookingForm.endDate" label="Check-In" readonly>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="event" class="cursor-pointer"> </q-icon>
|
||||||
|
</template>
|
||||||
|
<q-popup-proxy
|
||||||
|
cover
|
||||||
|
transition-show="scale"
|
||||||
|
transition-hide="scale"
|
||||||
|
@before-show="endDateOrTime = true"
|
||||||
|
>
|
||||||
|
<q-date
|
||||||
|
v-model="bookingForm.startDate"
|
||||||
|
mask="ddd MMM D, YYYY h:mm A"
|
||||||
|
:options="limitDate"
|
||||||
|
v-if="endDateOrTime"
|
||||||
|
>
|
||||||
|
<div class="row items-center justify-end">
|
||||||
|
<q-btn
|
||||||
|
label="Next"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
@click="endDateOrTime = !endDateOrTime"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-date>
|
||||||
|
<q-time
|
||||||
|
v-model="bookingForm.endDate"
|
||||||
|
mask="ddd MMM D, YYYY h:mm A"
|
||||||
|
:minute-options="minOpts"
|
||||||
|
v-else
|
||||||
|
>
|
||||||
|
<div class="row items-center justify-end">
|
||||||
|
<q-btn v-close-popup label="Close" color="primary" flat />
|
||||||
|
</div>
|
||||||
|
</q-time>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-input>
|
||||||
|
<div>Booking Duration: {{ bookingDuration }} hours</div>
|
||||||
|
</q-form>
|
||||||
|
</q-card>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { QCalendarResource, today } from '@quasar/quasar-ui-qcalendar';
|
import { useAuthStore } from 'src/stores/auth';
|
||||||
|
import { Boat, useBoatStore } from 'src/stores/boat';
|
||||||
|
import { date } from 'quasar';
|
||||||
|
|
||||||
const selectedDate = ref(today());
|
const auth = useAuthStore();
|
||||||
type Resource = {
|
const boats = useBoatStore().boats;
|
||||||
id: string;
|
const startDateOrTime = ref(true);
|
||||||
name: string;
|
const endDateOrTime = ref(true);
|
||||||
expanded?: boolean;
|
const bookingForm = ref({
|
||||||
children?: Resource[];
|
name: auth.currentUser?.name,
|
||||||
};
|
boat: <Boat | undefined>undefined,
|
||||||
|
startDate: date.formatDate(new Date(), 'ddd MMM D, YYYY h:mm A'),
|
||||||
type Event = {
|
endDate: date.formatDate(
|
||||||
start: string;
|
date.addToDate(new Date(), { hours: 2 }),
|
||||||
title: string;
|
'ddd MMM D, YYYY h:mm A'
|
||||||
duration: number;
|
),
|
||||||
left?: number;
|
|
||||||
width?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ResourceIntervalScope = {
|
|
||||||
resource: Resource;
|
|
||||||
intervals: [];
|
|
||||||
timeStartPosX(start: string): number;
|
|
||||||
timeDurationWidth(duration: number): number;
|
|
||||||
};
|
|
||||||
|
|
||||||
const calendar = ref(null);
|
|
||||||
const resources = reactive<Resource[]>([
|
|
||||||
{ id: '1', name: 'ProjectX' },
|
|
||||||
{ id: '2', name: 'Take 5' },
|
|
||||||
{ id: '3', name: 'WeeBeestie' },
|
|
||||||
]);
|
|
||||||
|
|
||||||
const events = reactive<{ [key: string]: Event[] }>({
|
|
||||||
1: [
|
|
||||||
{ start: '06:00', title: 'John Smith', duration: 90 },
|
|
||||||
{ start: '12:00', title: 'Bob Barker', duration: 60 },
|
|
||||||
],
|
|
||||||
2: [
|
|
||||||
{ start: '08:00', title: 'Peter Parker', duration: 120 },
|
|
||||||
{ start: '11:00', title: 'Vince McMahon', duration: 240 },
|
|
||||||
],
|
|
||||||
3: [
|
|
||||||
{ start: '08:00', title: 'Heather Graham', duration: 240 },
|
|
||||||
{ start: '14:00', title: 'Lawrence Fishburne', duration: 60 },
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function getEvents(scope: ResourceIntervalScope) {
|
const bookingDuration = computed(() => {
|
||||||
const resourceEvents = events[scope.resource.id];
|
const diff = date.getDateDiff(
|
||||||
return resourceEvents.map((event) => ({
|
bookingForm.value.endDate,
|
||||||
left: scope.timeStartPosX(event.start),
|
bookingForm.value.startDate,
|
||||||
width: scope.timeDurationWidth(event.duration),
|
'hours'
|
||||||
title: event.title,
|
);
|
||||||
}));
|
return diff > 0 ? diff : 'Invalid.';
|
||||||
}
|
});
|
||||||
|
|
||||||
function getStyle(event: { left: number; width: number; title: string }) {
|
const limitDate = (startDate: string) => {
|
||||||
return {
|
return date.isBetweenDates(
|
||||||
position: 'absolute',
|
startDate,
|
||||||
background: 'white',
|
new Date(),
|
||||||
left: `${event.left}px`,
|
date.addToDate(new Date(), { days: 21 })
|
||||||
width: `${event.width}px`,
|
);
|
||||||
height: '40px',
|
};
|
||||||
overflow: 'hidden',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function onToday() {
|
const minOpts = [0, 15, 30, 45, 60];
|
||||||
calendar.value.moveToToday();
|
|
||||||
}
|
|
||||||
function onPrev() {
|
|
||||||
calendar.value.prev();
|
|
||||||
}
|
|
||||||
function onNext() {
|
|
||||||
calendar.value.next();
|
|
||||||
}
|
|
||||||
function onMoved(data) {
|
|
||||||
console.log('onMoved', data);
|
|
||||||
}
|
|
||||||
function onChange(data) {
|
|
||||||
console.log('onChange', data);
|
|
||||||
}
|
|
||||||
function onResourceExpanded(data) {
|
|
||||||
console.log('onResourceExpanded', data);
|
|
||||||
}
|
|
||||||
function onClickDate(data) {
|
|
||||||
console.log('onClickDate', data);
|
|
||||||
}
|
|
||||||
function onClickTime(data) {
|
|
||||||
console.log('onClickTime', data);
|
|
||||||
}
|
|
||||||
function onClickResource(data) {
|
|
||||||
console.log('onClickResource', data);
|
|
||||||
}
|
|
||||||
function onClickHeadResources(data) {
|
|
||||||
console.log('onClickHeadResources', data);
|
|
||||||
}
|
|
||||||
function onClickInterval(data) {
|
|
||||||
console.log('onClickInterval', data);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
8
src/pages/schedule/BoatScheduleView.vue
Normal file
8
src/pages/schedule/BoatScheduleView.vue
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
<q-page padding>
|
||||||
|
<!-- content -->
|
||||||
|
</q-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
@@ -1,5 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page padding> </q-page>
|
<q-page padding>
|
||||||
|
<q-item v-for="link in navlinks" :key="link.label">
|
||||||
|
<q-btn
|
||||||
|
:icon="link.icon"
|
||||||
|
color="primary"
|
||||||
|
size="1.25em"
|
||||||
|
:to="link.to"
|
||||||
|
:label="link.label"
|
||||||
|
rounded
|
||||||
|
class="full-width"
|
||||||
|
align="left"
|
||||||
|
/>
|
||||||
|
</q-item>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
const navlinks = [
|
||||||
|
{
|
||||||
|
icon: 'more_time',
|
||||||
|
to: '/schedule/book',
|
||||||
|
label: 'Create a Reservation',
|
||||||
|
},
|
||||||
|
{ icon: 'calendar_month', to: '/schedule/view', label: 'View Schedule' },
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ import IndexPageVue from 'src/pages/IndexPage.vue';
|
|||||||
import ProfilePageVue from 'src/pages/ProfilePage.vue';
|
import ProfilePageVue from 'src/pages/ProfilePage.vue';
|
||||||
import TaskPageVue from 'src/pages/TaskPage.vue';
|
import TaskPageVue from 'src/pages/TaskPage.vue';
|
||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
import BoatReservationPageVue from 'src/pages/schedule/BoatReservationPage.vue';
|
|
||||||
import SchedulePageView from 'pages/schedule/SchedulePageView.vue';
|
import SchedulePageView from 'pages/schedule/SchedulePageView.vue';
|
||||||
|
import BoatReservationPageVue from 'src/pages/schedule/BoatReservationPage.vue';
|
||||||
|
import BoatScheduleViewVue from 'src/pages/schedule/BoatScheduleView.vue';
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
@@ -48,6 +49,11 @@ const routes: RouteRecordRaw[] = [
|
|||||||
component: BoatReservationPageVue,
|
component: BoatReservationPageVue,
|
||||||
name: 'reserve-boat',
|
name: 'reserve-boat',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'view',
|
||||||
|
component: BoatScheduleViewVue,
|
||||||
|
name: 'boat-schedule',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import { defineStore } from 'pinia';
|
|||||||
// const boatSource = null;
|
// const boatSource = null;
|
||||||
|
|
||||||
export interface Boat {
|
export interface Boat {
|
||||||
id: number;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
class: string;
|
class?: string;
|
||||||
year: number;
|
year?: number;
|
||||||
imgsrc: string;
|
imgsrc?: string;
|
||||||
|
iconsrc?: string;
|
||||||
booking?: {
|
booking?: {
|
||||||
available: boolean;
|
available: boolean;
|
||||||
requiredCerts: string[];
|
requiredCerts: string[];
|
||||||
@@ -18,27 +19,46 @@ export interface Boat {
|
|||||||
type: string;
|
type: string;
|
||||||
severity: string;
|
severity: string;
|
||||||
description: string;
|
description: string;
|
||||||
detail: string;
|
detail?: string;
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSampleData = () => [
|
const getSampleData = () => [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: '1',
|
||||||
name: 'ProjectX',
|
name: 'ProjectX',
|
||||||
class: 'J/27',
|
class: 'J/27',
|
||||||
year: 1981,
|
year: 1981,
|
||||||
imgsrc: '/src/assets/j27.png',
|
imgsrc: '/src/assets/j27.png',
|
||||||
|
iconsrc: '/src/assets/projectx_avatar256.png',
|
||||||
|
defects: [
|
||||||
|
{
|
||||||
|
type: 'engine',
|
||||||
|
severity: 'moderate',
|
||||||
|
description: 'Fuel line leaks at engine fitting.',
|
||||||
|
detail: `The gasket in the end of the fuel hose is damaged, and does not properly seal.
|
||||||
|
This will cause fuel to leak, and will allow air into the fuel chamber, causing a lean mixture,
|
||||||
|
and rough engine performance.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'rigging',
|
||||||
|
severity: 'moderate',
|
||||||
|
description: 'Tiller extension is broken.',
|
||||||
|
detail:
|
||||||
|
'The tiller extension swivel is broken, and will not attach to the tiller.',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: '2',
|
||||||
name: 'Take5',
|
name: 'Take5',
|
||||||
class: 'J/27',
|
class: 'J/27',
|
||||||
year: 1985,
|
year: 1985,
|
||||||
imgsrc: '/src/assets/j27.png',
|
imgsrc: '/src/assets/j27.png',
|
||||||
|
iconsrc: '/src/assets/take5_avatar32.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: '3',
|
||||||
name: 'WeeBeestie',
|
name: 'WeeBeestie',
|
||||||
class: 'Capri 25',
|
class: 'Capri 25',
|
||||||
year: 1989,
|
year: 1989,
|
||||||
|
|||||||
41
src/stores/booking.ts
Normal file
41
src/stores/booking.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { Boat } from './boat';
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
export type Booking = {
|
||||||
|
start: string;
|
||||||
|
title: string;
|
||||||
|
duration: number;
|
||||||
|
left?: number;
|
||||||
|
width?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useBookingStore = defineStore('bookings', () => {
|
||||||
|
const bookings = reactive<{ [key: string]: Booking[] }>({
|
||||||
|
1: [
|
||||||
|
{ start: '06:00', title: 'John Smith', duration: 90 },
|
||||||
|
{ start: '12:00', title: 'Bob Barker', duration: 60 },
|
||||||
|
],
|
||||||
|
2: [
|
||||||
|
{ start: '08:00', title: 'Peter Parker', duration: 120 },
|
||||||
|
{ start: '11:00', title: 'Vince McMahon', duration: 240 },
|
||||||
|
],
|
||||||
|
3: [
|
||||||
|
{ start: '08:00', title: 'Heather Graham', duration: 240 },
|
||||||
|
{ start: '14:00', title: 'Lawrence Fishburne', duration: 60 },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// So nested... Trying to do something perhaps too complicated?
|
||||||
|
// const bookingsForResource = (boatid: string) => (bookings) => {
|
||||||
|
// return bookings.filter((booking: Booking) => booking.key == boatid )
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
// actions: {
|
||||||
|
// increment () {
|
||||||
|
// this.counter++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
return { bookings };
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user