CASH-464: working without modal and validation works too

This commit is contained in:
Adam Caouette 2025-04-21 22:59:36 -04:00
parent 44671d60fe
commit 43b53c9be8
2 changed files with 276 additions and 35 deletions

View file

@ -4,6 +4,12 @@
:class="`${calendarViewDirection} ${isPricingByDayClass} ${showPricingByDayClass}`"> :class="`${calendarViewDirection} ${isPricingByDayClass} ${showPricingByDayClass}`">
<fieldset id="date-picker-fieldset" ref="datePickerFieldset"> <fieldset id="date-picker-fieldset" ref="datePickerFieldset">
<legend class="sr-only">Select a day and time</legend> <legend class="sr-only">Select a day and time</legend>
<div style="font-size: .8rem; background: aqua; padding: .2rem; text-align: left;" >
<div>componentId {{ componentId }}</div>
<div>meta {{ meta }}</div>
<div>errors {{ errors }}</div>
<div>errorMessage {{ errorMessage }}</div>
</div>
<div <div
v-for="month in months" v-for="month in months"
:key="`${month.monthLabel}-${month.yearNum?.toString()}`" :key="`${month.monthLabel}-${month.yearNum?.toString()}`"
@ -99,11 +105,46 @@
@click="showAnotherMonth"> @click="showAnotherMonth">
View more dates View more dates
</button> </button>
<div class="new-times">
<div>selectedDate: {{ selectedDate }}</div>
<div>selectedTimeSlotInfo: {{ selectedTimeSlotInfo }}</div>
<!-- <div>timeSlotsForSelectedDate: {{ timeSlotsForSelectedDate }}</div> -->
</div>
<timeSlotQuestion
ref="timeSlotModalQuestion"
v-model="selectedTimeSlotInfo"
cmsWidgetName="TimeSlotModalQuestion"
waitListLabelWidget="WaitListLabelWidget"
waitListQuestionWidget="WaitListQuestionWidget"
mobilePremiumCmsWidgetName="MobilePremiumTimeSlotModal"
mobileCmsWidgetName="MobileTimeSlotModal"
dropoffCmsWidgetName="DropOffTimeSlotModal"
sameDayDropOffCmsWidgetName="SameDayDropOffTimeSlotModal"
overnightDropOffCmsWidgetName="OvernightDropOffTimeSlotModal"
:selectedDate="selectedDate"
:appointmentType="appointmentType"
:premiumAppointmentFee="mobilePremiumAppointmentFee"
:displayWaitList="displayWaitList"
:timeSlotsForSelectedDate="timeSlotsForSelectedDate"
:estimatedServiceMinutesMinimum="
selectableDatesData.estimatedServiceMinutesMinimum
"
:estimatedServiceMinutesMaximum="
selectableDatesData.estimatedServiceMinutesMaximum
"
@waitListRequested="handleWaitListRequested"
@time-slot-modal-closed="timeSlotModalClosed"
/>
</fieldset> </fieldset>
</div> </div>
</template> </template>
<script> <script>
import timeSlotQuestion from "@/layouts/schedule/time-slot-question/time-slot-question.vue";
// Supporting files // Supporting files
import loader from "@/ux-components/loader/loader"; import loader from "@/ux-components/loader/loader";
import store from "@/store"; import store from "@/store";
@ -113,6 +154,11 @@ import {
MONTHS_OF_YEAR, MONTHS_OF_YEAR,
DAYS_OF_WEEK, DAYS_OF_WEEK,
} from "@/digital-components/date-picker/mixins/constants"; } from "@/digital-components/date-picker/mixins/constants";
import {
AppointmentTypeStrings,
PREMIUM_FEE_PART_TYPE,
PRICING_BY_DAY_PART_TYPE,
} from "@/constants/schedule-constants";
import { import {
selectableDaysOptions, selectableDaysOptions,
requiredParameter, requiredParameter,
@ -122,11 +168,25 @@ import {
convertDateToDateString, convertDateToDateString,
convertDateStringToDate, convertDateStringToDate,
} from "@/layouts/schedule/helpers/schedule-helper"; } from "@/layouts/schedule/helpers/schedule-helper";
import { useField, ErrorMessage } from "vee-validate"; import { useField, ErrorMessage, defineRule } from "vee-validate";
import { errorMessages } from "@/constants/error-messages";
import { deepClone } from "@/helpers/object-helper"; import { deepClone } from "@/helpers/object-helper";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
// DEFINE VALIDATION RULES
defineRule("time-slot-selection-required", (value) => {
console.log("%c DP - VALIDATION of time-slot-selection-required, value is: ", "background: lime; color: black;", value);
debugger; // eslint-disable-line no-debugger
if (value?.timeSlot?.routeCode == null) {
console.log("%c DP - VALIDATION of time-slot-selection-required, VALIDATION ERROR... ", "background: lime; color: black;", "TIME SLOT VALIDATION FAILURE! " + errorMessages.DATE_REQUIRED);
return "TIME SLOT VALIDATION FAILURE! " + errorMessages.DATE_REQUIRED;
}
return true;
});
export default { export default {
name: "datePicker", name: "datePicker",
data() { data() {
@ -136,6 +196,9 @@ export default {
disableViewMoreDatesButton: false, disableViewMoreDatesButton: false,
selectableDatesData: [], // NOTE: uses monthNum (1-based), NOT monthIndex (0-based) selectableDatesData: [], // NOTE: uses monthNum (1-based), NOT monthIndex (0-based)
hideSomeDaysForInitialView: null, hideSomeDaysForInitialView: null,
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
}; };
}, },
props: { props: {
@ -169,6 +232,10 @@ export default {
pricingByDayBasePrice: Number, pricingByDayBasePrice: Number,
pricingByDayUpcharge: Number, pricingByDayUpcharge: Number,
isPricingByDayExperiment: Boolean, isPricingByDayExperiment: Boolean,
// selectedTimeSlotInfo: Object,
timeSlotsForSelectedDate: Object,
}, },
setup(props) { setup(props) {
const uuid = uuidv4(); const uuid = uuidv4();
@ -184,6 +251,9 @@ export default {
initialValue: initialValue, initialValue: initialValue,
}; };
console.log("%c DP - running setup()... modelValue: ", "background: lime; color: black;", modelValue);
debugger; // eslint-disable-line no-debugger
const { errorMessage, handleBlur, handleChange, meta, validate, errors, resetField } = const { errorMessage, handleBlur, handleChange, meta, validate, errors, resetField } =
useField(componentId, props.validationRules, fieldOptions); useField(componentId, props.validationRules, fieldOptions);
@ -228,12 +298,36 @@ export default {
}, },
selectedDate: { selectedDate: {
get() { get() {
console.log("%c DP - G etting selectedDate; it is: ", "background: lime; color: black;", this.modelValue);
debugger; // eslint-disable-line no-debugger
return this.modelValue; return this.modelValue;
}, },
set(newSelectedDate) { set(newSelectedDate) {
console.log("%c DP - S etting selectedDate; it is now: ", "background: lime; color: black;", newSelectedDate);
debugger; // eslint-disable-line no-debugger
this.$emit("update:modelValue", newSelectedDate); this.$emit("update:modelValue", newSelectedDate);
}, },
}, },
// selectedTimeSlotInfo: {
// get() {
// console.log("%c DP - G etting selectedTimeSlotInfo; it is: ", "background: lime; color: black;", this.modelValue);
// debugger; // eslint-disable-line no-debugger
// return this.modelValue;
// },
// set(newSelectedTimeSlotInfo) {
// console.log("%c DP - S etting selectedTimeSlotInfo; it is now: ", "background: lime; color: black;", newSelectedTimeSlotInfo);
// debugger; // eslint-disable-line no-debugger
// this.$emit("update:modelValue", newSelectedTimeSlotInfo);
// },
// },
}, },
methods: { methods: {
initializeComponent(initialData) { initializeComponent(initialData) {
@ -744,9 +838,50 @@ export default {
}; };
window.requestAnimationFrame(step); window.requestAnimationFrame(step);
}, },
//// NEW METHODS //// NEW METHODS //// NEW METHODS //// NEW METHODS //// NEW METHODS
//// //// NEW METHODS //// NEW METHODS //// NEW METHODS //// NEW METHODS //// NEW METHODS
getSelectedTimeSlotInfo() {
const supportingItems = this.getSupportingItems();
var isPremiumAppointment = false;
if (supportingItems) {
isPremiumAppointment =
!!supportingItems.filter(
(lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE
).length > 0;
}
const selectedTimeSlotInfo = {
timeSlot: store.getters.order.schedule,
isPremiumAppointment: isPremiumAppointment,
};
console.log("%c DP - computing getSelectedTimeSlotInfo()... returning: ", "background: lime; color: black;", selectedTimeSlotInfo);
debugger; // eslint-disable-line no-debugger
return selectedTimeSlotInfo;
},
getSupportingItems() {
return store.getters.lineItems.supportingItems;
},
}, },
watch: { watch: {
modelValue(newValue, oldValue) { modelValue(newValue, oldValue) {
console.log("%c DP - WATCHED modelValue now: ", "background: lime; color: black;", newValue);
console.log(" ");
debugger; // eslint-disable-line no-debugger
this.resetField({ this.resetField({
value: newValue, value: newValue,
}); });
@ -757,10 +892,31 @@ export default {
this.scrollToElement("date-of-month-error"); this.scrollToElement("date-of-month-error");
} }
}, },
selectedDate(newValue) {
console.log("%c DP - WATCHED selectedDate now: ", "background: lime; color: black;", newValue);
console.log(" ");
debugger; // eslint-disable-line no-debugger
},
selectedTimeSlotInfo(newValue) {
console.log("%c DP - WATCHED selectedTimeSlotInfo now: ", "background: lime; color: black;", newValue);
console.log(" ");
debugger; // eslint-disable-line no-debugger
this.$emit(
"TimeSlotSelected",
newValue
);
},
}, },
components: { components: {
loader, loader,
ErrorMessage, ErrorMessage,
timeSlotQuestion,
}, },
}; };
</script> </script>
@ -1115,7 +1271,7 @@ export default {
&:focus + label, &:focus + label,
&:checked:focus + label { &:checked:focus + label {
box-shadow: none; box-shadow: none;
background-color: $white; background-color: $blue-100;
color: $black; color: $black;
} }
&:checked + label { &:checked + label {
@ -1209,4 +1365,12 @@ export default {
max-width: 414px; max-width: 414px;
text-align: left; text-align: left;
} }
.new-times {
min-height: 1rem;
padding: .2rem;
margin: 1rem 0;
background: lightgreen;
font-size: .6rem;
}
</style> </style>

View file

@ -1,6 +1,14 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<loadingModal ref="loadingModal" /> <loadingModal ref="loadingModal" />
<div style="font-size: .8rem; background: silver; padding: .2rem; text-align: left;" >
<div>componentId {{ componentId }}</div>
<div>meta {{ meta }}</div>
<div>errors {{ errors }}</div>
<div>errorMessage {{ errorMessage }}</div>
</div>
<div class="container-fluid page-container-grouped-styles"> <div class="container-fluid page-container-grouped-styles">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -23,6 +31,7 @@
selectableDatesSetting="custom" selectableDatesSetting="custom"
ref="datePicker" ref="datePicker"
v-model="selectedDate" v-model="selectedDate"
v-model:new="selectedTimeSlotInfo"
class="text-link-small" class="text-link-small"
:customSelectableDatesCallback="getAvailableDatesMethod" :customSelectableDatesCallback="getAvailableDatesMethod"
validationRules="date-required" validationRules="date-required"
@ -30,34 +39,41 @@
:pricingByDayUpcharge="pricingByDayUpcharge" :pricingByDayUpcharge="pricingByDayUpcharge"
:showPricingByDay="showPricingByDay" :showPricingByDay="showPricingByDay"
:isPricingByDayExperiment="isPricingByDayExperiment" :isPricingByDayExperiment="isPricingByDayExperiment"
@date-clicked="handleDateClicked" />
<timeSlotModalQuestion :selectedTimeSlotInfo="selectedTimeSlotInfo"
ref="timeSlotModalQuestion"
customComponentId="timeSlotModalQuestion"
v-model="selectedTimeSlotInfo"
cmsWidgetName="TimeSlotModalQuestion"
waitListLabelWidget="WaitListLabelWidget"
waitListQuestionWidget="WaitListQuestionWidget"
mobilePremiumCmsWidgetName="MobilePremiumTimeSlotModal"
mobileCmsWidgetName="MobileTimeSlotModal"
dropoffCmsWidgetName="DropOffTimeSlotModal"
sameDayDropOffCmsWidgetName="SameDayDropOffTimeSlotModal"
overnightDropOffCmsWidgetName="OvernightDropOffTimeSlotModal"
:selectedDate="selectedDate"
:appointmentType="appointmentType"
:premiumAppointmentFee="mobilePremiumAppointmentFee"
:displayWaitList="displayWaitList"
:timeSlotsForSelectedDate="timeSlotsForSelectedDate" :timeSlotsForSelectedDate="timeSlotsForSelectedDate"
:estimatedServiceMinutesMinimum="
selectableDatesData.estimatedServiceMinutesMinimum @TimeSlotSelected="updateTimeSlot"
"
:estimatedServiceMinutesMaximum=" @date-clicked="handleDateClicked" />
selectableDatesData.estimatedServiceMinutesMaximum
" <timeSlotModalQuestion
@waitListRequested="handleWaitListRequested" ref="timeSlotModalQuestion"
@time-slot-modal-closed="timeSlotModalClosed" customComponentId="timeSlotModalQuestion"
validationRules="time-slot-selection-required" v-model="selectedTimeSlotInfo"
@TimeSlotSelected="forwardButtonAction" /> cmsWidgetName="TimeSlotModalQuestion"
waitListLabelWidget="WaitListLabelWidget"
waitListQuestionWidget="WaitListQuestionWidget"
mobilePremiumCmsWidgetName="MobilePremiumTimeSlotModal"
mobileCmsWidgetName="MobileTimeSlotModal"
dropoffCmsWidgetName="DropOffTimeSlotModal"
sameDayDropOffCmsWidgetName="SameDayDropOffTimeSlotModal"
overnightDropOffCmsWidgetName="OvernightDropOffTimeSlotModal"
:selectedDate="selectedDate"
:appointmentType="appointmentType"
:premiumAppointmentFee="mobilePremiumAppointmentFee"
:displayWaitList="displayWaitList"
:timeSlotsForSelectedDate="timeSlotsForSelectedDate"
:estimatedServiceMinutesMinimum="
selectableDatesData.estimatedServiceMinutesMinimum
"
:estimatedServiceMinutesMaximum="
selectableDatesData.estimatedServiceMinutesMaximum
"
@waitListRequested="handleWaitListRequested"
@time-slot-modal-closed="timeSlotModalClosed"
validationRules="time-slot-selection-required"
@TimeSlotSelected="forwardButtonAction" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
@ -112,13 +128,24 @@ import { partNumberStrings } from "@/constants/part-number-strings";
import { deepClone } from "@/helpers/object-helper"; import { deepClone } from "@/helpers/object-helper";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule("date-required", required(errorMessages.DATE_REQUIRED)); // defineRule("date-required", required(errorMessages.DATE_REQUIRED));
defineRule("time-slot-selection-required", (value) => { defineRule("date-required", (value) => {
if (value?.timeSlot?.routeCode == null) { console.log("SCHEDULE VALIDATION of date-required, value is: ", value)
return errorMessages.DATE_REQUIRED; debugger; // eslint-disable-line no-debugger
}
// if (!value || value == null || value?.length < 1) {
// return errorMessages.DATE_REQUIRED;
// }
return true; return true;
}); });
// defineRule("time-slot-selection-required", (value) => {
// console.log("SCHEDULE VALIDATION of time-slot-selection-required, value is: ", value)
// debugger; // eslint-disable-line no-debugger
// if (value?.timeSlot?.routeCode == null) {
// return "TIME SLOT VALIDATION FAILURE! " + errorMessages.DATE_REQUIRED;
// }
// return true;
// });
// Define constants // Define constants
const TIME_SLOTS_CALL_DAYS_LIMIT = 34; // needs to be 34 for API limits (35 does not consistently work) const TIME_SLOTS_CALL_DAYS_LIMIT = 34; // needs to be 34 for API limits (35 does not consistently work)
@ -398,8 +425,15 @@ export default {
return this.$store.getters.order.serviceLocation.appointmentType; return this.$store.getters.order.serviceLocation.appointmentType;
}, },
timeSlotsForSelectedDate() { timeSlotsForSelectedDate() {
console.log("SCHEDULE, computing timeSlotsForSelectedDate... this.selectedDate: ", this.selectedDate)
if (!this.selectedDate) return null; if (!this.selectedDate) return null;
let tempOutput = this.selectableDatesData.days?.find(
(selectableDate) => selectableDate.date === this.selectedDate
);
console.log("SCHEDULE, computing timeSlotsForSelectedDate... returning: ", tempOutput)
debugger; // eslint-disable-line no-debugger
return this.selectableDatesData.days?.find( return this.selectableDatesData.days?.find(
(selectableDate) => selectableDate.date === this.selectedDate (selectableDate) => selectableDate.date === this.selectedDate
); );
@ -483,6 +517,9 @@ export default {
isPremiumAppointment: isPremiumAppointment, isPremiumAppointment: isPremiumAppointment,
}; };
console.log("SCHEDULE, computing getSelectedTimeSlotInfo()... returning: ", selectedTimeSlotInfo)
debugger; // eslint-disable-line no-debugger
return selectedTimeSlotInfo; return selectedTimeSlotInfo;
}, },
getSupportingItems() { getSupportingItems() {
@ -548,6 +585,9 @@ export default {
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
}, },
forwardButtonAction() { forwardButtonAction() {
console.log(" ")
console.log("SCHEDULE, forwardButtonAction... this.selectedTimeSlotInfo: ", this.selectedTimeSlotInfo)
debugger; // eslint-disable-line no-debugger
this.updateSupportingItems(); this.updateSupportingItems();
if (this.waitListRequested) { if (this.waitListRequested) {
@ -703,11 +743,23 @@ export default {
this.includePricingByDayUpcharge = false; this.includePricingByDayUpcharge = false;
} }
this.openInshopTimeSlotsModal(); // this.openInshopTimeSlotsModal(); // TURNON OR TURNOFF OLD MODAL OLDMODAL AJC
}, },
updateTimeSlot(timeSlot) {
console.log(" << NEW >> updateTimeSlot()... timeSlot: ", timeSlot)
debugger; // eslint-disable-line no-debugger
this.selectedTimeSlotInfo = timeSlot;
}
}, },
watch: { watch: {
selectedDate(newValue, oldValue) { selectedDate(newValue, oldValue) {
console.log("SCHEDULE WATCHED selectedDate was updated to: ", newValue)
debugger; // eslint-disable-line no-debugger
// Clear time slot selection if date selected changes // Clear time slot selection if date selected changes
if (newValue !== oldValue) { if (newValue !== oldValue) {
this.selectedTimeSlotInfo = { this.selectedTimeSlotInfo = {
@ -724,6 +776,10 @@ export default {
} }
}, },
selectedTimeSlotInfo(newValue) { selectedTimeSlotInfo(newValue) {
console.log("SCHEDULE WATCHED selectedTimeSlotInfo was updated to: ", newValue)
debugger; // eslint-disable-line no-debugger
this.updateFooterButtonText(newValue); this.updateFooterButtonText(newValue);
}, },
}, },
@ -765,4 +821,25 @@ export default {
margin-bottom: 0.25rem; margin-bottom: 0.25rem;
} }
} }
.modal-open {
overflow: auto !important;
padding-right: auto !important;
.modal {
position: relative;
display: block;
height: auto;
}
.modal-backdrop {
display: none !important;
}
}
</style> </style>