Files
bab-app/src/components/scheduling/boat/BoatScheduleTableComponent.vue

269 lines
7.1 KiB
Vue

<template>
<div>
<CalendarHeaderComponent v-model="selectedDate" />
<div class="boat-schedule-table-component">
<QCalendarDay
ref="calendar"
class="q-pa-xs"
flat
animated
dense
:disabled-before="disabledBefore"
interval-height="24"
interval-count="18"
interval-start="06:00"
:short-interval-label="true"
v-model="selectedDate"
:column-count="boatData.length"
@change="changeEvent"
v-touch-swipe.left.right="handleSwipe"
>
<template #head-day="{ scope }">
<div style="text-align: center; font-weight: 800">
{{ getBoatDisplayName(scope) }}
</div>
</template>
<template #day-body="{ scope }">
<div v-for="block in getBoatBlocks(scope)" :key="block.$id">
<div
class="timeblock"
:class="selectedBlock?.$id === block.$id ? 'selected' : ''"
:style="
blockStyles(block, scope.timeStartPos, scope.timeDurationHeight)
"
:id="block.id"
@click="selectBlock($event, scope, block)"
>
{{ boatData[scope.columnIndex].name }}<br />
{{ selectedBlock?.$id === block.$id ? 'Selected' : 'Available' }}
</div>
</div>
<!-- <div
v-for="r in boatData[scope.columnIndex].reservations"
:key="r.id"
>
<div
class="reservation"
:style="
reservationStyles(
r,
scope.timeStartPos,
scope.timeDurationHeight
)
"
>
{{ r.user }}
</div>
</div> -->
</template>
</QCalendarDay>
</div>
</div>
</template>
<script setup lang="ts">
import {
QCalendarDay,
Timestamp,
diffTimestamp,
today,
parseTimestamp,
parseDate,
addToDate,
makeDateTime,
} from '@quasar/quasar-ui-qcalendar';
import CalendarHeaderComponent from './CalendarHeaderComponent.vue';
import { ref, computed, onMounted } from 'vue';
import { Boat, useBoatStore } from 'src/stores/boat';
import { useScheduleStore } from 'src/stores/schedule';
import { Reservation, Timeblock } from 'src/stores/schedule.types';
import { date } from 'quasar';
const scheduleStore = useScheduleStore();
const boatStore = useBoatStore();
const boatData = boatStore.boats;
const selectedBlock = defineModel<Timeblock | null>();
const selectedDate = ref(today());
const calendar = ref<QCalendarDay | null>(null);
onMounted(async () => {
await boatStore.fetchBoats();
await scheduleStore.fetchTimeBlocks();
// useScheduleStore().fetchReservations()
}); // TODO: Probably need this to be more sophisticated.
function handleSwipe({ ...event }) {
event.direction === 'right' ? calendar.value?.prev() : calendar.value?.next();
}
function reservationStyles(
reservation: Reservation,
timeStartPos: (t: string) => string,
timeDurationHeight: (d: number) => string
) {
return genericBlockStyle(
parseDate(reservation.start) as Timestamp,
parseDate(reservation.end) as Timestamp,
timeStartPos,
timeDurationHeight
);
}
function blockStyles(
block: Timeblock,
timeStartPos: (t: string) => string,
timeDurationHeight: (d: number) => string
) {
return genericBlockStyle(
parseDate(new Date(block.start)) as Timestamp,
parseDate(new Date(block.end)) as Timestamp,
timeStartPos,
timeDurationHeight
);
}
function getBoatDisplayName(scope: DayBodyScope) {
return boatData && boatData.value[scope.columnIndex]
? boatData.value[scope.columnIndex].displayName
: '';
}
function genericBlockStyle(
start: Timestamp,
end: Timestamp,
timeStartPos: (t: string) => string,
timeDurationHeight: (d: number) => string
) {
const s = {
top: '',
height: '',
opacity: '',
};
if (timeStartPos && timeDurationHeight) {
s.top = timeStartPos(start.time) + 'px';
s.height =
parseInt(
timeDurationHeight(diffTimestamp(start, end, false) / 1000 / 60)
) -
1 +
'px';
}
// if (selectedBlock.value?.id === block.id) {
// s.opacity = '1.0';
// }
return s;
}
interface DayBodyScope {
columnIndex: number;
timeDurationHeight: string;
timeStartPos: (time: string, clamp: boolean) => string;
timestamp: Timestamp;
}
function selectBlock(event: MouseEvent, scope: DayBodyScope, block: Timeblock) {
// TODO: Disable blocks before today with updateDisabled and/or comparison
selectedBlock.value === block
? (selectedBlock.value = null)
: (selectedBlock.value = block);
}
interface BoatBlocks {
[key: string]: Timeblock[];
}
const boatBlocks = computed((): BoatBlocks => {
return scheduleStore
.getTimeblocksForDate(selectedDate.value)
.reduce((result, tb) => {
if (!result[tb.boatId]) result[tb.boatId] = [];
result[tb.boatId].push(tb);
return result;
}, <BoatBlocks>{});
});
function getBoatBlocks(scope: DayBodyScope): Timeblock[] {
return boatData.value[scope.columnIndex]
? boatBlocks.value[boatData.value[scope.columnIndex].$id]
: [];
}
function changeEvent({ start }: { start: string }) {
// const newBlocks = scheduleStore.getTimeblocksForDate(start);
// const reservations = scheduleStore.getBoatReservations(
// parsed(start) as Timestamp
// );
// boatData.value.map((boat) => {
// boat.reservations = reservations.filter(
// (reservation) => reservation.resource === boat
// );
// boat.blocks = newBlocks.filter(
// (block) =>
// block.boatId === boat.$id &&
// boat.reservations?.filter(
// (r: Reservation) =>
// r.start <
// date.addToDate(makeDateTime(parsed(block.end) as Timestamp), {
// hours: 4,
// }) &&
// r.end >
// date.addToDate(makeDateTime(parsed(block.start) as Timestamp), {
// hours: 4,
// })
// ).length == 0
// );
// });
// setTimeout(() => calendar.value?.scrollToTime('09:00'), 100); // Should figure out why we need this setTimeout...
}
const disabledBefore = computed(() => {
const todayTs = parseTimestamp(today()) as Timestamp;
return addToDate(todayTs, { day: -1 }).date;
});
</script>
<style lang="sass">
.boat-schedule-table-component
display: flex
max-height: 60vh
max-width: 98vw
.reservation
display: flex
position: absolute
justify-content: center
align-items: center
text-align: center
width: 100%
opacity: 1
margin: 0px
text-overflow: ellipsis
font-size: 0.8em
cursor: pointer
background: $accent
color: white
border: 1px solid black
.timeblock
display: flex
position: absolute
justify-content: center
text-align: center
align-items: center
width: 100%
opacity: 0.5
margin: 0px
text-overflow: ellipsis
font-size: 0.8em
cursor: pointer
background: $primary
color: white
border: 1px solid black
.selected
opacity: 1 !important
.q-calendar-day__interval--text
font-size: 0.8em
.q-calendar-day__day.q-current-day
padding: 1px
</style>