From 2730b0650ee7fd41ff7fcf86860bf96a7c4a5c27 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 14 Oct 2025 08:37:10 -0400 Subject: [PATCH 01/21] CASH-1426 CASH-1426 use a part number (DISCOUNT) that exists on mainframe IPF file so that work order submission does not fail in ESL. --- src/helpers/promotions-helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/promotions-helper.js b/src/helpers/promotions-helper.js index 2921fbfc8..e386660ac 100644 --- a/src/helpers/promotions-helper.js +++ b/src/helpers/promotions-helper.js @@ -6,7 +6,7 @@ import baseMixin from "@/mixins/base-mixin.js"; export const promoPartNumberStrings = { WIPER_DISCOUNT_PART_NUMBER: "WIPER DISCOUNT", - RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISC RAIN REPEL", + RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISCOUNT", GLASS_DISCOUNT_PART_NUMBER: "DISCOUNT", GLASS_CLEANER_DISCOUNT_PART_NUMBER: "DISC GLASS CLN", }; From b195d308234b3c223286013242a1754fb886e7ee Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Tue, 14 Oct 2025 13:08:57 -0400 Subject: [PATCH 02/21] CASH-1677 add emit to force selection change if only one --- .../schedule/time-slot-question/time-slot-question.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/layouts/schedule/time-slot-question/time-slot-question.vue b/src/layouts/schedule/time-slot-question/time-slot-question.vue index 18f3b77d2..1b8a2cb2e 100644 --- a/src/layouts/schedule/time-slot-question/time-slot-question.vue +++ b/src/layouts/schedule/time-slot-question/time-slot-question.vue @@ -509,8 +509,12 @@ export default { // this.availableTimeSlots only returns mobile/inshop slots so we know // the only available slot is not dropOFf this.selectedAnswerForTimeSlots = this.availableTimeSlots[0].value; + // emit up to parent that the time slot has been selected (when mobile or inshop) + this.timeSlotSelectionChanged(this.availableTimeSlots[0].value); } else { this.selectedAnswerForDropOffOrInshop = this.answersForDropOffQuestion[0].value; + // emit up to parent that the time slot has been selected (when only dropoff) + this.dropOffSelectionChanged(this.answersForDropOffQuestion[0].value); } } }, From 3b171fe57c31bd4979a7ac68431e5b45974edf8d Mon Sep 17 00:00:00 2001 From: CarlNation Date: Sun, 19 Oct 2025 10:31:00 -0400 Subject: [PATCH 03/21] CASH-1426 CASH-1426 use correct part number for rain repel discount. rain defen is the actual part number on the part file. --- src/helpers/promotions-helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/promotions-helper.js b/src/helpers/promotions-helper.js index e386660ac..b9e3327b6 100644 --- a/src/helpers/promotions-helper.js +++ b/src/helpers/promotions-helper.js @@ -6,7 +6,7 @@ import baseMixin from "@/mixins/base-mixin.js"; export const promoPartNumberStrings = { WIPER_DISCOUNT_PART_NUMBER: "WIPER DISCOUNT", - RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISCOUNT", + RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISC RAIN DEFEN", GLASS_DISCOUNT_PART_NUMBER: "DISCOUNT", GLASS_CLEANER_DISCOUNT_PART_NUMBER: "DISC GLASS CLN", }; From 9c4d2daa3ecc90cda38995353739ca1eac03dd39 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Wed, 31 Dec 2025 17:04:33 -0500 Subject: [PATCH 04/21] CASH-1315: move all today getters into helper --- src/digital-components/date-picker/date-picker.vue | 5 +++-- src/layouts/schedule/helpers/schedule-helper.js | 8 ++++++++ src/layouts/schedule/schedule.vue | 9 +++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index cbaba9193..b77e90e3e 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -150,6 +150,7 @@ import { import { convertDateToDateString, convertDateStringToDate, + getTodayDateString, } from "@/layouts/schedule/helpers/schedule-helper"; import { useField, ErrorMessage } from "vee-validate"; import { deepClone } from "@/helpers/object-helper"; @@ -227,7 +228,7 @@ export default { }, computed: { todayString() { - return this.todayOverrideDateString || convertDateToDateString(new Date()); + return this.todayOverrideDateString || getTodayDateString(); }, todayDayIndex() { return convertDateStringToDate(this.todayString).getDay(); @@ -414,7 +415,7 @@ export default { } else if (config.todayOverrideDateString) { todayDateString = config.todayOverrideDateString; } else { - todayDateString = convertDateToDateString(new Date()); + todayDateString = getTodayDateString(); } if (config.selectableDatesSetting === "past") calendarViewDirection = "past"; if (config.selectableDatesSetting === "custom") calendarViewDirection = "future"; diff --git a/src/layouts/schedule/helpers/schedule-helper.js b/src/layouts/schedule/helpers/schedule-helper.js index 41a1cd66a..85df8aa43 100644 --- a/src/layouts/schedule/helpers/schedule-helper.js +++ b/src/layouts/schedule/helpers/schedule-helper.js @@ -71,3 +71,11 @@ export function isDropOffRouteCode(routeCode) { routeCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF) ); } + +export function getTodayDate(routeCode) { + return new Date(); +} + +export function getTodayDateString(routeCode) { + return convertDateToDateString(getTodayDate()); +} diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index af7e67bd0..01b9841c0 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -233,6 +233,7 @@ import { convertDateStringToDate, sumDateString, isDropOffRouteCode, + getTodayDate, } from "@/layouts/schedule/helpers/schedule-helper"; import { DAYS_OF_WEEK } from "@/digital-components/date-picker/mixins/constants"; @@ -826,7 +827,7 @@ export default { } }, isSameDay() { - const todaysDate = new Date().toISOString().split("T")[0]; + const todaysDate = getTodayDate().toISOString().split("T")[0]; return this.selectedDate === todaysDate; }, isOvernightDropoff() { @@ -1100,7 +1101,7 @@ export default { }, getTimeSlotInfo() { // Get the current date - const currentDate = new Date(); + const currentDate = getTodayDate(); // Add 10 days to the current date currentDate.setDate(currentDate.getDate() + 10); @@ -1403,7 +1404,7 @@ export default { const type = store.getters.isMobileAppointment ? "mobile" : "inshop"; gaLabel = `${status}_${type}`; - const currentDate = new Date(); + const currentDate = getTodayDate(); const dateString = this.isMobileSelected ? this.selectableDatesMobile.days[0].date : this.selectableDatesInshop.days[0].date; @@ -1477,7 +1478,7 @@ export default { ) { const [year, month, day] = dateString.split("-").map(Number); const targetDate = new Date(year, month - 1, day); - const currentDate = new Date(); + const currentDate = getTodayDate(); const futureDate = new Date(currentDate); const experimentThresholdDays = experimentMixin.methods.hasSetting( experimentSettings.WAITLIST_THRESHOLD_DAYS From f2322450781b679a753dc5be8177de75ee04b568 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Wed, 31 Dec 2025 17:13:20 -0500 Subject: [PATCH 05/21] CASH-1315: ensure that date picker selects first available date once loaded --- .../date-picker/date-picker.vue | 17 +++++ src/layouts/schedule/schedule.vue | 72 +++++++------------ 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index b77e90e3e..3f9b1f668 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -200,6 +200,7 @@ export default { pricingByDayUpcharge: Number, isPricingByDayExperiment: Boolean, isMobileSelected: Boolean, + isLoadingDates: Boolean, }, setup(props) { const uuid = uuidv4(); @@ -260,6 +261,15 @@ export default { this.dispatchStoreAction(this.storeActions.SAVE_WAITLIST_REQUESTED, false, false); }, }, + firstAvailableSelectableDate() { + const mobileFirstDate = Array.isArray(this.selectableDatesMobile) + ? this.selectableDatesMobile[0]?.date + : null; + const inshopFirstDate = Array.isArray(this.selectableDatesInshop) + ? this.selectableDatesInshop[0]?.date + : null; + return this.isMobileSelected ? mobileFirstDate + "-mobile" : inshopFirstDate; + }, }, methods: { async initializeComponent(initialData) { @@ -835,6 +845,13 @@ export default { }, }, watch: { + isLoadingDates(newValue) { + // if done loading dates, then set to first available date + if (newValue === false && this.firstAvailableSelectableDate) { + this.selectedDate = this.firstAvailableSelectableDate; + } + }, + modelValue(newValue) { this.resetField({ value: newValue, diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 01b9841c0..178a15d7b 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -134,6 +134,7 @@ selectableDatesSetting="custom" ref="datePicker" v-model="selectedDate" + :isLoadingDates="isLoadingDates" :isMobileSelected="isMobileSelected" class="text-link-small" :getMoreDatesCallback="getMoreScheduleData" @@ -332,12 +333,16 @@ const getScheduleApiResponse = async ({ const mobileTimeSlotsData = { days: [], }; - function compareDayStrings(a, b) { if (a.date < b.date) return -1; if (a.date > b.date) return 1; return 0; } + function removePastDates(array, todaysDate) { + return array.filter(function (a) { + return !(a.date < todaysDate); + }); + } const makeParallelCalls = async () => { await Promise.all( @@ -390,6 +395,10 @@ const getScheduleApiResponse = async ({ inshopTimeSlotsData.days.sort(compareDayStrings); mobileTimeSlotsData.days.sort(compareDayStrings); + const todaysDate = getTodayDate().toISOString().split("T")[0]; + inshopTimeSlotsData.days = removePastDates(inshopTimeSlotsData.days, todaysDate); + mobileTimeSlotsData.days = removePastDates(mobileTimeSlotsData.days, todaysDate); + return { inshopTimeSlotsData: inshopTimeSlotsData, mobileTimeSlotsData: mobileTimeSlotsData, @@ -423,7 +432,7 @@ export default { selectableDatesInshop: [], selectableDatesMobile: [], preSelectedDate: null, - + isLoadingDates: true, streetAddress: this.getServiceAddressFromStore(), apartmentNumberOrBusinessName: this.getServiceAddress2FromStore(), carId: this.getCarIdfromStore(), @@ -613,7 +622,7 @@ export default { this.selectedDate.includes("mobile") && !this.isMobileSelected ) { - this.getNewSelectedDate(); + this.setSelectedDateToFirstAvailable(); } return this.selectedDate && this.appointmentTypeFromAppointmentTypeQuestion; }, @@ -1180,45 +1189,24 @@ export default { datePickerInitialData.pricingByDayUpcharge = this.pricingByDayUpcharge; await this.$refs.datePicker.initializeComponent(datePickerInitialData); this.selectableDatesInshop = - datePickerInitialData.initialShopTimeSlotsResponse.inshopTimeSlotsData; + await datePickerInitialData.initialShopTimeSlotsResponse.inshopTimeSlotsData; this.selectableDatesMobile = - datePickerInitialData.initialShopTimeSlotsResponse.mobileTimeSlotsData; + await datePickerInitialData.initialShopTimeSlotsResponse.mobileTimeSlotsData; this.setDisplayWaitList(); - if (this.preSelectedDate) this.selectedDate = this.preSelectedDate; - - if (!this.preSelectedDate) { - // if no date is preselected on load, then select the first available - let selectedDateMobile = this.getSelectedDateForMobile(); - let selectedDateInshop = this.getSelectedDateForInshop(); - - // if there is still no selected date, then load more and try again + if (this.preSelectedDate) { + this.selectedDate = this.preSelectedDate; + } else { + // if no date is preselected on load, make sure there are some dates available if ( - (this.isServiceableMobile && !selectedDateMobile) || - (this.isServiceableInshop && !selectedDateInshop) || - (this.isServiceableDropoff && !selectedDateInshop) + this.selectableDatesInshop.days.length < 1 || + this.selectableDatesMobile.days.length < 1 ) { await this.$nextTick(); await this.$refs.datePicker.showAnotherMonth(); - - // update all dates - - // > CHLOE HERD 7/22 -- CASH-1207 - // > Do not update the available dates again here; - // > they have already been updated by `showAnotherMonth`. - // > Doing so will likely add or remove dates, - // > desyncing the schedule page and the date-picker. - + this.isLoadingDates = false; this.setDisplayWaitList(); } - - await this.$nextTick(); - - if (this.isMobileSelected) { - this.selectedDate = this.getSelectedDateForMobile(); - } else { - this.selectedDate = this.getSelectedDateForInshop(); - } } }, getScheduleApiResponse, @@ -1623,7 +1611,7 @@ export default { ? AppointmentTypeStrings.DROP_OFF : AppointmentTypeStrings.IN_SHOP; }, - getSelectedDate() { + getFirstAvailableDate() { let dateToSelect; if (this.isMobileSelected) { dateToSelect = returnFirstDate(this.selectableDatesMobile); @@ -1633,16 +1621,6 @@ export default { if (!dateToSelect) return null; return this.isMobileSelected ? dateToSelect + "-mobile" : dateToSelect; }, - getSelectedDateForMobile() { - let dateToSelect = returnFirstDate(this.selectableDatesMobile); - if (!dateToSelect) return null; - return dateToSelect + "-mobile"; - }, - getSelectedDateForInshop() { - let dateToSelect = returnFirstDate(this.selectableDatesInshop); - if (!dateToSelect) return null; - return dateToSelect; - }, resetSelectedProvider() { this.selectedProvider = new Provider(); this.updateSelectedProvider(); @@ -1741,11 +1719,11 @@ export default { } else { this.appointmentType = null; } - this.selectedDate = this.getSelectedDate(); + this.setSelectedDateToFirstAvailable(); this.setDisplayWaitList(); }, - getNewSelectedDate() { - this.selectedDate = this.getSelectedDate(); + setSelectedDateToFirstAvailable() { + this.selectedDate = this.getFirstAvailableDate(); }, }, watch: { From cfc36ca247c4d4c2e88c48941c4e76f304e32665 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Wed, 31 Dec 2025 18:31:32 -0500 Subject: [PATCH 06/21] CASH-1315: remove redundent isLoading check --- src/digital-components/date-picker/date-picker.vue | 4 +--- src/layouts/schedule/schedule.vue | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index 3f9b1f668..a531244a5 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -200,7 +200,6 @@ export default { pricingByDayUpcharge: Number, isPricingByDayExperiment: Boolean, isMobileSelected: Boolean, - isLoadingDates: Boolean, }, setup(props) { const uuid = uuidv4(); @@ -845,13 +844,12 @@ export default { }, }, watch: { - isLoadingDates(newValue) { + isLoading(newValue) { // if done loading dates, then set to first available date if (newValue === false && this.firstAvailableSelectableDate) { this.selectedDate = this.firstAvailableSelectableDate; } }, - modelValue(newValue) { this.resetField({ value: newValue, diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 178a15d7b..7c9d9f444 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -134,7 +134,6 @@ selectableDatesSetting="custom" ref="datePicker" v-model="selectedDate" - :isLoadingDates="isLoadingDates" :isMobileSelected="isMobileSelected" class="text-link-small" :getMoreDatesCallback="getMoreScheduleData" @@ -432,7 +431,6 @@ export default { selectableDatesInshop: [], selectableDatesMobile: [], preSelectedDate: null, - isLoadingDates: true, streetAddress: this.getServiceAddressFromStore(), apartmentNumberOrBusinessName: this.getServiceAddress2FromStore(), carId: this.getCarIdfromStore(), @@ -1204,7 +1202,6 @@ export default { ) { await this.$nextTick(); await this.$refs.datePicker.showAnotherMonth(); - this.isLoadingDates = false; this.setDisplayWaitList(); } } From 4b65a9ddb3119b9785c95a03727cf6964693a0c3 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 14 Oct 2025 08:37:10 -0400 Subject: [PATCH 07/21] CASH-1426 CASH-1426 use a part number (DISCOUNT) that exists on mainframe IPF file so that work order submission does not fail in ESL. --- src/helpers/promotions-helper.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/helpers/promotions-helper.js b/src/helpers/promotions-helper.js index b9e3327b6..57e3dc7e7 100644 --- a/src/helpers/promotions-helper.js +++ b/src/helpers/promotions-helper.js @@ -6,7 +6,11 @@ import baseMixin from "@/mixins/base-mixin.js"; export const promoPartNumberStrings = { WIPER_DISCOUNT_PART_NUMBER: "WIPER DISCOUNT", +<<<<<<< HEAD RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISC RAIN DEFEN", +======= + RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISCOUNT", +>>>>>>> 2730b0650 (CASH-1426) GLASS_DISCOUNT_PART_NUMBER: "DISCOUNT", GLASS_CLEANER_DISCOUNT_PART_NUMBER: "DISC GLASS CLN", }; From 63b3ef642f8b4ef0ce89317f619d26eae9cbe2a2 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Sun, 19 Oct 2025 10:31:00 -0400 Subject: [PATCH 08/21] CASH-1426 CASH-1426 use correct part number for rain repel discount. rain defen is the actual part number on the part file. --- src/helpers/promotions-helper.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/helpers/promotions-helper.js b/src/helpers/promotions-helper.js index 57e3dc7e7..af93af3c9 100644 --- a/src/helpers/promotions-helper.js +++ b/src/helpers/promotions-helper.js @@ -6,11 +6,15 @@ import baseMixin from "@/mixins/base-mixin.js"; export const promoPartNumberStrings = { WIPER_DISCOUNT_PART_NUMBER: "WIPER DISCOUNT", +<<<<<<< HEAD <<<<<<< HEAD RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISC RAIN DEFEN", ======= RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISCOUNT", >>>>>>> 2730b0650 (CASH-1426) +======= + RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISC RAIN DEFEN", +>>>>>>> 3b171fe57 (CASH-1426) GLASS_DISCOUNT_PART_NUMBER: "DISCOUNT", GLASS_CLEANER_DISCOUNT_PART_NUMBER: "DISC GLASS CLN", }; From 222f27ee75350156a417af44cbc788e994fa74e1 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Mon, 20 Oct 2025 08:25:16 -0400 Subject: [PATCH 09/21] CASH-1315 - fix accidental merge crud --- src/helpers/promotions-helper.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/helpers/promotions-helper.js b/src/helpers/promotions-helper.js index af93af3c9..b9e3327b6 100644 --- a/src/helpers/promotions-helper.js +++ b/src/helpers/promotions-helper.js @@ -6,15 +6,7 @@ import baseMixin from "@/mixins/base-mixin.js"; export const promoPartNumberStrings = { WIPER_DISCOUNT_PART_NUMBER: "WIPER DISCOUNT", -<<<<<<< HEAD -<<<<<<< HEAD RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISC RAIN DEFEN", -======= - RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISCOUNT", ->>>>>>> 2730b0650 (CASH-1426) -======= - RAIN_REPEL_DISCOUNT_PART_NUMBER: "DISC RAIN DEFEN", ->>>>>>> 3b171fe57 (CASH-1426) GLASS_DISCOUNT_PART_NUMBER: "DISCOUNT", GLASS_CLEANER_DISCOUNT_PART_NUMBER: "DISC GLASS CLN", }; From 504a774863e0c7f6411d11b8aa21b448ce4e6a10 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Mon, 20 Oct 2025 08:48:44 -0400 Subject: [PATCH 10/21] CASH-1315 refactor to avoid null being coerced into a string --- src/digital-components/date-picker/date-picker.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index a531244a5..63449320c 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -267,7 +267,7 @@ export default { const inshopFirstDate = Array.isArray(this.selectableDatesInshop) ? this.selectableDatesInshop[0]?.date : null; - return this.isMobileSelected ? mobileFirstDate + "-mobile" : inshopFirstDate; + return (this.isMobileSelected && mobileFirstDate) ? mobileFirstDate + "-mobile" : inshopFirstDate; }, }, methods: { From efee6aa70aff4c9170acacf1c3dc625f8ef8ffc8 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Wed, 31 Dec 2025 09:37:39 -0500 Subject: [PATCH 11/21] CASH-1315: refactoring from PR review - remove watch --- .../date-picker/date-picker.vue | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index 63449320c..32fe7f5f3 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -267,7 +267,9 @@ export default { const inshopFirstDate = Array.isArray(this.selectableDatesInshop) ? this.selectableDatesInshop[0]?.date : null; - return (this.isMobileSelected && mobileFirstDate) ? mobileFirstDate + "-mobile" : inshopFirstDate; + return this.isMobileSelected && mobileFirstDate + ? mobileFirstDate + "-mobile" + : inshopFirstDate; }, }, methods: { @@ -540,6 +542,8 @@ export default { } this.months = months; this.isLoading = false; + // if done loading dates, then set to first available date + if (!this.selectedDate) this.selectedDate = this.firstAvailableSelectableDate; if (config.preSelectedDate) { this.$nextTick(() => { @@ -773,6 +777,9 @@ export default { ); this.isLoading = false; + // if done loading dates, then set to first available date + if (!this.selectedDate) this.selectedDate = this.firstAvailableSelectableDate; + this.hideSomeDaysForInitialView = false; // if hid days on initial partial view, this will reveal those days monthToShow.monthClass = monthToShow.monthClass.replace(" month-hidden", ""); this.scrollToElement(monthToShow.monthString); @@ -844,12 +851,6 @@ export default { }, }, watch: { - isLoading(newValue) { - // if done loading dates, then set to first available date - if (newValue === false && this.firstAvailableSelectableDate) { - this.selectedDate = this.firstAvailableSelectableDate; - } - }, modelValue(newValue) { this.resetField({ value: newValue, From dfc70d19bc22cf22260d42bb5daa0393de779173 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Tue, 30 Dec 2025 10:54:01 -0500 Subject: [PATCH 12/21] CASH-1315 undo removal of watch --- src/digital-components/date-picker/date-picker.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index 32fe7f5f3..65ada843e 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -267,9 +267,7 @@ export default { const inshopFirstDate = Array.isArray(this.selectableDatesInshop) ? this.selectableDatesInshop[0]?.date : null; - return this.isMobileSelected && mobileFirstDate - ? mobileFirstDate + "-mobile" - : inshopFirstDate; + return (this.isMobileSelected && mobileFirstDate) ? mobileFirstDate + "-mobile" : inshopFirstDate; }, }, methods: { From 5bf73e43bb909785cf53a76a459a3d9a45d95353 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Tue, 30 Dec 2025 10:59:14 -0500 Subject: [PATCH 13/21] CASH-1315 prettier updates: --- src/digital-components/date-picker/date-picker.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index 65ada843e..32fe7f5f3 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -267,7 +267,9 @@ export default { const inshopFirstDate = Array.isArray(this.selectableDatesInshop) ? this.selectableDatesInshop[0]?.date : null; - return (this.isMobileSelected && mobileFirstDate) ? mobileFirstDate + "-mobile" : inshopFirstDate; + return this.isMobileSelected && mobileFirstDate + ? mobileFirstDate + "-mobile" + : inshopFirstDate; }, }, methods: { From e8ab9d5625cc0ea023e69b10e62e700a39e6b4b0 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Tue, 30 Dec 2025 11:16:32 -0500 Subject: [PATCH 14/21] Revert "CASH-1315: refactoring from PR review - remove watch" This reverts commit efee6aa70aff4c9170acacf1c3dc625f8ef8ffc8. --- .../date-picker/date-picker.vue | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index 32fe7f5f3..63449320c 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -267,9 +267,7 @@ export default { const inshopFirstDate = Array.isArray(this.selectableDatesInshop) ? this.selectableDatesInshop[0]?.date : null; - return this.isMobileSelected && mobileFirstDate - ? mobileFirstDate + "-mobile" - : inshopFirstDate; + return (this.isMobileSelected && mobileFirstDate) ? mobileFirstDate + "-mobile" : inshopFirstDate; }, }, methods: { @@ -542,8 +540,6 @@ export default { } this.months = months; this.isLoading = false; - // if done loading dates, then set to first available date - if (!this.selectedDate) this.selectedDate = this.firstAvailableSelectableDate; if (config.preSelectedDate) { this.$nextTick(() => { @@ -777,9 +773,6 @@ export default { ); this.isLoading = false; - // if done loading dates, then set to first available date - if (!this.selectedDate) this.selectedDate = this.firstAvailableSelectableDate; - this.hideSomeDaysForInitialView = false; // if hid days on initial partial view, this will reveal those days monthToShow.monthClass = monthToShow.monthClass.replace(" month-hidden", ""); this.scrollToElement(monthToShow.monthString); @@ -851,6 +844,12 @@ export default { }, }, watch: { + isLoading(newValue) { + // if done loading dates, then set to first available date + if (newValue === false && this.firstAvailableSelectableDate) { + this.selectedDate = this.firstAvailableSelectableDate; + } + }, modelValue(newValue) { this.resetField({ value: newValue, From 21c247f91606c4ae1baba7b341d153210d50606b Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Tue, 30 Dec 2025 11:25:57 -0500 Subject: [PATCH 15/21] Revert "Merge pull request #2897 from Safelite/feature/CASH-1315-v4" This reverts commit 78273792b04a1a26a73c48cb7a72c179a56f3fa1, reversing changes made to b2478f4e9ea187fd568f3c12c202ff5262405e45. --- .../date-picker/date-picker.vue | 5 +- .../schedule/helpers/schedule-helper.js | 8 -- src/layouts/schedule/schedule.vue | 78 ++++++++++++------- 3 files changed, 53 insertions(+), 38 deletions(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index 63449320c..737a9e715 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -150,7 +150,6 @@ import { import { convertDateToDateString, convertDateStringToDate, - getTodayDateString, } from "@/layouts/schedule/helpers/schedule-helper"; import { useField, ErrorMessage } from "vee-validate"; import { deepClone } from "@/helpers/object-helper"; @@ -228,7 +227,7 @@ export default { }, computed: { todayString() { - return this.todayOverrideDateString || getTodayDateString(); + return this.todayOverrideDateString || convertDateToDateString(new Date()); }, todayDayIndex() { return convertDateStringToDate(this.todayString).getDay(); @@ -424,7 +423,7 @@ export default { } else if (config.todayOverrideDateString) { todayDateString = config.todayOverrideDateString; } else { - todayDateString = getTodayDateString(); + todayDateString = convertDateToDateString(new Date()); } if (config.selectableDatesSetting === "past") calendarViewDirection = "past"; if (config.selectableDatesSetting === "custom") calendarViewDirection = "future"; diff --git a/src/layouts/schedule/helpers/schedule-helper.js b/src/layouts/schedule/helpers/schedule-helper.js index 85df8aa43..41a1cd66a 100644 --- a/src/layouts/schedule/helpers/schedule-helper.js +++ b/src/layouts/schedule/helpers/schedule-helper.js @@ -71,11 +71,3 @@ export function isDropOffRouteCode(routeCode) { routeCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF) ); } - -export function getTodayDate(routeCode) { - return new Date(); -} - -export function getTodayDateString(routeCode) { - return convertDateToDateString(getTodayDate()); -} diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 7c9d9f444..af7e67bd0 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -233,7 +233,6 @@ import { convertDateStringToDate, sumDateString, isDropOffRouteCode, - getTodayDate, } from "@/layouts/schedule/helpers/schedule-helper"; import { DAYS_OF_WEEK } from "@/digital-components/date-picker/mixins/constants"; @@ -332,16 +331,12 @@ const getScheduleApiResponse = async ({ const mobileTimeSlotsData = { days: [], }; + function compareDayStrings(a, b) { if (a.date < b.date) return -1; if (a.date > b.date) return 1; return 0; } - function removePastDates(array, todaysDate) { - return array.filter(function (a) { - return !(a.date < todaysDate); - }); - } const makeParallelCalls = async () => { await Promise.all( @@ -394,10 +389,6 @@ const getScheduleApiResponse = async ({ inshopTimeSlotsData.days.sort(compareDayStrings); mobileTimeSlotsData.days.sort(compareDayStrings); - const todaysDate = getTodayDate().toISOString().split("T")[0]; - inshopTimeSlotsData.days = removePastDates(inshopTimeSlotsData.days, todaysDate); - mobileTimeSlotsData.days = removePastDates(mobileTimeSlotsData.days, todaysDate); - return { inshopTimeSlotsData: inshopTimeSlotsData, mobileTimeSlotsData: mobileTimeSlotsData, @@ -431,6 +422,7 @@ export default { selectableDatesInshop: [], selectableDatesMobile: [], preSelectedDate: null, + streetAddress: this.getServiceAddressFromStore(), apartmentNumberOrBusinessName: this.getServiceAddress2FromStore(), carId: this.getCarIdfromStore(), @@ -620,7 +612,7 @@ export default { this.selectedDate.includes("mobile") && !this.isMobileSelected ) { - this.setSelectedDateToFirstAvailable(); + this.getNewSelectedDate(); } return this.selectedDate && this.appointmentTypeFromAppointmentTypeQuestion; }, @@ -834,7 +826,7 @@ export default { } }, isSameDay() { - const todaysDate = getTodayDate().toISOString().split("T")[0]; + const todaysDate = new Date().toISOString().split("T")[0]; return this.selectedDate === todaysDate; }, isOvernightDropoff() { @@ -1108,7 +1100,7 @@ export default { }, getTimeSlotInfo() { // Get the current date - const currentDate = getTodayDate(); + const currentDate = new Date(); // Add 10 days to the current date currentDate.setDate(currentDate.getDate() + 10); @@ -1187,23 +1179,45 @@ export default { datePickerInitialData.pricingByDayUpcharge = this.pricingByDayUpcharge; await this.$refs.datePicker.initializeComponent(datePickerInitialData); this.selectableDatesInshop = - await datePickerInitialData.initialShopTimeSlotsResponse.inshopTimeSlotsData; + datePickerInitialData.initialShopTimeSlotsResponse.inshopTimeSlotsData; this.selectableDatesMobile = - await datePickerInitialData.initialShopTimeSlotsResponse.mobileTimeSlotsData; + datePickerInitialData.initialShopTimeSlotsResponse.mobileTimeSlotsData; this.setDisplayWaitList(); - if (this.preSelectedDate) { - this.selectedDate = this.preSelectedDate; - } else { - // if no date is preselected on load, make sure there are some dates available + if (this.preSelectedDate) this.selectedDate = this.preSelectedDate; + + if (!this.preSelectedDate) { + // if no date is preselected on load, then select the first available + let selectedDateMobile = this.getSelectedDateForMobile(); + let selectedDateInshop = this.getSelectedDateForInshop(); + + // if there is still no selected date, then load more and try again if ( - this.selectableDatesInshop.days.length < 1 || - this.selectableDatesMobile.days.length < 1 + (this.isServiceableMobile && !selectedDateMobile) || + (this.isServiceableInshop && !selectedDateInshop) || + (this.isServiceableDropoff && !selectedDateInshop) ) { await this.$nextTick(); await this.$refs.datePicker.showAnotherMonth(); + + // update all dates + + // > CHLOE HERD 7/22 -- CASH-1207 + // > Do not update the available dates again here; + // > they have already been updated by `showAnotherMonth`. + // > Doing so will likely add or remove dates, + // > desyncing the schedule page and the date-picker. + this.setDisplayWaitList(); } + + await this.$nextTick(); + + if (this.isMobileSelected) { + this.selectedDate = this.getSelectedDateForMobile(); + } else { + this.selectedDate = this.getSelectedDateForInshop(); + } } }, getScheduleApiResponse, @@ -1389,7 +1403,7 @@ export default { const type = store.getters.isMobileAppointment ? "mobile" : "inshop"; gaLabel = `${status}_${type}`; - const currentDate = getTodayDate(); + const currentDate = new Date(); const dateString = this.isMobileSelected ? this.selectableDatesMobile.days[0].date : this.selectableDatesInshop.days[0].date; @@ -1463,7 +1477,7 @@ export default { ) { const [year, month, day] = dateString.split("-").map(Number); const targetDate = new Date(year, month - 1, day); - const currentDate = getTodayDate(); + const currentDate = new Date(); const futureDate = new Date(currentDate); const experimentThresholdDays = experimentMixin.methods.hasSetting( experimentSettings.WAITLIST_THRESHOLD_DAYS @@ -1608,7 +1622,7 @@ export default { ? AppointmentTypeStrings.DROP_OFF : AppointmentTypeStrings.IN_SHOP; }, - getFirstAvailableDate() { + getSelectedDate() { let dateToSelect; if (this.isMobileSelected) { dateToSelect = returnFirstDate(this.selectableDatesMobile); @@ -1618,6 +1632,16 @@ export default { if (!dateToSelect) return null; return this.isMobileSelected ? dateToSelect + "-mobile" : dateToSelect; }, + getSelectedDateForMobile() { + let dateToSelect = returnFirstDate(this.selectableDatesMobile); + if (!dateToSelect) return null; + return dateToSelect + "-mobile"; + }, + getSelectedDateForInshop() { + let dateToSelect = returnFirstDate(this.selectableDatesInshop); + if (!dateToSelect) return null; + return dateToSelect; + }, resetSelectedProvider() { this.selectedProvider = new Provider(); this.updateSelectedProvider(); @@ -1716,11 +1740,11 @@ export default { } else { this.appointmentType = null; } - this.setSelectedDateToFirstAvailable(); + this.selectedDate = this.getSelectedDate(); this.setDisplayWaitList(); }, - setSelectedDateToFirstAvailable() { - this.selectedDate = this.getFirstAvailableDate(); + getNewSelectedDate() { + this.selectedDate = this.getSelectedDate(); }, }, watch: { From fa0f09b46db3b7beb503228e5cd71e2e667517eb Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Tue, 30 Dec 2025 11:29:14 -0500 Subject: [PATCH 16/21] CASH-1315 prettier revert --- src/digital-components/date-picker/date-picker.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index 737a9e715..6f635d0bc 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -266,7 +266,9 @@ export default { const inshopFirstDate = Array.isArray(this.selectableDatesInshop) ? this.selectableDatesInshop[0]?.date : null; - return (this.isMobileSelected && mobileFirstDate) ? mobileFirstDate + "-mobile" : inshopFirstDate; + return this.isMobileSelected && mobileFirstDate + ? mobileFirstDate + "-mobile" + : inshopFirstDate; }, }, methods: { From ad1990d8b4fc68d85f57b7f00e6fcb28eb239c14 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Wed, 31 Dec 2025 17:04:33 -0500 Subject: [PATCH 17/21] CASH-1315: move all today getters into helper --- src/digital-components/date-picker/date-picker.vue | 5 +++-- src/layouts/schedule/helpers/schedule-helper.js | 8 ++++++++ src/layouts/schedule/schedule.vue | 9 +++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index 6f635d0bc..d586ff839 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -150,6 +150,7 @@ import { import { convertDateToDateString, convertDateStringToDate, + getTodayDateString, } from "@/layouts/schedule/helpers/schedule-helper"; import { useField, ErrorMessage } from "vee-validate"; import { deepClone } from "@/helpers/object-helper"; @@ -227,7 +228,7 @@ export default { }, computed: { todayString() { - return this.todayOverrideDateString || convertDateToDateString(new Date()); + return this.todayOverrideDateString || getTodayDateString(); }, todayDayIndex() { return convertDateStringToDate(this.todayString).getDay(); @@ -425,7 +426,7 @@ export default { } else if (config.todayOverrideDateString) { todayDateString = config.todayOverrideDateString; } else { - todayDateString = convertDateToDateString(new Date()); + todayDateString = getTodayDateString(); } if (config.selectableDatesSetting === "past") calendarViewDirection = "past"; if (config.selectableDatesSetting === "custom") calendarViewDirection = "future"; diff --git a/src/layouts/schedule/helpers/schedule-helper.js b/src/layouts/schedule/helpers/schedule-helper.js index 41a1cd66a..85df8aa43 100644 --- a/src/layouts/schedule/helpers/schedule-helper.js +++ b/src/layouts/schedule/helpers/schedule-helper.js @@ -71,3 +71,11 @@ export function isDropOffRouteCode(routeCode) { routeCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF) ); } + +export function getTodayDate(routeCode) { + return new Date(); +} + +export function getTodayDateString(routeCode) { + return convertDateToDateString(getTodayDate()); +} diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index af7e67bd0..01b9841c0 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -233,6 +233,7 @@ import { convertDateStringToDate, sumDateString, isDropOffRouteCode, + getTodayDate, } from "@/layouts/schedule/helpers/schedule-helper"; import { DAYS_OF_WEEK } from "@/digital-components/date-picker/mixins/constants"; @@ -826,7 +827,7 @@ export default { } }, isSameDay() { - const todaysDate = new Date().toISOString().split("T")[0]; + const todaysDate = getTodayDate().toISOString().split("T")[0]; return this.selectedDate === todaysDate; }, isOvernightDropoff() { @@ -1100,7 +1101,7 @@ export default { }, getTimeSlotInfo() { // Get the current date - const currentDate = new Date(); + const currentDate = getTodayDate(); // Add 10 days to the current date currentDate.setDate(currentDate.getDate() + 10); @@ -1403,7 +1404,7 @@ export default { const type = store.getters.isMobileAppointment ? "mobile" : "inshop"; gaLabel = `${status}_${type}`; - const currentDate = new Date(); + const currentDate = getTodayDate(); const dateString = this.isMobileSelected ? this.selectableDatesMobile.days[0].date : this.selectableDatesInshop.days[0].date; @@ -1477,7 +1478,7 @@ export default { ) { const [year, month, day] = dateString.split("-").map(Number); const targetDate = new Date(year, month - 1, day); - const currentDate = new Date(); + const currentDate = getTodayDate(); const futureDate = new Date(currentDate); const experimentThresholdDays = experimentMixin.methods.hasSetting( experimentSettings.WAITLIST_THRESHOLD_DAYS From 3b3f8cd800eb3e8468e84e8fe027c24f5dfd5ef6 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Wed, 31 Dec 2025 17:13:20 -0500 Subject: [PATCH 18/21] CASH-1315: ensure that date picker selects first available date once loaded (cherry picked from commit f2322450781b679a753dc5be8177de75ee04b568) --- .../date-picker/date-picker.vue | 3 +- src/layouts/schedule/schedule.vue | 72 +++++++------------ 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index d586ff839..e12c835e9 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -200,6 +200,7 @@ export default { pricingByDayUpcharge: Number, isPricingByDayExperiment: Boolean, isMobileSelected: Boolean, + isLoadingDates: Boolean, }, setup(props) { const uuid = uuidv4(); @@ -846,7 +847,7 @@ export default { }, }, watch: { - isLoading(newValue) { + isLoadingDates(newValue) { // if done loading dates, then set to first available date if (newValue === false && this.firstAvailableSelectableDate) { this.selectedDate = this.firstAvailableSelectableDate; diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 01b9841c0..178a15d7b 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -134,6 +134,7 @@ selectableDatesSetting="custom" ref="datePicker" v-model="selectedDate" + :isLoadingDates="isLoadingDates" :isMobileSelected="isMobileSelected" class="text-link-small" :getMoreDatesCallback="getMoreScheduleData" @@ -332,12 +333,16 @@ const getScheduleApiResponse = async ({ const mobileTimeSlotsData = { days: [], }; - function compareDayStrings(a, b) { if (a.date < b.date) return -1; if (a.date > b.date) return 1; return 0; } + function removePastDates(array, todaysDate) { + return array.filter(function (a) { + return !(a.date < todaysDate); + }); + } const makeParallelCalls = async () => { await Promise.all( @@ -390,6 +395,10 @@ const getScheduleApiResponse = async ({ inshopTimeSlotsData.days.sort(compareDayStrings); mobileTimeSlotsData.days.sort(compareDayStrings); + const todaysDate = getTodayDate().toISOString().split("T")[0]; + inshopTimeSlotsData.days = removePastDates(inshopTimeSlotsData.days, todaysDate); + mobileTimeSlotsData.days = removePastDates(mobileTimeSlotsData.days, todaysDate); + return { inshopTimeSlotsData: inshopTimeSlotsData, mobileTimeSlotsData: mobileTimeSlotsData, @@ -423,7 +432,7 @@ export default { selectableDatesInshop: [], selectableDatesMobile: [], preSelectedDate: null, - + isLoadingDates: true, streetAddress: this.getServiceAddressFromStore(), apartmentNumberOrBusinessName: this.getServiceAddress2FromStore(), carId: this.getCarIdfromStore(), @@ -613,7 +622,7 @@ export default { this.selectedDate.includes("mobile") && !this.isMobileSelected ) { - this.getNewSelectedDate(); + this.setSelectedDateToFirstAvailable(); } return this.selectedDate && this.appointmentTypeFromAppointmentTypeQuestion; }, @@ -1180,45 +1189,24 @@ export default { datePickerInitialData.pricingByDayUpcharge = this.pricingByDayUpcharge; await this.$refs.datePicker.initializeComponent(datePickerInitialData); this.selectableDatesInshop = - datePickerInitialData.initialShopTimeSlotsResponse.inshopTimeSlotsData; + await datePickerInitialData.initialShopTimeSlotsResponse.inshopTimeSlotsData; this.selectableDatesMobile = - datePickerInitialData.initialShopTimeSlotsResponse.mobileTimeSlotsData; + await datePickerInitialData.initialShopTimeSlotsResponse.mobileTimeSlotsData; this.setDisplayWaitList(); - if (this.preSelectedDate) this.selectedDate = this.preSelectedDate; - - if (!this.preSelectedDate) { - // if no date is preselected on load, then select the first available - let selectedDateMobile = this.getSelectedDateForMobile(); - let selectedDateInshop = this.getSelectedDateForInshop(); - - // if there is still no selected date, then load more and try again + if (this.preSelectedDate) { + this.selectedDate = this.preSelectedDate; + } else { + // if no date is preselected on load, make sure there are some dates available if ( - (this.isServiceableMobile && !selectedDateMobile) || - (this.isServiceableInshop && !selectedDateInshop) || - (this.isServiceableDropoff && !selectedDateInshop) + this.selectableDatesInshop.days.length < 1 || + this.selectableDatesMobile.days.length < 1 ) { await this.$nextTick(); await this.$refs.datePicker.showAnotherMonth(); - - // update all dates - - // > CHLOE HERD 7/22 -- CASH-1207 - // > Do not update the available dates again here; - // > they have already been updated by `showAnotherMonth`. - // > Doing so will likely add or remove dates, - // > desyncing the schedule page and the date-picker. - + this.isLoadingDates = false; this.setDisplayWaitList(); } - - await this.$nextTick(); - - if (this.isMobileSelected) { - this.selectedDate = this.getSelectedDateForMobile(); - } else { - this.selectedDate = this.getSelectedDateForInshop(); - } } }, getScheduleApiResponse, @@ -1623,7 +1611,7 @@ export default { ? AppointmentTypeStrings.DROP_OFF : AppointmentTypeStrings.IN_SHOP; }, - getSelectedDate() { + getFirstAvailableDate() { let dateToSelect; if (this.isMobileSelected) { dateToSelect = returnFirstDate(this.selectableDatesMobile); @@ -1633,16 +1621,6 @@ export default { if (!dateToSelect) return null; return this.isMobileSelected ? dateToSelect + "-mobile" : dateToSelect; }, - getSelectedDateForMobile() { - let dateToSelect = returnFirstDate(this.selectableDatesMobile); - if (!dateToSelect) return null; - return dateToSelect + "-mobile"; - }, - getSelectedDateForInshop() { - let dateToSelect = returnFirstDate(this.selectableDatesInshop); - if (!dateToSelect) return null; - return dateToSelect; - }, resetSelectedProvider() { this.selectedProvider = new Provider(); this.updateSelectedProvider(); @@ -1741,11 +1719,11 @@ export default { } else { this.appointmentType = null; } - this.selectedDate = this.getSelectedDate(); + this.setSelectedDateToFirstAvailable(); this.setDisplayWaitList(); }, - getNewSelectedDate() { - this.selectedDate = this.getSelectedDate(); + setSelectedDateToFirstAvailable() { + this.selectedDate = this.getFirstAvailableDate(); }, }, watch: { From 3af1a9af4c2c903d52b0c132f9484cc6e3e81401 Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Wed, 31 Dec 2025 18:31:32 -0500 Subject: [PATCH 19/21] CASH-1315: remove redundent isLoading check --- src/digital-components/date-picker/date-picker.vue | 3 +-- src/layouts/schedule/schedule.vue | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index e12c835e9..d586ff839 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -200,7 +200,6 @@ export default { pricingByDayUpcharge: Number, isPricingByDayExperiment: Boolean, isMobileSelected: Boolean, - isLoadingDates: Boolean, }, setup(props) { const uuid = uuidv4(); @@ -847,7 +846,7 @@ export default { }, }, watch: { - isLoadingDates(newValue) { + isLoading(newValue) { // if done loading dates, then set to first available date if (newValue === false && this.firstAvailableSelectableDate) { this.selectedDate = this.firstAvailableSelectableDate; diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 178a15d7b..7c9d9f444 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -134,7 +134,6 @@ selectableDatesSetting="custom" ref="datePicker" v-model="selectedDate" - :isLoadingDates="isLoadingDates" :isMobileSelected="isMobileSelected" class="text-link-small" :getMoreDatesCallback="getMoreScheduleData" @@ -432,7 +431,6 @@ export default { selectableDatesInshop: [], selectableDatesMobile: [], preSelectedDate: null, - isLoadingDates: true, streetAddress: this.getServiceAddressFromStore(), apartmentNumberOrBusinessName: this.getServiceAddress2FromStore(), carId: this.getCarIdfromStore(), @@ -1204,7 +1202,6 @@ export default { ) { await this.$nextTick(); await this.$refs.datePicker.showAnotherMonth(); - this.isLoadingDates = false; this.setDisplayWaitList(); } } From bb293cf0fc9bc62210d75f3df8f76604eda27752 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 09:09:29 -0400 Subject: [PATCH 20/21] CASH-1713 | Insurance pricing error (tax refactor) Moved helper function to a helper file Price all line items on payment-method just in case something isn't in serverData yet --- src/helpers/pricing-helper.js | 20 ++++++++++++ src/layouts/payment-method/payment-method.vue | 32 +++++++++---------- src/store/index.js | 21 +----------- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/helpers/pricing-helper.js b/src/helpers/pricing-helper.js index 9aa317353..1216836d5 100644 --- a/src/helpers/pricing-helper.js +++ b/src/helpers/pricing-helper.js @@ -99,3 +99,23 @@ export async function getPricingByDayPartWithPrice(pageNameToLog) { return pricingResults[0]; } + +export function addPricesToLineItems(lineItems, pricingLineItems) { + lineItems.forEach((lineItem) => { + const lineItemIndex = pricingLineItems.findIndex( + (pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber + ); + + if (lineItem.childParts) { + addPricesToLineItems(lineItem.childParts, pricingLineItems); + } + + const pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0]; + lineItem.laborAmount = pricedLineItem.laborAmount; + lineItem.sellingPrice = pricedLineItem.sellingPrice; + lineItem.kitPrice = pricedLineItem.kitPrice; + lineItem.salesTax = pricedLineItem.salesTax; + }); + + return lineItems; +} \ No newline at end of file diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index ffb3d2353..6767777c8 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -155,7 +155,6 @@ import { getNewlyInactivatedPromos, } from "@/helpers/promotions-helper"; import { queryStrings } from "@/constants/query-strings"; -import { getQuerystringParameter } from "@/helpers/querystring-helper"; import { deepClone } from "@/helpers/object-helper"; import { Form } from "vee-validate"; @@ -163,17 +162,12 @@ import { defineRule } from "vee-validate"; import { required } from "@/helpers/validation-rules"; import { errorMessages } from "@/constants/error-messages"; import { AppointmentTypeStrings } from "@/constants/schedule-constants"; -import { partTypeStrings } from "@/constants/part-type-strings"; -import { mapTaxedLineItemsToStoreFormat } from "../../store"; import { coverageStatus } from "@/constants/insurance"; -import { containsLineItemWithPartType } from "@/helpers/service-package-helper"; import { containsRecalParts } from "@/helpers/recal-helper"; import { getBoolFromString } from "@/helpers/boolean-helper"; import { - getDisplayAmountDue, getAmountDue, - getSubTotal, - getSalesTax, + addPricesToLineItems } from "@/helpers/pricing-helper.js"; import { consumeQueryFromStash } from "@/router/methods/helpers/querystring-stash"; import { debugLog } from "@/helpers/debug-log-helper"; @@ -231,21 +225,28 @@ export default { const availableVaps = [resultMap.rainRepel, ...resultMap.wipers]; - const pricedAvailableVaps = await baseMixin.methods.dispatchStoreActionWithLogging( + const lineItemsOnOrderAndAvailableVaps = [ + ...availableVaps, + ...glassParts, + ...supportingItems, + ...vaps, + ]; + + // All line items are already priced except availableVaps + // Price everything again to ensure that serverData has all values + // Specifically this addresses an error where insurance client glass parts are not in serverData + // See CASH-1713 for details + const pricedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - availableLineItems: availableVaps, + availableLineItems: lineItemsOnOrderAndAvailableVaps, }, "payment-method", false ); - const lineItemsOnOrderAndAvailableVaps = [ - ...pricedAvailableVaps, - ...glassParts, - ...supportingItems, - ...vaps, - ]; + // Add prices to the availableVaps + const pricedAvailableVaps = addPricesToLineItems(availableVaps, pricedLineItems); // Promo logic // Populate the previous state of promos for toast message usage in "next()" @@ -265,7 +266,6 @@ export default { delete lineItemsForCart.serverData; // End of promo logic - // const vapsToAddToCart = getVapsThatNeedToBeAddedToSatisfyPromos( lineItemsForCart.promos ?? [], diff --git a/src/store/index.js b/src/store/index.js index 1fa9b4f14..ef67b84a0 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -59,6 +59,7 @@ import { } from "@/helpers/recal-helper"; import { externalParameterStatus } from "@/constants/external-parameters"; import { experimentSettings } from "@/constants/experiments"; +import { addPricesToLineItems } from "@/helpers/pricing-helper"; // Export State const getDefaultState = () => { @@ -3701,26 +3702,6 @@ function convertGlassPieceNamingFromApi(glassArray) { return glassArray; } -function addPricesToLineItems(lineItems, pricingLineItems) { - lineItems.forEach((lineItem) => { - const lineItemIndex = pricingLineItems.findIndex( - (pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber - ); - - if (lineItem.childParts) { - addPricesToLineItems(lineItem.childParts, pricingLineItems); - } - - const pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0]; - lineItem.laborAmount = pricedLineItem.laborAmount; - lineItem.sellingPrice = pricedLineItem.sellingPrice; - lineItem.kitPrice = pricedLineItem.kitPrice; - lineItem.salesTax = pricedLineItem.salesTax; - }); - - return lineItems; -} - function addTaxesToPricedLineItems(pricedLineItems, taxingLineItems = []) { pricedLineItems.forEach((pricedLineItem) => { const lineItemIndex = taxingLineItems.findIndex( From 1e6d1c0bfceb80ce7bd53d01c50c32a9131f6667 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 09:11:42 -0400 Subject: [PATCH 21/21] CASH-1713 | Formatting --- src/helpers/pricing-helper.js | 2 +- src/layouts/payment-method/payment-method.vue | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/helpers/pricing-helper.js b/src/helpers/pricing-helper.js index 1216836d5..0a8b85d7e 100644 --- a/src/helpers/pricing-helper.js +++ b/src/helpers/pricing-helper.js @@ -118,4 +118,4 @@ export function addPricesToLineItems(lineItems, pricingLineItems) { }); return lineItems; -} \ No newline at end of file +} diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 6767777c8..abee992bf 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -165,10 +165,7 @@ import { AppointmentTypeStrings } from "@/constants/schedule-constants"; import { coverageStatus } from "@/constants/insurance"; import { containsRecalParts } from "@/helpers/recal-helper"; import { getBoolFromString } from "@/helpers/boolean-helper"; -import { - getAmountDue, - addPricesToLineItems -} from "@/helpers/pricing-helper.js"; +import { getAmountDue, addPricesToLineItems } from "@/helpers/pricing-helper.js"; import { consumeQueryFromStash } from "@/router/methods/helpers/querystring-stash"; import { debugLog } from "@/helpers/debug-log-helper"; import { ErrorMessage } from "vee-validate";