Some Auto formatting on save for the index page Add global auth handler on Index page. remove a left in console.warn on schedule.
1056 lines
48 KiB
Vue
1056 lines
48 KiB
Vue
<template>
|
|
<Form
|
|
ref="theForm"
|
|
@submit="onSubmit"
|
|
@invalidSubmit="onInvalidSubmit">
|
|
<div class="fade-on-route-transition">
|
|
<div class="justify-content-center">
|
|
<siteHeader
|
|
cmsWidgetName="SiteHeaderWidget" />
|
|
</div>
|
|
<div class="iss-heritage-container-width">
|
|
<div class="schedule-page-container iss-heritage-content-container-width">
|
|
<siteSubHeader
|
|
cmsWidgetName="ScheduleSubHeaderWidget"
|
|
secondaryTextClasses="text-center small sub-text"
|
|
class="mt-4" />
|
|
<div class="service-location-content-container">
|
|
<serviceLocation
|
|
ref="serviceLocation"
|
|
:schedulingInshopAvailabilityRating="inShopAvailabilityRating"
|
|
@appointmentTypeChanged="appointmentTypeChangedFromServiceLocation"
|
|
@cityUpdated="cityUpdatedFromServiceLocation"
|
|
@clearMobileData="clearMobileDataFromServiceLocation"
|
|
@inShopZipUpdated="inShopZipUpdatedFromServiceLocation"
|
|
@mobileZipUpdated="mobileZipUpdatedFromServiceLocation"
|
|
@providerChanged="providerChangedFromServiceLocation" />
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-show="hasNeededServiceLocationData"
|
|
class="date-picker-container iss-heritage-content-container-width">
|
|
<div class="date-picker-content-container">
|
|
<locationAlerts
|
|
ref="locationAlerts"
|
|
cmsWidgetPrefix="LocationAlert-"
|
|
:city="selectedServiceLocationCity" />
|
|
<datePicker
|
|
ref="datePicker"
|
|
v-model="selectedTimeSlotInfo"
|
|
customComponentId="dateQuestion"
|
|
selectableDatesSetting="custom"
|
|
class="text-link-small"
|
|
:activeAppointmentType="selectedAppointmentType"
|
|
:isMobileView="isMobileView"
|
|
:showTimeSlotError="showDatePickerError"
|
|
:customSelectableDatesCallback="getAvailableDatesMethod"
|
|
@dateSelected="dateSelectedFromPicker"
|
|
@timeSlotSelected="timeSlotSelectedFromPicker" />
|
|
</div>
|
|
</div>
|
|
<div class="site-footer-container iss-heritage-content-container-width">
|
|
<siteFooter
|
|
ref="navbar"
|
|
class="mt-5"
|
|
cmsWidgetName="SiteFooterWidget"
|
|
:isForwardButtonHidden="!hasNeededServiceLocationData"
|
|
:isForwardButtonNavigationDisabled="!isFormValid"
|
|
@backClicked="navigateBack(this, navigateBackScenario)"
|
|
@forwardClicked="forwardButtonAction" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<suggestTimeslotModal
|
|
:ref="SUGGEST_TIMESLOT_MODAL_REF_NAME"
|
|
cmsWidgetName="SuggestTimeslotModal"
|
|
@confirmAppointmentClicked="autoSelectTimeslotConfirmed" />
|
|
<recalAckModal
|
|
:ref="RECAL_ACK_MODAL_REF_NAME"
|
|
cmsWidgetName="RecalAckModalWidget"
|
|
:ackError="ackError"
|
|
@recalAcknowledged="updateIsRecalAcknowledged"/>
|
|
</Form>
|
|
</template>
|
|
<script>
|
|
// Components
|
|
import siteHeader from '@/iss-components/site-header/site-header.vue';
|
|
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
|
|
import locationAlerts from '@/layouts/schedule-page/location-alerts/location-alerts.vue';
|
|
import datePicker from '@/digital-components/date-picker/date-picker.vue';
|
|
import serviceLocation from '@/layouts/schedule-page/service-location/service-location.vue';
|
|
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
|
import suggestTimeslotModal from '@/layouts/schedule-page/suggest-timeslot-modal/suggest-timeslot-modal.vue';
|
|
import recalAckModal from '@/layouts/schedule-page/recal-ack-modal/recal-ack-modal.vue';
|
|
|
|
// Supporting files
|
|
import { experimentSettings, experimentTest, experimentVariation, experimentUniverses } from '@/constants/experiments';
|
|
import {
|
|
AppointmentTypeStrings,
|
|
GET_MOBILE_TIME_SLOTS,
|
|
GET_SHOP_TIME_SLOTS,
|
|
PREMIUM_FEE_PART_TYPE
|
|
} from '@/constants/schedule-constants.js';
|
|
import {
|
|
fetchCmsContentForPage,
|
|
splitCopyOnCMSPlaceHolder
|
|
} from '@/helpers/cms-content-helper';
|
|
import {
|
|
calcDaysBetweenDates,
|
|
convertDateToDateString,
|
|
sumDateString
|
|
} from '@/helpers/date-helper';
|
|
import settleAllPromises from '@/helpers/layout-helper';
|
|
import showIssLoadingModal from '@/helpers/loading-modal-helper.js';
|
|
import {
|
|
getPricedMobileFeePart,
|
|
getMobileZipCodeData,
|
|
getZipCodeData,
|
|
isServiceableMobileWithData,
|
|
mapTimeSlot
|
|
} from '@/helpers/service-location-helper';
|
|
import { Form } from 'vee-validate';
|
|
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
|
import { useMainStore } from '@/store';
|
|
import { containsRecalParts, anyPartWithRequiresRecalFlag } from '@/helpers/recal-helper';
|
|
import errorMessages from '@/constants/error-messages';
|
|
|
|
// Define constants
|
|
const SUGGEST_TIMESLOT_MODAL_REF_NAME = 'SuggestTimeslotModal';
|
|
const TIME_SLOTS_CALL_DAYS_LIMIT = 15;
|
|
const RECAL_ACK_MODAL_REF_NAME = 'recalAckModal';
|
|
|
|
const getAvailableDates = async (
|
|
startDateString,
|
|
endDateString,
|
|
appointmentType,
|
|
providerNumber,
|
|
mobileZipCodeOverride = null
|
|
) => {
|
|
const apiEndDateLimit = sumDateString(
|
|
startDateString,
|
|
TIME_SLOTS_CALL_DAYS_LIMIT - 1
|
|
);
|
|
const difference = calcDaysBetweenDates(startDateString, endDateString);
|
|
const apiCallsCount = Math.ceil(difference / TIME_SLOTS_CALL_DAYS_LIMIT);
|
|
const storeActionConfigs = [];
|
|
let apiStartDate = startDateString;
|
|
let apiEndDate = endDateString;
|
|
|
|
for (let i = 1; i <= apiCallsCount; i++) {
|
|
let storeActionConfig;
|
|
|
|
if (i > 1) {
|
|
apiStartDate = sumDateString(apiEndDate, 1);
|
|
apiEndDate = sumDateString(
|
|
apiStartDate,
|
|
TIME_SLOTS_CALL_DAYS_LIMIT - 1
|
|
);
|
|
|
|
if (i === apiCallsCount) {
|
|
apiEndDate = endDateString;
|
|
}
|
|
} else if (apiEndDate > apiEndDateLimit) {
|
|
apiEndDate = apiEndDateLimit;
|
|
}
|
|
|
|
if (appointmentType === AppointmentTypeStrings.MOBILE || appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
|
|
storeActionConfig = {
|
|
storeAction: GET_MOBILE_TIME_SLOTS,
|
|
payload: {
|
|
startDate: apiStartDate,
|
|
endDate: apiEndDate,
|
|
zipCodeOverride: mobileZipCodeOverride
|
|
}
|
|
};
|
|
} else {
|
|
storeActionConfig = {
|
|
storeAction: GET_SHOP_TIME_SLOTS,
|
|
payload: {
|
|
startDate: apiStartDate,
|
|
endDate: apiEndDate,
|
|
shopAppointmentType: appointmentType,
|
|
providerNumber
|
|
}
|
|
};
|
|
}
|
|
if (apiStartDate < apiEndDate) storeActionConfigs.push(storeActionConfig);
|
|
}
|
|
|
|
const timeSlotsResponsesData = {
|
|
days: []
|
|
};
|
|
|
|
function compareDayStrings(a, b) {
|
|
if (a.date < b.date) return -1;
|
|
if (a.date > b.date) return 1;
|
|
return 0;
|
|
}
|
|
|
|
const makeParallelCalls = async () => {
|
|
await Promise.all(storeActionConfigs.map(async (storeAction) => {
|
|
let timeSlotsResponse = null;
|
|
if (storeAction.storeAction === GET_SHOP_TIME_SLOTS) {
|
|
if (storeAction.payload.providerNumber) {
|
|
timeSlotsResponse = await useMainStore().getShopTimeSlots(
|
|
storeAction.payload.startDate,
|
|
storeAction.payload.endDate,
|
|
storeAction.payload.shopAppointmentType,
|
|
storeAction.payload.providerNumber
|
|
);
|
|
}
|
|
} else if (storeAction.payload?.zipCodeOverride) {
|
|
timeSlotsResponse = await useMainStore().getMobileTimeSlots(
|
|
storeAction.payload.startDate,
|
|
storeAction.payload.endDate,
|
|
storeAction.payload.zipCodeOverride
|
|
);
|
|
}
|
|
|
|
if (!timeSlotsResponse || !timeSlotsResponse.data) {
|
|
return;
|
|
}
|
|
|
|
timeSlotsResponsesData.estimatedServiceMinutesMinimum = timeSlotsResponse.data.estimatedServiceMinutesMinimum;
|
|
timeSlotsResponsesData.estimatedServiceMinutesMaximum = timeSlotsResponse.data.estimatedServiceMinutesMaximum;
|
|
timeSlotsResponsesData.days = [
|
|
...timeSlotsResponsesData.days,
|
|
...timeSlotsResponse.data.days
|
|
];
|
|
}));
|
|
};
|
|
|
|
return makeParallelCalls().then(() => {
|
|
// sort days chronologically
|
|
timeSlotsResponsesData.days.sort(compareDayStrings);
|
|
return timeSlotsResponsesData;
|
|
})
|
|
.catch(() => {
|
|
return timeSlotsResponsesData;
|
|
});
|
|
};
|
|
|
|
export default {
|
|
name: 'schedule-page',
|
|
components: {
|
|
siteHeader,
|
|
siteSubHeader,
|
|
locationAlerts,
|
|
datePicker,
|
|
serviceLocation,
|
|
siteFooter,
|
|
suggestTimeslotModal,
|
|
Form,
|
|
recalAckModal
|
|
},
|
|
mixins: [BaseFormMixin],
|
|
async beforeRouteEnter(to, from, next) {
|
|
// Call APIs
|
|
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
|
let storeServiceLocation = useMainStore().order.serviceLocation;
|
|
let storeSelectedProvider = storeServiceLocation?.provider;
|
|
|
|
const storeSelectedSchedule = useMainStore().order.schedule;
|
|
if (storeSelectedProvider?.providerNumber && !storeSelectedSchedule?.routeCode) {
|
|
useMainStore().resetServiceLocationProvider();
|
|
storeServiceLocation = useMainStore().order.serviceLocation;
|
|
storeSelectedProvider = storeServiceLocation?.provider;
|
|
}
|
|
const storeSelectedAppointmentType = storeServiceLocation?.appointmentType;
|
|
const isMobileAppointment = storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE
|
|
|| storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP;
|
|
const serviceZipCode = storeServiceLocation?.zipCode || useMainStore().order.customer.address.zipCode;
|
|
const zipCodeData = getZipCodeData(serviceZipCode);
|
|
const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode);
|
|
const serviceabilityDetailsPromise = useMainStore().getServiceabilityDetails(serviceZipCode);
|
|
const getGlassFeesPromise = useMainStore().getGlassFees();
|
|
const providersPromise = useMainStore().getSafeliteProviders(serviceZipCode, 150);
|
|
const premiumFeePromise = useMainStore().getMobilePremiumFee();
|
|
const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
|
|
if (result.data) {
|
|
return useMainStore().getCombinedQuote(result.data);
|
|
}
|
|
return result.data;
|
|
});
|
|
|
|
// Settle promises and get results
|
|
const promiseResultMap = [
|
|
{
|
|
resultKey: 'cmsContent',
|
|
promise: cmsContentPromise
|
|
},
|
|
{
|
|
resultKey: 'mobileFeePart',
|
|
promise: mobileFeePartPromise
|
|
},
|
|
{
|
|
resultKey: 'glassFees',
|
|
promise: getGlassFeesPromise
|
|
},
|
|
{
|
|
resultKey: 'serviceabilityDetails',
|
|
promise: serviceabilityDetailsPromise
|
|
},
|
|
{
|
|
resultKey: 'zipCodeData',
|
|
promise: zipCodeData
|
|
},
|
|
{
|
|
resultKey: 'providers',
|
|
promise: providersPromise
|
|
},
|
|
{
|
|
resultKey: 'premiumFeeWithPrice',
|
|
promise: premiumFeeWithPricePromise
|
|
}
|
|
];
|
|
|
|
// use resultMap to populate layout content.
|
|
const resultMap = await settleAllPromises(promiseResultMap);
|
|
const providersUnderOneHundredMiles = resultMap.providers?.shopProviders?.filter((provider) => provider.distanceInMiles <= 100);
|
|
const serviceLocationData = {
|
|
defaultMobileZipCode: isMobileAppointment
|
|
? storeServiceLocation?.zipCode
|
|
: '',
|
|
glassFees: resultMap.glassFees,
|
|
mobileFeePart: resultMap.mobileFeePart,
|
|
providers: {
|
|
...resultMap.providers,
|
|
shopProviders: providersUnderOneHundredMiles || []
|
|
},
|
|
serviceabilityDetails: resultMap.serviceabilityDetails,
|
|
zipCodeData: resultMap.zipCodeData
|
|
};
|
|
useMainStore().updateIsSafeliteProvider(true);
|
|
next(async (vm) => {
|
|
const foundProviderInFullList = resultMap.providers?.shopProviders
|
|
.find((provider) => provider.providerNumber === storeSelectedProvider?.providerNumber) || null;
|
|
const foundProviderInHundredMiles = providersUnderOneHundredMiles
|
|
.find((provider) => provider.providerNumber === storeSelectedProvider?.providerNumber) || null;
|
|
|
|
if (!foundProviderInHundredMiles && !foundProviderInFullList) {
|
|
if (storeSelectedProvider?.providerNumber && resultMap.providers?.shopProviders) {
|
|
serviceLocationData.providers?.shopProviders.push(storeSelectedProvider);
|
|
}
|
|
} else if (!foundProviderInHundredMiles && foundProviderInFullList) {
|
|
serviceLocationData.providers?.shopProviders.push(foundProviderInFullList);
|
|
}
|
|
|
|
const initialServiceLocationObj = {
|
|
mobileProviderNumber: isMobileAppointment
|
|
? storeSelectedProvider?.providerNumber
|
|
: null,
|
|
provider: isMobileAppointment ? null : foundProviderInFullList || resultMap.providers?.shopProviders[0] || null,
|
|
zipCode: useMainStore().order.serviceLocation.zipCode || useMainStore().order.customer.address.zipCode,
|
|
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);
|
|
await vm.checkMobileFirstExperience(mobileFirstObject);
|
|
showIssLoadingModal(false);
|
|
});
|
|
},
|
|
setup() {
|
|
const mainStore = useMainStore();
|
|
return { mainStore };
|
|
},
|
|
data() {
|
|
return {
|
|
inShopAvailabilityRating: 'high',
|
|
inShopDatesData: [],
|
|
isDatePickerRefreshing: false,
|
|
isMobileView: false,
|
|
mobileDatesData: [],
|
|
mobileFeePart: null,
|
|
mobilePremiumAppointmentFee: null,
|
|
mobileProviderNumber: null,
|
|
selectableDatesData: [],
|
|
selectedAppointmentType: this.getAppointmentType(),
|
|
selectedDate: this.getSelectedDate(),
|
|
selectedMobileZipCode: null,
|
|
selectedProvider: this.getSelectedProvider(),
|
|
selectedServiceLocation: this.getServiceLocation(),
|
|
selectedServiceLocationCity: this.getServiceLocationCity(),
|
|
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
|
|
showDatePickerError: false,
|
|
SUGGEST_TIMESLOT_MODAL_REF_NAME,
|
|
RECAL_ACK_MODAL_REF_NAME,
|
|
isRecalAcknowledged: this.getIsRecalAcknowledgedForScheduling()
|
|
};
|
|
},
|
|
computed: {
|
|
hasNeededServiceLocationData() {
|
|
const serviceLocationToUse = this.selectedServiceLocation;
|
|
if (!serviceLocationToUse || !this.selectedAppointmentType) {
|
|
return false;
|
|
}
|
|
|
|
const validMobileAppointmentType = ((this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
|
|
|| this.selectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP)
|
|
&& serviceLocationToUse.mobileProviderNumber);
|
|
const validInShopAppointmentType = ((this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP
|
|
|| this.selectedAppointmentType === AppointmentTypeStrings.DROP_OFF)
|
|
&& (this.selectedProvider?.providerNumber || serviceLocationToUse.provider?.providerNumber));
|
|
|
|
const serviceLocationPreReqs = serviceLocationToUse.zipCode !== null
|
|
&& serviceLocationToUse.zipCodeCtu !== null
|
|
&& serviceLocationToUse.appointmentType !== null
|
|
&& (validMobileAppointmentType || validInShopAppointmentType)
|
|
&& !this.isDatePickerRefreshing;
|
|
|
|
const damageInfo = useMainStore().order.damage.isRepair
|
|
|| (useMainStore().order.lineItems?.glassParts != null && useMainStore().order.lineItems.glassParts.length > 0);
|
|
|
|
const supportingItems = this.supportingItems !== null;
|
|
|
|
return (serviceLocationPreReqs && supportingItems && damageInfo);
|
|
},
|
|
isFormValid() {
|
|
const hasTimeSlotSelected = this.selectedTimeSlotInfo?.timeSlot?.routeCode != null;
|
|
return hasTimeSlotSelected;
|
|
},
|
|
navigateBackScenario() {
|
|
const { isNoComp, isITAC } = useMainStore();
|
|
return isNoComp || isITAC
|
|
? this.navigationScenarios.CLICKED_BACK_CANNOT_REACH_TPA_FLOW
|
|
: this.navigationScenarios.CLICKED_BACK_CAN_REACH_TPA_FLOW;
|
|
},
|
|
supportingItems() {
|
|
return useMainStore().lineItems.supportingItems;
|
|
},
|
|
displayRecalAckModal() {
|
|
// if any of the glass parts contain an item with the requiresRecalibration flag set to true
|
|
// and the order does not contain a recalibration part, show the recalibration acknowledgement modal
|
|
const { glassParts } = useMainStore().order.lineItems;
|
|
const containsRecalPart = containsRecalParts(glassParts);
|
|
const hasPartWithRecalRequirement = anyPartWithRequiresRecalFlag(glassParts);
|
|
|
|
if (!containsRecalPart && hasPartWithRecalRequirement) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
ackError() {
|
|
return errorMessages.ACKNOWLEDGEMENT_REQUIRED;
|
|
}
|
|
},
|
|
watch: {
|
|
inShopDatesData(newData) {
|
|
if (newData?.initialShopTimeSlotsResponse?.days?.length > 0) {
|
|
const numberOfDaysNeededToBeHighAvailability = 2;
|
|
const availabilityEndDate = new Date();
|
|
availabilityEndDate.setDate(availabilityEndDate.getDate() + 6);
|
|
|
|
const datesInAvailabilityRange = newData.initialShopTimeSlotsResponse.days.filter((day) => {
|
|
const dayDate = new Date(`${day.date}T00:00:00`);
|
|
return dayDate <= availabilityEndDate;
|
|
});
|
|
const isGoodAvailability =
|
|
datesInAvailabilityRange.filter((x) => x.timeSlots.length > 0).length
|
|
>= numberOfDaysNeededToBeHighAvailability;
|
|
|
|
this.inShopAvailabilityRating = isGoodAvailability ? 'high' : 'low';
|
|
} else {
|
|
this.inShopAvailabilityRating = 'low';
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
showIssLoadingModal(true);
|
|
this.mql = window.matchMedia('(min-width: 1200px)');
|
|
this.isMobileView = !this.mql.matches;
|
|
this.mql.addEventListener('change', this.handleMqlChange);
|
|
this.mainStore.order.isRecalAcknowledgedForScheduling = false;
|
|
this.isRecalAcknowledged = false;
|
|
},
|
|
unmounted() {
|
|
if (this.mql) {
|
|
this.mql.removeEventListener('change', this.handleMqlChange);
|
|
}
|
|
},
|
|
methods: {
|
|
splitCopyOnCMSPlaceHolder,
|
|
arePagePrerequisitesValid() {
|
|
return useMainStore().order.serviceLocation.zipCode !== null;
|
|
},
|
|
async autoSelectTimeslotConfirmed(emittedValue) {
|
|
if (this.mainStore.isNoComp || this.mainStore.isITAC) {
|
|
console.log('User is No Comp or ITAC, skipping mobile fee update on auto select timeslot confirmed');
|
|
// this.mainStore.updateMobileFee(this.mobileFeePart);
|
|
}
|
|
|
|
const providerToUse = {
|
|
providerNumber: emittedValue.mobileProviderNumber,
|
|
address: {
|
|
streetAddress: null,
|
|
city: null,
|
|
state: null,
|
|
zipCode: null,
|
|
zipCodeCtu: null
|
|
}
|
|
};
|
|
|
|
this.mainStore.updateServiceLocation({
|
|
state: emittedValue.zipCodeData.state,
|
|
zipCode: emittedValue.zipCodeData.zipCode,
|
|
zipCodeCtu: emittedValue.zipCodeData.zipCodeCtu,
|
|
appointmentType: AppointmentTypeStrings.MOBILE,
|
|
provider: providerToUse
|
|
});
|
|
|
|
const timeSlotToUse = {
|
|
date: emittedValue.date,
|
|
routeCode: emittedValue.timeSlot.id,
|
|
startTime: emittedValue.timeSlot.startTime,
|
|
endTime: emittedValue.timeSlot.endTime,
|
|
jobMaxMinutes: emittedValue.estimatedServiceMinutesMax.toString(),
|
|
jobMinMinutes: emittedValue.estimatedServiceMinutesMin.toString(),
|
|
};
|
|
|
|
this.selectedAppointmentType = AppointmentTypeStrings.MOBILE;
|
|
this.pushServiceTypeEvent();
|
|
this.mainStore.saveSchedule(timeSlotToUse);
|
|
showIssLoadingModal(true);
|
|
this.$router.navigate(
|
|
this.navigationScenarios.CLICKED_FORWARD,
|
|
this.$route
|
|
);
|
|
},
|
|
async checkMobileFirstExperience(mobileFirstObject = {}) {
|
|
const mobileFirstExperimentVariation = this.getExperimentVariationNameByTestName(experimentTest.ISS_MOBILE_FIRST_POPUP_V3);
|
|
const isMobileFirstTestVariation = mobileFirstExperimentVariation === experimentVariation.ISS_MOBILE_FIRST_TEST_V3;
|
|
const showMobileFirst = this.getSettingValue(experimentSettings.ISS_MOBILE_FIRST_SHOW_FIRST_MOBILE_APPOINTMENT);
|
|
if (showMobileFirst) {
|
|
const pmMobileDaysLimit = this.getSettingValue(experimentSettings.ISS_MOBILE_FIRST_MAX_PM_MOBILE_DAYS);
|
|
const mobileDaysLimit = this.getSettingValue(experimentSettings.ISS_MOBILE_FIRST_MAX_MOBILE_DAYS);
|
|
const hasSelectedDate = !!this.getSelectedDate();
|
|
const isServiceableMobile = isServiceableMobileWithData(
|
|
mobileFirstObject.serviceabilityDetails?.isGlassServiceableMobile ?? null,
|
|
mobileFirstObject.serviceabilityDetails?.isRecalibrationServiceableMobile ?? null
|
|
);
|
|
if (!hasSelectedDate && isServiceableMobile && mobileFirstObject.mobileProviderNumber && mobileFirstObject.zipCode) {
|
|
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
|
|
};
|
|
});
|
|
|
|
this.mobileDatesData = initialData;
|
|
|
|
const estimatedServiceMinutesMax = initialData.initialShopTimeSlotsResponse?.estimatedServiceMinutesMaximum || 120;
|
|
const estimatedServiceMinutesMin = initialData.initialShopTimeSlotsResponse?.estimatedServiceMinutesMinimum || 90;
|
|
|
|
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) => mapTimeSlot(timeSlot, 'morning')),
|
|
afternoonTimeSlots: selectableDate.timeSlots.filter((timeSlot) => {
|
|
const timeHour = parseInt(timeSlot.startTime.split(':')[0], 10);
|
|
return timeHour >= 12;
|
|
}).map((timeSlot) => 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);
|
|
});
|
|
|
|
let dateDifferenceForPmMobile = null;
|
|
const firstPmMobileDateWithTimeSlots = retTimeSlotsResponse.find((date) => {
|
|
const hasPmMobileTimeSlots = date.afternoonTimeSlots?.length > 0;
|
|
if (hasPmMobileTimeSlots && pmMobileDaysLimit) {
|
|
dateDifferenceForPmMobile = calcDaysBetweenDates(todayDateString, date.date);
|
|
return dateDifferenceForPmMobile <= pmMobileDaysLimit;
|
|
}
|
|
return hasPmMobileTimeSlots;
|
|
});
|
|
|
|
let dateDifferenceForMobile = null;
|
|
const firstMobileDateWithTimeSlots = retTimeSlotsResponse.find((date) => {
|
|
const hasMobileTimeSlots = date.morningTimeSlots?.length > 0;
|
|
const hasPmMobileTimeSlots = date.afternoonTimeSlots?.length > 0;
|
|
if (hasMobileTimeSlots || hasPmMobileTimeSlots) {
|
|
if (mobileDaysLimit) {
|
|
dateDifferenceForMobile = calcDaysBetweenDates(todayDateString, date.date);
|
|
return mobileDaysLimit && dateDifferenceForMobile <= mobileDaysLimit;
|
|
}
|
|
return true;
|
|
}
|
|
return hasPmMobileTimeSlots;
|
|
});
|
|
|
|
const zipCodeData = await getMobileZipCodeData(mobileFirstObject.zipCode);
|
|
if ((firstPmMobileDateWithTimeSlots || firstMobileDateWithTimeSlots) && zipCodeData?.isValid) {
|
|
zipCodeData.zipCode = mobileFirstObject.zipCode;
|
|
const timeSlotForAutoSelectionMobile = {
|
|
date: firstPmMobileDateWithTimeSlots ? firstPmMobileDateWithTimeSlots.date : firstMobileDateWithTimeSlots.date,
|
|
estimatedServiceMinutesMax,
|
|
estimatedServiceMinutesMin,
|
|
isRepair: this.mainStore.order.damage.isRepair,
|
|
mobileProviderNumber: mobileFirstObject.mobileProviderNumber,
|
|
timeSlot: firstPmMobileDateWithTimeSlots ? firstPmMobileDateWithTimeSlots.afternoonTimeSlots[0]
|
|
: (firstMobileDateWithTimeSlots.morningTimeSlots[0] || firstMobileDateWithTimeSlots.afternoonTimeSlots[0]),
|
|
zipCodeData
|
|
};
|
|
|
|
const dateObjectToUse = new Date(`${timeSlotForAutoSelectionMobile.date}T${timeSlotForAutoSelectionMobile.timeSlot.startTime}:00`);
|
|
timeSlotForAutoSelectionMobile.dateObject = dateObjectToUse;
|
|
timeSlotForAutoSelectionMobile.dayOfWeek = dateObjectToUse.toLocaleDateString('en-US', { weekday: 'long' });
|
|
|
|
const experiment = this.getExperimentByName(experimentUniverses.ISS_MOBILE_FIRST_APPOINTMENTS);
|
|
if (experiment && !experiment.isExposed) {
|
|
this.mainStore.logMobileFirstExperimentExposure();
|
|
}
|
|
|
|
if (isMobileFirstTestVariation) {
|
|
this.$refs[SUGGEST_TIMESLOT_MODAL_REF_NAME].openModal(timeSlotForAutoSelectionMobile);
|
|
} else {
|
|
console.log('In Control group or experiment not found, skip showing popup');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
async setData(premiumFeeWithPriceResponse, initialServiceLocationObj) {
|
|
this.selectedServiceLocation = initialServiceLocationObj;
|
|
this.mobilePremiumAppointmentFee = premiumFeeWithPriceResponse
|
|
? premiumFeeWithPriceResponse[0]
|
|
: null;
|
|
|
|
if (initialServiceLocationObj?.zipCodeCtu) {
|
|
this.$refs.locationAlerts.loadInitialData(
|
|
initialServiceLocationObj.zipCodeCtu,
|
|
initialServiceLocationObj.provider?.ctu
|
|
).then((alertReasons) => {
|
|
this.$refs.locationAlerts.initializeComponent(alertReasons.data);
|
|
});
|
|
}
|
|
|
|
if (this.selectedAppointmentType !== AppointmentTypeStrings.MOBILE
|
|
&& this.selectedAppointmentType !== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
|
|
await this.getDatePickerInitialData(initialServiceLocationObj.provider?.providerNumber).then((initialData) => {
|
|
this.selectableDatesData = initialData.initialShopTimeSlotsResponse;
|
|
this.$refs.datePicker.setCalendarData(initialData);
|
|
});
|
|
} else {
|
|
this.mobileProviderNumber = initialServiceLocationObj.mobileProviderNumber;
|
|
this.selectedMobileZipCode = initialServiceLocationObj.zipCode;
|
|
await this.getDatePickerInitialData().then((initialData) => {
|
|
this.selectableDatesData = initialData.initialShopTimeSlotsResponse;
|
|
this.$refs.datePicker.setCalendarData(initialData);
|
|
});
|
|
}
|
|
},
|
|
appointmentTypeChangedFromServiceLocation(newAppointmentType) {
|
|
this.selectedAppointmentType = newAppointmentType.appointmentType;
|
|
if (newAppointmentType.appointmentType === AppointmentTypeStrings.IN_SHOP) {
|
|
if (this.inShopDatesData?.initialShopTimeSlotsResponse?.days?.length > 0) {
|
|
this.selectableDatesData = this.inShopDatesData.initialShopTimeSlotsResponse;
|
|
this.$refs.datePicker.initializeComponent(this.inShopDatesData);
|
|
}
|
|
} else if (this.mobileDatesData?.initialShopTimeSlotsResponse?.days?.length > 0) {
|
|
this.selectableDatesData = this.mobileDatesData.initialShopTimeSlotsResponse;
|
|
this.$refs.datePicker.initializeComponent(this.mobileDatesData);
|
|
}
|
|
},
|
|
cityUpdatedFromServiceLocation(newCity) {
|
|
this.selectedServiceLocationCity = newCity;
|
|
},
|
|
clearMobileDataFromServiceLocation() {
|
|
if (this.selectedServiceLocation) {
|
|
this.selectedServiceLocation.mobileProviderNumber = null;
|
|
}
|
|
this.mobileDatesData = [];
|
|
this.mobileProviderNumber = null;
|
|
this.selectedMobileZipCode = null;
|
|
},
|
|
dateSelectedFromPicker(date) {
|
|
this.selectedDate = date;
|
|
this.showDatePickerError = false;
|
|
},
|
|
getAppointmentType() {
|
|
return this.mainStore.order?.serviceLocation?.appointmentType;
|
|
},
|
|
async getAvailableDatesMethod(startDate, endDate) {
|
|
let mobileProviderNumberToUse = this.mobileProviderNumber;
|
|
if (this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
|
|
|| this.selectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
|
|
mobileProviderNumberToUse = this.selectedServiceLocation.mobileProviderNumber;
|
|
}
|
|
|
|
const newShopTimeSlots = await getAvailableDates(
|
|
startDate,
|
|
endDate,
|
|
this.selectedAppointmentType,
|
|
this.selectedProvider?.providerNumber || mobileProviderNumberToUse,
|
|
this.selectedMobileZipCode
|
|
);
|
|
// ADD API CALL RESULTS TO EXISTING DATE DATA
|
|
this.selectableDatesData.days =
|
|
this.selectableDatesData.days.concat(newShopTimeSlots.days);
|
|
return newShopTimeSlots;
|
|
},
|
|
getAvailableDates,
|
|
async getDatePickerInitialData(defaultProviderNumber = null) {
|
|
let todayDateString;
|
|
const todayDateObject = new Date();
|
|
const calendarViewDirection = 'future';
|
|
const initialDays = 15;
|
|
|
|
if (this.todayString) {
|
|
todayDateString = this.todayString;
|
|
} else {
|
|
todayDateString = convertDateToDateString(todayDateObject);
|
|
}
|
|
|
|
const initialViewStartDate = todayDateString;
|
|
const initialEndDate = new Date();
|
|
initialEndDate.setDate(initialEndDate.getDate() + (initialDays - 1));
|
|
let initialViewEndDate = convertDateToDateString(initialEndDate);
|
|
const preSelectedDate = this.selectedDate;
|
|
|
|
const endDateObject = this.getEndDateForExistingDate(
|
|
todayDateObject,
|
|
preSelectedDate,
|
|
initialDays
|
|
);
|
|
|
|
if (endDateObject.endDateString !== initialViewEndDate) {
|
|
initialViewEndDate = endDateObject.endDateString;
|
|
}
|
|
|
|
let mobileProviderNumberToUse = defaultProviderNumber;
|
|
if (this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
|
|
|| this.selectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
|
|
mobileProviderNumberToUse = this.selectedServiceLocation.mobileProviderNumber;
|
|
}
|
|
|
|
const initialData = await getAvailableDates(
|
|
initialViewStartDate,
|
|
initialViewEndDate,
|
|
this.selectedAppointmentType || AppointmentTypeStrings.IN_SHOP,
|
|
this.selectedProvider?.providerNumber || mobileProviderNumberToUse,
|
|
this.selectedServiceLocation.zipCode
|
|
).then((response) => ({
|
|
todayDate: todayDateString,
|
|
initialViewStartDate,
|
|
initialViewEndDate,
|
|
calendarViewDirection,
|
|
initialShopTimeSlotsResponse: response,
|
|
preSelectedDate,
|
|
initialDaysLoaded: endDateObject.newDaysLoaded || initialDays,
|
|
daysFromStart: endDateObject.daysFromStart || null
|
|
}))
|
|
.catch(() => {
|
|
return {
|
|
todayDate: todayDateString,
|
|
initialViewStartDate,
|
|
initialViewEndDate,
|
|
calendarViewDirection,
|
|
initialShopTimeSlotsResponse: { days: [] },
|
|
preSelectedDate,
|
|
initialDaysLoaded: endDateObject.newDaysLoaded || initialDays,
|
|
daysFromStart: endDateObject.daysFromStart || null
|
|
};
|
|
});
|
|
|
|
if (this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
|
|
|| this.selectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
|
|
this.pushMobileFirstDateEvent(initialData);
|
|
this.mobileDatesData = initialData;
|
|
|
|
if (this.selectedProvider?.providerNumber) {
|
|
const inShopData = await getAvailableDates(
|
|
initialViewStartDate,
|
|
initialViewEndDate,
|
|
AppointmentTypeStrings.IN_SHOP,
|
|
this.selectedProvider?.providerNumber || defaultProviderNumber,
|
|
this.selectedServiceLocation.zipCode
|
|
).then((response) => ({
|
|
todayDate: todayDateString,
|
|
initialViewStartDate,
|
|
initialViewEndDate,
|
|
calendarViewDirection,
|
|
initialShopTimeSlotsResponse: response,
|
|
preSelectedDate,
|
|
initialDaysLoaded: endDateObject.newDaysLoaded || initialDays,
|
|
daysFromStart: endDateObject.daysFromStart || null
|
|
}));
|
|
|
|
this.pushInshopFirstDateEvent(inShopData);
|
|
this.inShopDatesData = inShopData;
|
|
}
|
|
} else {
|
|
this.pushInshopFirstDateEvent(initialData);
|
|
this.inShopDatesData = initialData;
|
|
this.mobileDatesData = [];
|
|
}
|
|
|
|
return initialData;
|
|
},
|
|
getEndDateForExistingDate(startDate, selectedDateString, daysInView) {
|
|
const endDate = new Date(startDate);
|
|
endDate.setDate(endDate.getDate() + (daysInView - 1));
|
|
|
|
if (selectedDateString) {
|
|
const selectedDate = new Date(`${selectedDateString}T00:00:00`);
|
|
const daysDifferenceComparedToStartDate = Math.ceil((selectedDate - startDate) / (1000 * 60 * 60 * 24));
|
|
if (selectedDate > endDate) {
|
|
const daysDifferenceComparedToStartDateAsPages = Math.ceil(daysDifferenceComparedToStartDate / daysInView);
|
|
const newEndDate = new Date(startDate);
|
|
newEndDate.setDate(newEndDate.getDate() + (daysDifferenceComparedToStartDateAsPages * daysInView) - 1);
|
|
|
|
return {
|
|
endDateString: convertDateToDateString(newEndDate),
|
|
newDaysLoaded: (daysDifferenceComparedToStartDateAsPages * daysInView),
|
|
daysFromStart: daysDifferenceComparedToStartDate
|
|
};
|
|
}
|
|
|
|
return {
|
|
endDateString: convertDateToDateString(endDate),
|
|
newDaysLoaded: null,
|
|
daysFromStart: daysDifferenceComparedToStartDate
|
|
};
|
|
}
|
|
|
|
return {
|
|
endDateString: convertDateToDateString(endDate),
|
|
newDaysLoaded: null,
|
|
daysFromStart: null
|
|
};
|
|
},
|
|
getServiceZipCtuCodeFromStore() {
|
|
return this.mainStore.order.serviceLocation.zipCodeCtu;
|
|
},
|
|
getSelectedDate() {
|
|
return this.mainStore.order.schedule.date;
|
|
},
|
|
getSelectedProvider() {
|
|
return this.mainStore.order.serviceLocation.provider;
|
|
},
|
|
getSelectedTimeSlotInfo() {
|
|
const isPremiumAppointment =
|
|
!!(
|
|
this.supportingItems?.filter((lineItem) =>
|
|
lineItem.partType === PREMIUM_FEE_PART_TYPE) ?? []
|
|
).length > 0;
|
|
|
|
const selectedTimeSlotInfo = {
|
|
timeSlot: this.mainStore.order.schedule,
|
|
isPremiumAppointment
|
|
};
|
|
|
|
return selectedTimeSlotInfo;
|
|
},
|
|
getServiceLocation() {
|
|
return this.mainStore.order.serviceLocation;
|
|
},
|
|
getServiceLocationCity() {
|
|
return this.mainStore.order.serviceLocation?.city;
|
|
},
|
|
handleMqlChange(e) {
|
|
this.isMobileView = !e.matches;
|
|
},
|
|
inShopZipUpdatedFromServiceLocation(inShopZipServiceLocation) {
|
|
if (inShopZipServiceLocation) {
|
|
this.mobileProviderNumber = null;
|
|
this.selectedMobileZipCode = null;
|
|
this.selectedServiceLocation = inShopZipServiceLocation;
|
|
}
|
|
},
|
|
mobileZipUpdatedFromServiceLocation(mobileZipServiceLocation) {
|
|
if (mobileZipServiceLocation) {
|
|
this.mobileProviderNumber = mobileZipServiceLocation.mobileProviderNumber;
|
|
this.selectedMobileZipCode = mobileZipServiceLocation.zipCode;
|
|
this.selectedServiceLocation = mobileZipServiceLocation;
|
|
|
|
if (mobileZipServiceLocation.refreshDatePicker) {
|
|
this.refreshDatePicker();
|
|
}
|
|
}
|
|
},
|
|
async providerChangedFromServiceLocation(newProvider) {
|
|
this.selectedProvider = newProvider?.provider;
|
|
if (newProvider?.refreshDatePicker && newProvider.provider) {
|
|
this.mainStore.updateServiceLocationProvider(newProvider.provider);
|
|
|
|
showIssLoadingModal(true);
|
|
await this.mainStore.getBillToInfo(newProvider.provider?.providerNumber)
|
|
.then(() => {
|
|
this.refreshDatePicker();
|
|
})
|
|
.catch(() => {
|
|
// Error fetching billTo info, close loading modal
|
|
showIssLoadingModal(false);
|
|
});
|
|
}
|
|
},
|
|
pushInshopFirstDateEvent(inshopData) {
|
|
let dateDiffString = '';
|
|
if (inshopData?.initialShopTimeSlotsResponse?.days?.length > 0) {
|
|
const todayDateString = convertDateToDateString(new Date());
|
|
dateDiffString = calcDaysBetweenDates(todayDateString, inshopData.initialShopTimeSlotsResponse.days[0].date).toString();
|
|
}
|
|
this.pushEventToGA('appointment', 'availability_inshop', `days_out_${dateDiffString}`, true, null, null);
|
|
},
|
|
pushMobileFirstDateEvent(mobileData) {
|
|
let dateDiffString = '';
|
|
if (mobileData?.initialShopTimeSlotsResponse?.days?.length > 0) {
|
|
const todayDateString = convertDateToDateString(new Date());
|
|
dateDiffString = calcDaysBetweenDates(todayDateString, mobileData.initialShopTimeSlotsResponse.days[0].date).toString();
|
|
}
|
|
this.pushEventToGA('appointment', 'availability_mobile', `days_out_${dateDiffString}`, true, null, null);
|
|
},
|
|
pushServiceTypeEvent() {
|
|
if (this.selectedAppointmentType) {
|
|
this.pushEventToGA('appointment', 'service_type', this.selectedAppointmentType.toLowerCase(), true, null, null);
|
|
}
|
|
},
|
|
async refreshDatePicker() {
|
|
this.resetLocalFlags();
|
|
this.isDatePickerRefreshing = true;
|
|
await this.getDatePickerInitialData().then((data) => {
|
|
this.selectableDatesData = data.initialShopTimeSlotsResponse;
|
|
this.$refs.datePicker.initializeComponent(data);
|
|
this.isDatePickerRefreshing = false;
|
|
showIssLoadingModal(false);
|
|
});
|
|
},
|
|
resetLocalFlags() {
|
|
this.selectedDate = null;
|
|
this.selectedTimeSlotInfo = null;
|
|
this.showDatePickerError = false;
|
|
},
|
|
timeSlotSelectedFromPicker(timeSlot) {
|
|
this.selectedTimeSlotInfo = timeSlot;
|
|
this.showDatePickerError = false;
|
|
},
|
|
async forwardButtonAction() {
|
|
if (this.displayRecalAckModal && this.isRecalAcknowledged === false) {
|
|
showIssLoadingModal(false);
|
|
this.$refs[RECAL_ACK_MODAL_REF_NAME].openModal();
|
|
return;
|
|
}
|
|
|
|
if (!this.isFormValid) {
|
|
this.showDatePickerError = true;
|
|
return;
|
|
}
|
|
|
|
let appointmentTypeToUse = this.selectedAppointmentType;
|
|
if (appointmentTypeToUse === AppointmentTypeStrings.IN_SHOP && this.selectedTimeSlotInfo.timeSlot?.isDropoff === true) {
|
|
appointmentTypeToUse = AppointmentTypeStrings.DROP_OFF;
|
|
}
|
|
|
|
await this.$refs.serviceLocation.forwardButtonAction(appointmentTypeToUse);
|
|
this.pushServiceTypeEvent();
|
|
this.mainStore.saveSchedule(this.selectedTimeSlotInfo.timeSlot);
|
|
this.$router.navigate(
|
|
this.navigationScenarios.CLICKED_FORWARD,
|
|
this.$route
|
|
);
|
|
},
|
|
updateIsRecalAcknowledged(isAcknowledged) {
|
|
this.isRecalAcknowledged = isAcknowledged;
|
|
this.mainStore.order.isRecalAcknowledgedForScheduling = isAcknowledged;
|
|
},
|
|
getIsRecalAcknowledgedForScheduling() {
|
|
return this.mainStore.order.isRecalAcknowledgedForScheduling;
|
|
},
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
$page-side-padding: 1.5rem;
|
|
|
|
.iss-heritage-container-width {
|
|
padding-right: 0.9375rem;
|
|
padding-left: 0.9375rem;
|
|
|
|
.schedule-page-container {
|
|
position: relative;
|
|
min-height: 1px;
|
|
}
|
|
}
|
|
|
|
:deep(.text-link-small) {
|
|
a,
|
|
.btn-link {
|
|
font-size: 0.875rem;
|
|
line-height: 1.5;
|
|
}
|
|
}
|
|
|
|
:deep(.change-shop-link) {
|
|
a {
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
|
|
:deep(.subheader-primary) {
|
|
h5.dark-header {
|
|
margin-bottom: 0.25rem !important;
|
|
}
|
|
}
|
|
</style>
|