You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
6.4 KiB
Vue

<template>
<div class="Home">
<VDatePicker class="dateSelector" v-model.range="range" mode="date" :rules="datePickerRules" timezone="utc"
:input-debounce="50" />
<CenterSelector class="centerSelector" @selectionChanged="centerSelectionChanged"></CenterSelector>
<TrainerSelector class="trainerSelector" v-bind:centers="centers" @selectionChanged="trainerSelectionChanged">
</TrainerSelector>
<div class="trainers">
<div class="trainer" v-for="trainer in trainersWithDateGroupedTimeslots" :key="trainer.id">
<div class="top">
{{ trainer.first_name }} {{ trainer.last_name }}
</div>
<div class="dates">
<div class="date" v-for="date in trainer.dates">
{{ date.date }}
<div class="timeslots">
<div class="timeslot" v-for="timeslot in date.timeslots"
@click="createOrder(trainer, timeslot)">
{{ formatTime(timeslot.startDate) }} - {{ formatTime(timeslot.endDate) }}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- {{ trainersWithTimeslots }} -->
</div>
</template>
<style scoped>
.Home {
display: grid;
grid-template-columns: 1fr 3fr 1fr;
grid-template-rows: auto auto auto;
grid-column-gap: 50px;
grid-row-gap: 30px;
padding: 50px;
}
.dateSelector {
grid-area: 1 / 1 / 2 / 2;
}
.centerSelector {
grid-area: 1 / 3 / 2 / 4;
}
.trainerSelector {
grid-area: 2 / 3 / 3 / 4;
}
.trainers {
grid-area: 1 / 2 / 4 / 3;
display: flex;
gap: 10px;
flex-direction: column;
}
.trainer .top {
border-bottom: 1px solid #cbd5e1;
padding: 20px;
font-size: large;
}
.trainer {
border: 1px solid #cbd5e1;
border-radius: 0.5rem;
}
.dates {
padding: 20px;
}
.timeslots {
border-top: 1px solid #cbd5e1;
display: flex;
flex-wrap: wrap;
}
.timeslot {
padding: 5px;
border: 1px solid #cbd5e1;
margin: 5px;
cursor: pointer;
}
.timeslot:hover {
border-color: black;
}
</style>
<script lang="ts">
import CenterSelector from '@/components/CenterSelector.vue';
import TrainerSelector from '@/components/TrainerSelector.vue';
import type { Timeslot } from '@/interfaces/timeslot';
import type { DateGroupedTimeslots, DateGroupedTimeslotsList, TrainerWithDateGroupedTimeslots, TrainerWithTimeslots } from '@/interfaces/trainerWithTimeslots';
import dayjs from 'dayjs';
import LocalizedFormat from "dayjs/plugin/localizedFormat"
import utc from "dayjs/plugin/utc"
import { } from "dayjs/locale/da";
import type { Trainer } from '@/interfaces/trainer';
dayjs.extend(LocalizedFormat);
dayjs.extend(utc);
export default {
name: "Home",
components: {
CenterSelector,
TrainerSelector
},
data() {
return {
range: {
start: new Date(),
end: new Date()
},
datePickerRules: {
hours: 0,
minutes: 0,
seconds: 0,
milliseconds: 0
},
centers: [] as number[],
trainers: [] as number[],
trainersWithTimeslots: [] as TrainerWithTimeslots[]
}
},
computed: {
trainersWithDateGroupedTimeslots() {
return this.trainersWithTimeslots.map(trainer => {
const dates: DateGroupedTimeslotsList = {};
trainer.timeslots.forEach(timeslot => {
const day: string = new Date(timeslot.startDate).toISOString().split("T")[0];
if (!dates[day]) {
dates[day] = {
date: this.formatDate(new Date(day)),
timeslots: [] as Timeslot[]
};
}
dates[day].timeslots.push(timeslot);
});
const trainerWithDateGroupedTimeslots: TrainerWithDateGroupedTimeslots = { ...trainer, dates };
return trainerWithDateGroupedTimeslots;
});
}
},
watch: {
centers: {
handler() {
this.fetchTimeslots();
},
deep: true
},
trainers: {
handler() {
this.fetchTimeslots();
},
deep: true
},
range: {
handler() {
this.fetchTimeslots();
},
deep: true
}
},
methods: {
createOrder(trainer: Trainer, timeslot: Timeslot) {
this.$router.push({
path: "/createOrder", query: {
trainer: trainer.id,
startDate: new Date(timeslot.startDate).toISOString(),
endDate: new Date(timeslot.endDate).toISOString()
}
});
},
formatDate(date: Date): string {
let output: string = dayjs(date).locale("da").format("dddd D. MMM YYYY");
let outputStringArray = output.split("");
outputStringArray[0] = outputStringArray[0].toLocaleUpperCase();
output = outputStringArray.join("");
return output;
},
formatTime(date: Date): string {
let output: string = dayjs(date).utcOffset(0).locale("da").format("HH:mm");
return output;
},
centerSelectionChanged(selection: number[]) {
this.centers = selection;
},
trainerSelectionChanged(selection: number[]) {
this.trainers = selection;
},
async fetchTimeslots() {
const centerFilters = this.centers.map(c => `center=${c}`);
const trainerFilters = this.trainers.map(c => `trainer=${c}`);
const startDateFilter = `startDate=${this.range.start.toISOString()}`;
const endDateFilter = `endDate=${this.range.end.toISOString()}`;
const filters = [...centerFilters, ...trainerFilters, startDateFilter, endDateFilter].join("&");
const res = await fetch(`${import.meta.env.VITE_BASE_API_URL}/timeslot?${filters}`);
if (res.status === 200) {
this.trainersWithTimeslots = await res.json();
}
}
}
}
</script>