diff --git a/src/constants/experiments.js b/src/constants/experiments.js index 9e959331..c336503b 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -2,6 +2,7 @@ const experimentUniverses = Object.freeze({ ISS_FUNNEL: 'ISSFunnel', ISS_FEATURETOGGLE_AREFEES_HIDDEN: 'NextGenISS_FeatureToggle_AreFeesHidden', ISS_FEATURETOGGLE_AREFEES_OVERRIDDEN: 'NextGenISS_FeatureToggle_AreFeesOverridden', + ISS_MOBILE_FIRST_APPOINTMENTS: 'ISS_Mobile_First_Appointments', ADYEN_PAYMENT_TEST: 'NextGenAdyenPaymentTest' }); @@ -12,6 +13,9 @@ const experimentSettings = Object.freeze({ ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_OVERRIDDEN: 'OverrideMobileFee', ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_HIDDEN: 'HideRecycleFee', ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_OVERRIDDEN: 'OverrideRecycleFee', + ISS_MOBILE_FIRST_MAX_MOBILE_DAYS: 'MaxMobileDays', + ISS_MOBILE_FIRST_MAX_PM_MOBILE_DAYS: 'MaxPmMobileDays', + ISS_MOBILE_FIRST_SHOW_FIRST_MOBILE_APPOINTMENT: 'ShowMobileFirstAppointment', ISS_ENABLE_ADYEN_V1: 'ISS_Enable_Adyen_V1' }); diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index b4a68eb0..610ececc 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -72,6 +72,7 @@ import serviceLocation from '@/layouts/schedule-page/service-location/service-lo import siteFooter from '@/iss-components/site-footer/site-footer.vue'; // Supporting files +import { experimentSettings } from '@/constants/experiments'; import { AppointmentTypeStrings, GET_MOBILE_TIME_SLOTS, @@ -323,9 +324,20 @@ export default { zipCodeCtu: resultMap.zipCodeData?.zipCodeCtu }; + const mobileFirstObject = { + mobileProviderNumber: resultMap.providers?.mobileProviderNumber, + serviceabilityDetails: resultMap.serviceabilityDetails, + zipCode: initialServiceLocationObj.zipCode + } + vm.setCmsContent(resultMap.cmsContent); vm.$refs.serviceLocation.initializeComponent(serviceLocationData); await vm.setData(resultMap.premiumFeeWithPrice, initialServiceLocationObj); + console.log('Schedule page loaded with all API calls settled'); + console.log('Checking mobile first experience eligibility...'); + console.log(resultMap); + console.log('Mobile first experience eligibility object:', mobileFirstObject); + await vm.checkMobileFirstExperience(mobileFirstObject); showIssLoadingModal(false); }); }, @@ -432,6 +444,98 @@ export default { arePagePrerequisitesValid() { return useMainStore().order.serviceLocation.zipCode !== null; }, + async checkMobileFirstExperience(mobileFirstObject = {}) { + const showMobileFirst = this.getSettingValue(experimentSettings.ISS_MOBILE_FIRST_SHOW_FIRST_MOBILE_APPOINTMENT); + console.log('Mobile first experience enabled:', showMobileFirst); + if (showMobileFirst) { + console.log('Checking mobile first experience eligibility...'); + const hasSelectedDate = !!this.getSelectedDate(); + const isServicableMobile = mobileFirstObject.serviceabilityDetails?.isGlassServiceableMobile; + if (!hasSelectedDate && isServicableMobile && mobileFirstObject.mobileProviderNumber && mobileFirstObject.zipCode) { + console.log('Get Mobile Dates, Select first one and call modal... Gonna be fantastical!'); + const todayDateObject = new Date(); + const todayDateString = convertDateToDateString(todayDateObject); + const calendarViewDirection = 'future'; + const initialDays = 15; + + const initialViewStartDate = todayDateString; + const initialEndDate = new Date(); + initialEndDate.setDate(initialEndDate.getDate() + (initialDays - 1)); + const initialViewEndDate = convertDateToDateString(initialEndDate); + const preSelectedDate = this.selectedDate; + + const initialData = await getAvailableDates( + initialViewStartDate, + initialViewEndDate, + AppointmentTypeStrings.MOBILE, + mobileFirstObject.mobileProviderNumber, + mobileFirstObject.zipCode + ).then((response) => ({ + todayDate: todayDateString, + initialViewStartDate, + initialViewEndDate, + calendarViewDirection, + initialShopTimeSlotsResponse: response, + preSelectedDate, + initialDaysLoaded: initialDays, + daysFromStart: null + })) + .catch(() => { + return { + todayDate: todayDateString, + initialViewStartDate, + initialViewEndDate, + calendarViewDirection, + initialShopTimeSlotsResponse: { days: [] }, + preSelectedDate, + initialDaysLoaded: initialDays, + daysFromStart: null + }; + }); + + console.log('Mobile first experience initial data...'); + console.log(initialData); + + const retTimeSlotsResponse = []; + initialData.initialShopTimeSlotsResponse.days.forEach((selectableDate) => { + const dateObjectToPush = { + date: selectableDate.date, + timeSlots: selectableDate.timeSlots, + morningTimeSlots: selectableDate.timeSlots.filter((timeSlot) => { + const timeHour = parseInt(timeSlot.startTime.split(':')[0], 10); + return timeHour < 12; + }).map((timeSlot) => this.mapTimeSlot(timeSlot, 'morning')), + afternoonTimeSlots: selectableDate.timeSlots.filter((timeSlot) => { + const timeHour = parseInt(timeSlot.startTime.split(':')[0], 10); + return timeHour >= 12; + }).map((timeSlot) => this.mapTimeSlot(timeSlot, 'afternoon')), + isSelected: false + }; + + if (dateObjectToPush.morningTimeSlots.length > 0) { + const findIndex = dateObjectToPush.morningTimeSlots.findIndex((timeSlot) => timeSlot.id.endsWith('DROP OFF')); + if (findIndex !== -1) { + const dropOffSlot = dateObjectToPush.morningTimeSlots.splice(findIndex, 1)[0]; + dateObjectToPush.morningTimeSlots.unshift(dropOffSlot); + } + } + if (dateObjectToPush.afternoonTimeSlots.length > 0) { + const findIndex = dateObjectToPush.afternoonTimeSlots.findIndex((timeSlot) => timeSlot.id.endsWith('DROP OFF')); + if (findIndex !== -1) { + const dropOffSlot = dateObjectToPush.afternoonTimeSlots.splice(findIndex, 1)[0]; + dateObjectToPush.afternoonTimeSlots.push(dropOffSlot); + } + } + retTimeSlotsResponse.push(dateObjectToPush); + }); + + console.log('Mobile first experience mapped time slots response...'); + console.log(retTimeSlotsResponse); + + this.mobileDatesData = initialData; + } + } + }, async setData(premiumFeeWithPriceResponse, initialServiceLocationObj) { this.selectedServiceLocation = initialServiceLocationObj; this.mobilePremiumAppointmentFee = premiumFeeWithPriceResponse @@ -486,6 +590,7 @@ export default { this.selectedMobileZipCode = null; }, dateSelectedFromPicker(date) { + console.log('Schedule selected date from picker', date); this.selectedDate = date; this.showDatePickerError = false; }, @@ -677,6 +782,13 @@ export default { this.selectedServiceLocation = inShopZipServiceLocation; } }, + mapTimeSlot(timeSlot, timeOfDay) { + return { + ...timeSlot, + isDropoff: timeSlot.id.endsWith('DROP OFF'), + timeOfDay + }; + }, mobileZipUpdatedFromServiceLocation(mobileZipServiceLocation) { if (mobileZipServiceLocation) { this.mobileProviderNumber = mobileZipServiceLocation.mobileProviderNumber; @@ -711,6 +823,7 @@ export default { this.selectableDatesData = data.initialShopTimeSlotsResponse; this.$refs.datePicker.initializeComponent(data); this.isDatePickerRefreshing = false; + console.log('Date picker refreshed with new provider/zip code data'); showIssLoadingModal(false); }); }, diff --git a/vue.config.js b/vue.config.js index d9d97c60..0a9dc98e 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,4 +1,4 @@ -process.env.VUE_APP_CONSUMER_CF_DISTRO = 'https://digitalapi.dev.safelite.io'; +process.env.VUE_APP_CONSUMER_CF_DISTRO = 'https://digitalapi.test.safelite.io'; process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost'; process.env.VUE_APP_CUSTOMER_PORTAL_URL = 'https://myaccountdev.safelite.com/'; process.env.VUE_APP_GOOGLE_PLACES_API_KEY = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0';