%PDF- %PDF-
Direktori : /home/forge/takeaseat.eco-n-tech.co.uk/pages/booking/ |
Current File : //home/forge/takeaseat.eco-n-tech.co.uk/pages/booking/_slug.vue |
<template> <div class="page-wrapper"> <div class="py-10 sm:py-20 bg-white"> <div class="relative z-20 text-center"> <figure class="relative inline-block w-32 mb-4 sm:mb-8"> <div :class="'tas-border-'+therapist.colour" class="absolute top-0 left-0 w-full h-full border-15"></div> <img class="block w-full" :src="therapist.user.photo_url" :alt="therapist.user.first_name" /> </figure> <h1> <span class="block w-full text-5xl md:text-7xl leading-none ">{{ therapist.user.first_name }}</span> <span class="block w-full uppercase text-2xl">{{ therapist.user.last_name }}</span> </h1> </div> </div> <div class="bg-gray px-4 py-6 sm:py-10 sm:px-8 md:py-20"> <div class="max-w-lg w-full mx-auto"> <div class="py-8 px-6 sm:py-12 sm:px-16 rounded-xl bg-white"> <template v-if="step == 1"> <ValidationObserver ref="bookingStepOne"> <form @submit.prevent="summaryStep" role="form" method="POST"> <span class="block text-center text-3xl font-bold mb-6">Your Session</span> <t-calendar @user-date-changed="changeDates" v-model="selected_dates" multiple :minDate="minDate" :maxDate="maxDate" :yearsPerView="1" :disabledDates="getDisabledDates" inline></t-calendar> <div class="mb-6"> <span class="block font-bold mb-3">Select time</span> <div class="flex items-center justify-center" v-if="loading == true"> <svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-current" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> </svg> Loading Times... </div> <div v-else-if="availability.length !== 0 || availability.length == undefined"> <div class="mb-3" v-for="(date, key) in availability" v-bind:key="key"> <template v-if="date.length > 0"> <span class="block mb-2 font-bold">{{ $moment(key).format('DD/MM/Y') }}</span> <div class="grid grid-cols-2 sm:grid-cols-3 gap-3"> <label v-for="(slot, index) in date" v-bind:key="index" :class="selected_slots[key].slot == slot.start ? 'bg-yellow' : ''" class="border border-black px-3 py-2 rounded-md cursor-pointer text-center text-sm"> <input class="hidden" @change="changeTimeSlot(key, slot)" v-model="selected_slots[key].slot" type="radio" :id="'times-'+index" :name="'times-'+index" :value="slot.start" /> {{ $moment.utc(slot.start).format('H:mm') }} </label> </div> <div class="mt-4 mb-6"> <span class="block text-sm font-bold mb-2">Session type</span> <div class="grid grid-cols-2 sm:grid-cols-3 gap-3 mb-3" v-if="selected_slots[key].session_types"> <label v-for="(item, session_key) in selected_slots[key].session_types" v-bind:key="session_key" :class="item.id == selected_slots[key].session_id ? 'bg-yellow' : ''" class="border border-black px-3 py-2 rounded-md cursor-pointer text-center text-sm"> <input class="hidden" v-model="selected_slots[key].session_id" type="radio" :name="'session-'+key" :value="item.id" /> {{ item.name }} </label> </div> <div v-else> <p>No session types available.</p> </div> <div class="relative pl-10 mb-3 px-3 py-2 text-sm leading-5 rounded bg-blue text-white" v-if="selected_slots[key].session_id == 3 && selected_slots[key].address && selected_slots[key].address.address_type !== 'Personal'"> <svg class="absolute top-2 left-3 w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg> <span>This session will be at: {{ selected_slots[key].address.formatted }}</span> </div> <t-radio-group :classes="{ groupWrapper: 'grid grid-cols-2 sm:grid-cols-3 gap-3', label: 'block pl-2.5', input: 'rounded-md w-5 h-5 text-black transition duration-100 ease-in-out border-gray-300 shadow-sm focus:border-black focus:ring-2 focus:ring-black focus:outline-none focus:ring-opacity-50 focus:ring-offset-0 disabled:opacity-50 disabled:cursor-not-allowed', inputWrapper: 'inline-flex', wrapper: 'flex items-center my-1', }" v-model="selected_slots[key].product_id" textAttribute="type" valueAttribute="id" :name="'product-'+key" :options="therapist.products"></t-radio-group> </div> </template> <template v-else> <span class="block mb-2 text-sm font-bold">{{ $moment(key).format('DD/MM/Y') }}</span> <p>No availability for this day</p> </template> </div> </div> <div v-else> <p>No availability found</p> </div> </div> <div class="mt-6 flex items-center justify-center"> <button :disabled="isSlotSelected == false" @click="getSummary" class="btn btn-primary btn-small rounded-full w-full sm:w-auto" type="button">Next</button> </div> </form> </ValidationObserver> </template> <SummaryStep v-if="step == 2" v-model="step" :selected_slots="selectedSlots" :working="working" :nextStep="getPaymentStep" button_text="Proceed to Payment" /> <RegisterStep v-if="step == 3" v-model="step" /> <PaymentStep v-if="step == 4" v-model="step" :selected_slots="selectedSlots" /> </div> </div> </div> </div> </template> <script> export default { head () { return { titleTemplate: 'Book '+this.full_name+' | %s' } }, data() { return { step: 1, isLoaded: true, loading: false, working: false, timer: null, minDate: null, maxDate: null, availability: {}, available_dates: [], selected_dates: [], selected_slots: {} } }, computed: { is_logged_in() { return this.$auth.loggedIn; }, therapist() { return this.$store.state.booking.therapist }, full_name() { return this.therapist.user.full_name; }, isSlotSelected() { const object = this.selected_slots; for (const [key, value] of Object.entries(object)) { if(value.slot !== null && value.session_id !== null && value.product_id !== null) { return true; } } return false; }, selectedSlots() { const slots = this.selected_slots; return Object.keys(slots) .filter(key => slots[key].slot !== null && slots[key].session_id !== null && slots[key].product_id !== null) .reduce((obj, key) => { return { ...obj, [key]: slots[key] }; }, {}); } }, async mounted() { let query = this.$route.query; let today = new Date(); // Set some defaults this.minDate = this.$moment(today).add(1, 'days').format('Y-MM-DD'); await this.$axios.post('/availability/'+this.therapist.id, { dates: this.selected_dates }).then((response) => { this.loading = false; this.availability = response.data.availability; this.available_dates = response.data.available_dates; // Add the dates to the calendar this.minDate = this.available_dates[0]; this.maxDate = this.available_dates[this.available_dates.length - 1]; this.selected_dates = [this.available_dates[0]]; }).catch((response) => { this.loading = false; this.$toast.error(response).goAway(3000) }) }, async asyncData({ store, params }) { await store.dispatch('booking/get', params.slug) }, methods: { changeDates() { if (this.timer) { clearTimeout(this.timer); this.timer = null; } this.timer = setTimeout(() => { this.getTimes() }, 250); }, changeTimeSlot(key, slot) { this.selected_slots[key].session_types = slot.session_types // Set address if it exists if(slot.address !== null) { this.selected_slots[key].address = slot.address this.selected_slots[key].address_id = slot.address.id; } }, async getTimes() { let query = this.$route.query; this.loading = true; await this.$axios.post('/availability/'+this.therapist.id, { dates: this.selected_dates }).then((response) => { this.loading = false; this.availability = response.data.availability; this.available_dates = response.data.available_dates; this.selected_slots = response.data.selected_slots; // Add the dates to the calendar this.minDate = this.available_dates[0]; this.maxDate = this.available_dates[this.available_dates.length - 1]; if(this.isLoaded == true && query.time !== undefined && query.date !== undefined) { this.selected_slots[query.date].slot = query.time; this.selected_slots[query.date].product_id = this.therapist.products[0].id; if(this.availability[query.date][0].address) { this.selected_slots[query.date].address_id = this.availability[query.date][0].address.id; this.selected_slots[query.date].address = this.availability[query.date][0].address; } if(this.availability[query.date][0].session_types) { this.selected_slots[query.date].session_types = this.availability[query.date][0].session_types; this.selected_slots[query.date].session_id = this.availability[query.date][0].session_types[0].id; } this.isLoaded = false; } }).catch((response) => { this.loading = false; this.$toast.error(response).goAway(3000) }) }, async getSummary() { this.$refs.bookingStepOne.validate().then(success => { if (!success) { return; } this.step = 2; }); }, async getPaymentStep() { if(this.is_logged_in == false) { this.step = 3; } else { this.step = 4; } }, getDisabledDates(rawDate) { var date = this.$moment(rawDate).format('Y-MM-DD') return !this.available_dates.includes(date); } } } </script>