+ :class="[
+ isMobileFirstModalOpen || isMultiLocationModalOpen ? 'hidden-background' : '',
+ ]">
{
- vm.showMobileFirstModal();
+ // vm.showMobileFirstModal(); // KEEP IN CASE WE WANT TO REINSTATE MOBILE FIRST
+ vm.showMultiLocationModal();
vm.hideLoadingModal();
vm.calendarLoadingStatus = "none";
if (!vm.preSelectedDate) vm.setSelectedDateToFirstAvailable();
@@ -930,6 +940,11 @@ export default {
? this.$refs.mobileFirstModal?.getIsModalOpen()
: false;
},
+ isMultiLocationModalOpen() {
+ return this.selectableDatesMobile.days && this.selectableDatesInshop.days
+ ? this.$refs.multiLocationModal?.getIsModalOpen()
+ : false;
+ },
displayWaitList() {
if (!this.appointmentType) return false;
const firstMobileDateString =
@@ -990,6 +1005,12 @@ export default {
"true"
);
},
+ isShowMultiLocationPopup() {
+ return experimentMixin.methods.hasSettingEqualTo(
+ experimentSettings.SHOW_MULTI_LOCATION_APPT,
+ "true"
+ );
+ },
},
methods: {
splitCopyOnCMSPlaceHolder,
@@ -1275,7 +1296,8 @@ export default {
}
}
this.initializeDatePicker().then(() => {
- this.showMobileFirstModal();
+ // this.showMobileFirstModal(); // KEEP IN CASE WE WANT TO REINSTATE MOBILE FIRST
+ this.showMultiLocationModal();
this.hideLoadingModal();
this.calendarLoadingStatus = "none";
this.setSelectedDateToFirstAvailable();
@@ -1309,7 +1331,7 @@ export default {
},
async initializeDatePicker() {
- this.isShowMobileFirstAppt && this.showLoadingModal();
+ this.isShowMultiLocationPopup && this.showLoadingModal();
const includeMobileTimeSlots = this.isServiceableMobile;
const includeInshopTimeSlots = this.isServiceableInshop || this.isServiceableDropoff;
@@ -1821,7 +1843,8 @@ export default {
this.zipCodeCtu = newZipCode.zipCodeCtu;
this.selectedDate = null;
this.initializeDatePicker().then(() => {
- this.showMobileFirstModal();
+ // this.showMobileFirstModal(); // KEEP IN CASE WE WANT TO REINSTATE MOBILE FIRST
+ this.showMultiLocationModal();
this.hideLoadingModal();
this.calendarLoadingStatus = "none";
this.setSelectedDateToFirstAvailable();
@@ -2064,6 +2087,157 @@ export default {
}
}
},
+ async showMultiLocationModal() {
+ if (!this.selectedRouteCodeData?.routeCode) {
+ let maxDayRangeToShowPmTimeslot = experimentMixin.methods.getSettingValue(
+ experimentSettings.SHOW_PM_DAYS_MULTI_LOCATION
+ );
+ let maxDayRangeToShowNoPmTimeslot = experimentMixin.methods.getSettingValue(
+ experimentSettings.SHOW_NO_PM_DAYS_MULTI_LOCATION
+ );
+ let maxDayRangeToShowAnyTimeslot = experimentMixin.methods.getSettingValue(
+ experimentSettings.SHOW_NO_AVAILABILE_DAYS_MULTI_LOCATION
+ );
+ let showMultiLocationAppointment = experimentMixin.methods.getSettingValue(
+ experimentSettings.SHOW_MULTI_LOCATION_APPT
+ );
+
+ // temp vars to use for testing; TO BE REMOVED
+ maxDayRangeToShowPmTimeslot = 2;
+ maxDayRangeToShowNoPmTimeslot = 2;
+ maxDayRangeToShowAnyTimeslot = 5;
+
+ let promotedMobileAppointment = null;
+ let promotedInshopAppointment = null;
+ const todaysDate = getTodayDate();
+
+ // Helper function to calculate days until appointment (handles null/undefined)
+ const calculateDaysUntilDate = (appointmentObj) => {
+ const dateString = appointmentObj?.date;
+ return dateString
+ ? (new Date(dateString) - todaysDate) / (1000 * 60 * 60 * 24)
+ : null;
+ };
+
+ // Fetch all appointments
+ const [firstMobileAMAppt, firstMobilePMAppt, firstInshopAMAppt, firstInshopPMAppt] =
+ await Promise.all([
+ this.getFirstAvailableApptByTOD("AM", "mobile"),
+ this.getFirstAvailableApptByTOD("PM", "mobile"),
+ this.getFirstAvailableApptByTOD("AM", "inshop"),
+ this.getFirstAvailableApptByTOD("PM", "inshop"),
+ ]);
+
+ // Extract dates
+ const firstMobileAMDate = firstMobileAMAppt?.date;
+ const firstMobilePMDate = firstMobilePMAppt?.date;
+ const firstInshopAMDate = firstInshopAMAppt?.date;
+ const firstInshopPMDate = firstInshopPMAppt?.date;
+
+ // Calculate days until appointments
+ const numberOfDaysToFirstMobileAMDate = calculateDaysUntilDate(firstMobileAMAppt);
+ const numberOfDaysToFirstMobilePMDate = calculateDaysUntilDate(firstMobilePMAppt);
+ const numberOfDaysToFirstInshopAMDate = calculateDaysUntilDate(firstInshopAMAppt);
+ const numberOfDaysToFirstInshopPMDate = calculateDaysUntilDate(firstInshopPMAppt);
+
+ const shouldExposeMultiLocationModal = () => {
+ const isMobileAppointmentInDateRange =
+ (firstMobileAMDate &&
+ numberOfDaysToFirstMobileAMDate <= maxDayRangeToShowAnyTimeslot) ||
+ (firstMobilePMDate &&
+ numberOfDaysToFirstMobilePMDate <= maxDayRangeToShowAnyTimeslot);
+ const isInshopAppointmentInDateRange =
+ (firstInshopAMDate &&
+ numberOfDaysToFirstInshopAMDate <= maxDayRangeToShowAnyTimeslot) ||
+ (firstInshopPMDate &&
+ numberOfDaysToFirstInshopPMDate <= maxDayRangeToShowAnyTimeslot);
+
+ if (showMultiLocationAppointment) {
+ return isMobileAppointmentInDateRange && isInshopAppointmentInDateRange;
+ }
+ return false;
+ };
+
+ if (shouldExposeMultiLocationModal()) {
+ const multiLocationPopupExperiment =
+ store.getters.applicationUser.experiments.find(
+ (e) => e.universeName === experimentUniverses.MULTI_LOCATION_POPUP
+ );
+ const hasExposedMultiLocationPopup = multiLocationPopupExperiment?.isExposed;
+
+ if (!hasExposedMultiLocationPopup && multiLocationPopupExperiment) {
+ baseMixin.methods.dispatchStoreActionWithLogging(
+ storeActions.LOG_EXPERIMENT_EXPOSURE_AND_UPDATE_STORE,
+ {
+ userId: getUserIdValue(),
+ deviceId: getDeviceIdValue(),
+ sessionKey: getSessionKeyValue(),
+ pageName: "schedule",
+ experiment: multiLocationPopupExperiment,
+ },
+ "schedule",
+ false
+ );
+ }
+ if (this.isShowMultiLocationPopup) {
+ if (maxDayRangeToShowPmTimeslot == 0) {
+ // Selects the first available mobile time slot
+ promotedMobileAppointment =
+ numberOfDaysToFirstMobileAMDate <= numberOfDaysToFirstMobilePMDate
+ ? firstMobileAMAppt
+ : firstMobilePMAppt;
+ // Selects the first available inshop time slot
+ promotedInshopAppointment =
+ numberOfDaysToFirstInshopAMDate <= numberOfDaysToFirstInshopPMDate
+ ? firstInshopAMAppt
+ : firstInshopPMAppt;
+ } else {
+ if (
+ firstMobilePMDate &&
+ numberOfDaysToFirstMobilePMDate <= maxDayRangeToShowPmTimeslot
+ ) {
+ // Selects the first available PM time slot
+ promotedMobileAppointment = firstMobilePMAppt;
+ } else if (
+ firstMobilePMDate &&
+ numberOfDaysToFirstMobilePMDate >= maxDayRangeToShowNoPmTimeslot
+ ) {
+ // Selects the first available AM time slot. If none, selects the first available PM time slot
+ promotedMobileAppointment = firstMobileAMAppt
+ ? firstMobileAMAppt
+ : firstMobilePMAppt;
+ }
+
+ if (
+ firstInshopPMDate &&
+ numberOfDaysToFirstInshopPMDate <= maxDayRangeToShowPmTimeslot
+ ) {
+ // Selects the first available PM time slot
+ promotedInshopAppointment = firstInshopPMAppt;
+ } else if (
+ firstInshopPMDate &&
+ numberOfDaysToFirstInshopPMDate >= maxDayRangeToShowNoPmTimeslot
+ ) {
+ // Selects the first available AM time slot. If none, selects the first available PM time slot
+ promotedInshopAppointment = firstInshopAMAppt
+ ? firstInshopAMAppt
+ : firstInshopPMAppt;
+ }
+ }
+
+ if (promotedMobileAppointment && promotedInshopAppointment) {
+ this.$refs.multiLocationModal.setPromotedMobileAppointment(
+ promotedMobileAppointment
+ );
+ this.$refs.multiLocationModal.setPromotedInshopAppointment(
+ promotedInshopAppointment
+ );
+ this.$refs.multiLocationModal.openModal();
+ }
+ }
+ }
+ }
+ },
async getFirstAvailableApptByTOD(timeOfDay, appointmentType) {
let selectableDays;
if (appointmentType?.toLowerCase() == "mobile") {
@@ -2084,6 +2258,7 @@ export default {
},
timeSlot: null,
date: null,
+ addressCopy: null,
};
const isMatchingApptDay = dateObj.timeSlots.some(
(slot) =>
@@ -2116,6 +2291,18 @@ export default {
this.updateTimeSlot(timeSlotObj);
this.forwardButtonAction();
},
+ updateMultiLocationTimeSlotandNavigateForward({ selectedTimeSlot, appointmentType }) {
+ if (appointmentType?.toLowerCase() == "mobile") {
+ this.appointmentType = AppointmentTypeStrings.MOBILE;
+ } else if (appointmentType?.toLowerCase() == "inshop") {
+ this.appointmentType = AppointmentTypeStrings.IN_SHOP;
+ }
+ this.selectedMultiLocationAppointment = true;
+ this.selectedDate = selectedTimeSlot.date;
+ this.updateSelectedProvider();
+ this.updateTimeSlot(selectedTimeSlot);
+ this.forwardButtonAction();
+ },
updateRecalAcknowledgedAndNavigateForward(isAcknowledged) {
this.isRecalAcknowledgedForScheduling = isAcknowledged;
this.forwardButtonAction();
@@ -2139,6 +2326,7 @@ export default {
textBlock,
timeSlotQuestion,
mobileFirstModal,
+ multiLocationModal,
recalAckModal,
alert,
serviceZipModalQuestion,