227 lines
7.0 KiB
Vue
227 lines
7.0 KiB
Vue
<template>
|
|
<div class="q-pa-xs row q-gutter-xs">
|
|
<q-card
|
|
flat
|
|
class="col-lg-4 col-md-6 col-sm-8 col-xs-12">
|
|
<q-card-section>
|
|
<div class="text-h5 q-mt-none q-mb-xs">New Booking</div>
|
|
<div class="text-caption text-grey-8">for: {{ bookingForm.name }}</div>
|
|
</q-card-section>
|
|
<q-list class="q-px-xs">
|
|
<q-separator />
|
|
<q-item
|
|
class="q-px-none"
|
|
clickable
|
|
@click="boatSelect = true">
|
|
<q-item-section>
|
|
<q-card
|
|
v-if="bookingForm.boat"
|
|
flat>
|
|
<q-card-section>
|
|
<q-img
|
|
:src="bookingForm.boat?.imgSrc"
|
|
:fit="'scale-down'">
|
|
<div class="row absolute-top">
|
|
<div class="col text-h7 text-left">
|
|
{{ bookingForm.boat?.name }}
|
|
</div>
|
|
<div class="col text-right text-caption">
|
|
{{ bookingForm.boat?.class }}
|
|
</div>
|
|
</div>
|
|
</q-img>
|
|
</q-card-section>
|
|
<q-separator />
|
|
<q-card-section horizontal>
|
|
<q-card-section>
|
|
<q-list
|
|
dense
|
|
class="row">
|
|
<q-item>
|
|
<q-item-section avatar>
|
|
<q-badge
|
|
color="primary"
|
|
label="Start" />
|
|
</q-item-section>
|
|
<q-item-section class="text-body2">
|
|
{{
|
|
date.formatDate(
|
|
new Date(bookingForm.startDate as string),
|
|
'ddd MMM Do hh:mm A'
|
|
)
|
|
}}
|
|
</q-item-section>
|
|
</q-item>
|
|
<q-item class="q-ma-none">
|
|
<q-item-section avatar>
|
|
<q-badge
|
|
color="primary"
|
|
label="End" />
|
|
</q-item-section>
|
|
<q-item-section class="text-body2">
|
|
{{
|
|
date.formatDate(
|
|
new Date(bookingForm.endDate as string),
|
|
'ddd MMM Do hh:mm A'
|
|
)
|
|
}}
|
|
</q-item-section>
|
|
</q-item>
|
|
</q-list>
|
|
</q-card-section>
|
|
<q-separator vertical />
|
|
<q-card-section class="col-3 flex flex-center bg-grey-4">
|
|
{{ bookingDuration.hours }} hours
|
|
<div v-if="bookingDuration.minutes">
|
|
<q-separator />
|
|
{{ bookingDuration.minutes }} mins
|
|
</div>
|
|
</q-card-section>
|
|
</q-card-section>
|
|
</q-card>
|
|
<q-field
|
|
readonly
|
|
filled
|
|
v-else>
|
|
Tap to Select a Boat / Time
|
|
</q-field>
|
|
</q-item-section>
|
|
</q-item>
|
|
<q-item class="q-px-none">
|
|
<q-item-section>
|
|
<q-select
|
|
filled
|
|
v-model="bookingForm.reason"
|
|
:options="reason_options"
|
|
label="Reason for sail" />
|
|
</q-item-section>
|
|
</q-item>
|
|
<q-item class="q-px-none">
|
|
<q-item-section>
|
|
<q-input
|
|
v-model="bookingForm.comment"
|
|
clearable
|
|
autogrow
|
|
filled
|
|
label="Additional Comments (optional)" />
|
|
</q-item-section>
|
|
</q-item>
|
|
</q-list>
|
|
<q-card-actions align="right">
|
|
<q-btn
|
|
label="Reset"
|
|
@click="onReset"
|
|
color="secondary"
|
|
size="md" />
|
|
<q-btn
|
|
label="Submit"
|
|
@click="onSubmit"
|
|
color="primary" />
|
|
</q-card-actions>
|
|
</q-card>
|
|
<q-dialog
|
|
v-model="boatSelect"
|
|
full-width>
|
|
<BoatScheduleTableComponent v-model="interval" />
|
|
</q-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, ref, watch } from 'vue';
|
|
import { useAuthStore } from 'src/stores/auth';
|
|
import { Boat, useBoatStore } from 'src/stores/boat';
|
|
import { date, useQuasar } from 'quasar';
|
|
import { Interval, Reservation } from 'src/stores/schedule.types';
|
|
import BoatScheduleTableComponent from 'src/components/scheduling/boat/BoatScheduleTableComponent.vue';
|
|
import { getNewId } from 'src/utils/misc';
|
|
import { useRouter } from 'vue-router';
|
|
import { useReservationStore } from 'src/stores/reservation';
|
|
|
|
interface BookingForm {
|
|
bookingId: string;
|
|
name?: string;
|
|
boat?: Boat;
|
|
startDate?: string;
|
|
endDate?: string;
|
|
reason: string;
|
|
members: { name: string }[];
|
|
guests: { name: string }[];
|
|
comment?: string;
|
|
}
|
|
|
|
const reason_options = ['Open Sail', 'Private Sail', 'Racing', 'Other'];
|
|
|
|
const auth = useAuthStore();
|
|
const interval = ref<Interval>();
|
|
const newForm = {
|
|
bookingId: getNewId(),
|
|
name: auth.currentUser?.name,
|
|
boat: <Boat | undefined>undefined,
|
|
startDate: '',
|
|
endDate: '',
|
|
reason: 'Open Sail',
|
|
members: [],
|
|
guests: [],
|
|
comment: '',
|
|
};
|
|
const bookingForm = ref<BookingForm>({ ...newForm });
|
|
const router = useRouter();
|
|
const reservationStore = useReservationStore();
|
|
const $q = useQuasar();
|
|
const boatSelect = ref(false);
|
|
|
|
watch(interval, (new_interval) => {
|
|
bookingForm.value.boat = useBoatStore().boats.find(
|
|
(b) => b.$id === new_interval?.boatId
|
|
);
|
|
bookingForm.value.startDate = new_interval?.start;
|
|
bookingForm.value.endDate = new_interval?.end;
|
|
});
|
|
|
|
const bookingDuration = computed((): { hours: number; minutes: number } => {
|
|
if (bookingForm.value.startDate && bookingForm.value.endDate) {
|
|
const start = new Date(bookingForm.value.startDate).getTime();
|
|
const end = new Date(bookingForm.value.endDate).getTime();
|
|
const delta = Math.abs(end - start) / 1000;
|
|
const hours = Math.floor(delta / 3600) % 24;
|
|
const minutes = Math.floor(delta - hours * 3600) % 60;
|
|
return { hours: hours, minutes: minutes };
|
|
}
|
|
return { hours: 0, minutes: 0 };
|
|
});
|
|
|
|
const onReset = () => {
|
|
interval.value = undefined;
|
|
bookingForm.value = { ...newForm };
|
|
};
|
|
const onSubmit = () => {
|
|
const booking = bookingForm.value;
|
|
if (
|
|
!(booking.boat && booking.startDate && booking.endDate && auth.currentUser)
|
|
) {
|
|
// TODO: Make a proper validator
|
|
return;
|
|
}
|
|
const reservation = <Reservation>{
|
|
resource: booking.boat.$id,
|
|
start: booking.startDate,
|
|
end: booking.endDate,
|
|
user: auth.currentUser.$id,
|
|
status: 'confirmed',
|
|
reason: booking.reason,
|
|
comment: booking.comment,
|
|
};
|
|
console.log(reservation);
|
|
// TODO: Fix this. It will always look successful
|
|
reservationStore.createReservation(reservation); // Probably should pass the notify as a callback to the reservation creation.
|
|
$q.notify({
|
|
color: 'green-4',
|
|
textColor: 'white',
|
|
icon: 'cloud_done',
|
|
message: 'Submitted',
|
|
});
|
|
router.go(-1);
|
|
};
|
|
</script>
|