CSR-1137 | Initial creation of time-slot modal

This commit is contained in:
Scott Kiener 2023-05-08 09:25:57 -04:00
parent 8fe6155812
commit 491f6b273a
6 changed files with 170 additions and 5 deletions

View file

@ -13,4 +13,6 @@ const monthsOfYear = [
"December",
];
export { monthsOfYear };
const daysOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
export { monthsOfYear, daysOfWeek };

View file

@ -119,7 +119,6 @@ export default {
isRequired: Boolean,
isOverflowScrollable: Boolean,
isWide: Boolean,
isCashOrInsurance: Boolean,
modelValue: [Array, Number, String],
value: [Number, String],
validationRules: String,

View file

@ -56,6 +56,13 @@ export default {
onModalClosedCallback: {
type: Function,
},
allowManualFooterDisableOverride: {
type: Boolean,
default: false,
},
isFooterDisabledManualOverride: {
type: Boolean,
},
},
setup() {
const modalId = `modal-${crypto.randomUUID()}`;
@ -98,10 +105,13 @@ export default {
},
computed: {
isFooterButtonDisabled() {
if (!this.meta.touched) {
if (this.allowManualFooterDisableOverride !== null) {
return this.isFooterDisabledManualOverride;
} else if (!this.meta.touched) {
return !this.meta.valid;
} else {
return !this.meta.dirty || !this.meta.valid;
}
return !this.meta.dirty || !this.meta.valid;
},
},
components: {

View file

@ -1,6 +1,6 @@
<template>
<div
class="text-block w-100 mt-2"
class="text-block w-100 mt-2 d-flex"
:class="[justifyText, typeStyle, fontWeight]"
v-html="this.TextBlockCopy"></div>
</template>

View file

@ -23,6 +23,14 @@
selectableDatesSetting="custom"
v-model="selectedDate"
:customSelectableDatesCallback="getAvailableDates" />
<time-slot-selection-modal
ref="timeSlotModal"
v-model="selectedTimeSlot"
:dateForTimeSlotPicker="dateForTimeSlotPicker"
:availableTimeSlots="availableTimeSlots"
estimatedServiceMinutesMinimum="90"
estimatedServiceMinutesMaximum="180" />
<button @click="openModal">Click for timeslots</button>
<funnel-footer
cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter"
@ -41,6 +49,7 @@ import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-heade
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import { Form, defineRule } from "vee-validate";
import datePicker from "@/digital-components/date-picker/date-picker";
import timeSlotSelectionModal from "./time-slot-selection-modal/time-slot-selection-modal";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
@ -56,6 +65,7 @@ import {
} from "@/helpers/cms-content-helper";
import { errorMessages } from "@/constants/error-messages";
import { required } from "@/helpers/validation-rules";
import { daysOfWeek, monthsOfYear } from "@/constants/scheduling.js";
defineRule("date-required", required(errorMessages.DATE_REQUIRED));
@ -64,6 +74,31 @@ export default {
data() {
return {
selectedDate: null,
selectedTimeSlot: null,
dateForTimeSlotPicker: new Date("May 23 2023"),
availableTimeSlots: [
"8:00 AM",
"10:30 AM",
"11:00 AM",
"12:30 AM",
"1:00 PM",
"2:00 PM",
"4:30 PM",
"8:00 AM",
"10:30 AM",
"11:00 AM",
"12:30 AM",
"1:00 PM",
"2:00 PM",
"4:30 PM",
"8:00 AM",
"10:30 AM",
"11:00 AM",
"12:30 AM",
"1:00 PM",
"2:00 PM",
"4:30 PM",
],
mockSelectableDatesData: [
{ dateString: "2023-04-28" },
@ -202,6 +237,12 @@ export default {
// Splits content when brackets are found in text so that text can be looped through and router-link can be injected when needed
return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
},
DateSelectedReadableDate() {
const dayOfWeek = this.dateForTimeSlotPicker.getDay();
const month = this.dateForTimeSlotPicker.getMonth();
const dayOfMonth = this.dateForTimeSlotPicker.getDate();
return `${daysOfWeek[dayOfWeek]}, ${monthsOfYear[month]} ${dayOfMonth}`;
},
},
methods: {
doesCopyContainRouterLink,
@ -250,6 +291,9 @@ export default {
});
return responseData;
},
openModal() {
this.$refs["timeSlotModal"].openModal();
},
backButtonAction() {
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
},
@ -264,6 +308,7 @@ export default {
Form,
loadingModal,
datePicker,
timeSlotSelectionModal,
},
};
</script>

View file

@ -0,0 +1,109 @@
<template>
<modal
ref="timeSlots"
class="time-slots-modal"
:headerText="dateSelectedReadableDate"
footerButtonText="Save time slot"
allowManualFooterDisableOverride
:isFooterDisabledManualOverride="currentlySelectedTimeSlot === null"
:onModalOpenedCallback="onModalOpened"
:onModalClosedCallback="onModalClosed"
@footer-button-event="closeModal">
<textBlock
cmsWidgetName="appointmentDuration"
:customText="durationSubHeaderText"
justifyText="center"
typeStyle="small"
class="mb-5" />
<buttonQuestion
class="radioQuestion"
:answers="availableTimeSlots"
groupName="ChooseTimeSlot"
textPosition="text-center"
v-model="currentlySelectedTimeSlot"
isRequired />
</modal>
</template>
<script>
// Components
import modal from "@/digital-components/modal/modal";
import textBlock from "@/digital-components/text-block/text-block";
import buttonQuestion from "@/digital-components/button-question/button-question";
import { daysOfWeek, monthsOfYear } from "@/constants/scheduling.js";
export default {
name: "timeSlotSelectionModal",
props: {
modelValue: Object,
dateForTimeSlotPicker: Date,
availableTimeSlots: Array,
estimatedServiceMinutesMinimum: Number,
estimatedServiceMinutesMaximum: Number,
},
data() {
return {
currentlySelectedTimeSlot: null,
};
},
watch: {
modelValue() {
this.currentlySelectedTimeSlot = this.modelValue;
},
},
computed: {
dateSelectedReadableDate() {
const weekdayName = daysOfWeek[this.dateForTimeSlotPicker.getDay()];
const month = monthsOfYear[this.dateForTimeSlotPicker.getMonth()];
const numberDayOfMonth = this.dateForTimeSlotPicker.getDate();
// Ex. Tuesday, April 23
return `${weekdayName}, ${month} ${numberDayOfMonth}`;
},
durationSubHeaderText() {
let durationSubHeaderText = "Duration: ";
if (this.estimatedServiceMinutesMaximum >= 120) {
durationSubHeaderText += `${this.estimatedServiceMinutesMinimum / 60} - ${
this.estimatedServiceMinutesMaximum / 60} hours`;
} else {
durationSubHeaderText += `${this.estimatedServiceMinutesMinimum} - ${this.estimatedServiceMinutesMaximum} minutes`
}
return durationSubHeaderText;
},
},
methods: {
openModal() {
this.$refs["timeSlots"].openModal();
},
// fires any time the footer button is used, is fired before "onModalClosed"
closeModal() {
this.$emit("update:modelValue", this.currentlySelectedTimeSlot);
this.$refs["timeSlots"].closeModal("test");
},
// fires any time the modal is closed, AFTER "closeModal" fires if footer button is used
onModalClosed() {
this.currentlySelectedTimeSlot = this.modelValue;
},
},
components: {
modal,
textBlock,
buttonQuestion,
},
};
</script>
<style lang="scss">
.time-slots-modal.modal.modal-component {
> .modal-dialog > .modal-content {
margin-top: 24px;
}
.modal-header {
padding-bottom: 0;
margin-bottom: 0 !important;
}
.text-block {
margin-top: 0 !important;
}
}
</style>