initial check in
This commit is contained in:
parent
0afc36f802
commit
f06332c066
18 changed files with 622 additions and 587 deletions
|
|
@ -50,9 +50,6 @@ export const pageProgressMapper = {
|
||||||
'provider-preference': {
|
'provider-preference': {
|
||||||
percent: 60
|
percent: 60
|
||||||
},
|
},
|
||||||
'service-location': {
|
|
||||||
percent: 65
|
|
||||||
},
|
|
||||||
'schedule-page': {
|
'schedule-page': {
|
||||||
percent: 70
|
percent: 70
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,10 @@ export default {
|
||||||
},
|
},
|
||||||
default: selectableDaysOptions.PAST
|
default: selectableDaysOptions.PAST
|
||||||
},
|
},
|
||||||
|
isMobileView: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Object
|
type: Object
|
||||||
},
|
},
|
||||||
|
|
@ -241,8 +245,7 @@ export default {
|
||||||
daysLoaded: 0,
|
daysLoaded: 0,
|
||||||
appointmentDurationMinutesMinimum: 90,
|
appointmentDurationMinutesMinimum: 90,
|
||||||
appointmentDurationMinutesMaximum: 120,
|
appointmentDurationMinutesMaximum: 120,
|
||||||
initialDaysToLoad: 15,
|
initialDaysToLoad: 15
|
||||||
isMobileView: false
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -284,6 +287,16 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
isMobileView(newValue, oldValue) {
|
||||||
|
if (newValue !== oldValue) {
|
||||||
|
this.activePageIndex = 0;
|
||||||
|
this.selectedDate = null;
|
||||||
|
this.selectedTimeOfDayGrouping = null;
|
||||||
|
this.selectedTime = null;
|
||||||
|
this.selectedTimeSlot = null;
|
||||||
|
this.findFirstAvailableDateInView();
|
||||||
|
}
|
||||||
|
},
|
||||||
selectedTimeSlot(newValue, oldValue) {
|
selectedTimeSlot(newValue, oldValue) {
|
||||||
if (newValue !== oldValue) {
|
if (newValue !== oldValue) {
|
||||||
const testObj = this.getSelectedTimeSlotInfoObject(newValue);
|
const testObj = this.getSelectedTimeSlotInfoObject(newValue);
|
||||||
|
|
@ -296,20 +309,30 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
this.mql = window.matchMedia('(min-width: 1200px)');
|
|
||||||
this.isMobileView = !this.mql.matches;
|
|
||||||
this.mql.addEventListener('change', this.handleMqlChange);
|
|
||||||
},
|
|
||||||
unmounted() {
|
|
||||||
if (this.mql) {
|
|
||||||
this.mql.removeEventListener('change', this.handleMqlChange);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
initializeComponent(initialData) {
|
initializeComponent(initialData) {
|
||||||
|
this.resetComponent();
|
||||||
this.setCalendarData(initialData);
|
this.setCalendarData(initialData);
|
||||||
},
|
},
|
||||||
|
resetComponent() {
|
||||||
|
this.isLoading = true;
|
||||||
|
this.selectableDatesData = []; // NOTE: uses monthNum (1-based), NOT monthIndex (0-based)
|
||||||
|
this.selectableTimeSlotsData = [];
|
||||||
|
this.selectedTimeOfDayGrouping = null;
|
||||||
|
this.selectedDate = null;
|
||||||
|
this.selectedTime = null;
|
||||||
|
this.selectedTimeSlot = null;
|
||||||
|
this.activeDate = new Date();
|
||||||
|
this.activePageIndex = 0;
|
||||||
|
this.todaysDate = new Date();
|
||||||
|
this.mql = null;
|
||||||
|
this.daysInViewMobile = 3;
|
||||||
|
this.daysInViewStandard = 5;
|
||||||
|
this.daysLoaded = 0;
|
||||||
|
this.appointmentDurationMinutesMinimum = 90;
|
||||||
|
this.appointmentDurationMinutesMaximum = 120;
|
||||||
|
this.initialDaysToLoad = 15;
|
||||||
|
},
|
||||||
addPremiumFlagToInput(routeCode) {
|
addPremiumFlagToInput(routeCode) {
|
||||||
return (`${routeCode}${PREMIUM_TIME_SLOT_ID_FLAG}`);
|
return (`${routeCode}${PREMIUM_TIME_SLOT_ID_FLAG}`);
|
||||||
},
|
},
|
||||||
|
|
@ -352,15 +375,6 @@ export default {
|
||||||
isPremiumAppointment: null
|
isPremiumAppointment: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
handleMqlChange(e) {
|
|
||||||
this.isMobileView = !e.matches;
|
|
||||||
this.activePageIndex = 0;
|
|
||||||
this.selectedDate = null;
|
|
||||||
this.selectedTimeOfDayGrouping = null;
|
|
||||||
this.selectedTime = null;
|
|
||||||
this.selectedTimeSlot = null;
|
|
||||||
this.findFirstAvailableDateInView();
|
|
||||||
},
|
|
||||||
displayTimeSlotTime(timeSlot) {
|
displayTimeSlotTime(timeSlot) {
|
||||||
const { appointmentType } = this.mainStore.order.serviceLocation;
|
const { appointmentType } = this.mainStore.order.serviceLocation;
|
||||||
if (appointmentType === AppointmentTypeStrings.MOBILE || appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
|
if (appointmentType === AppointmentTypeStrings.MOBILE || appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
|
||||||
|
|
@ -434,38 +448,6 @@ export default {
|
||||||
const dateToShow = this.getDateToShow(index);
|
const dateToShow = this.getDateToShow(index);
|
||||||
return convertDateToDateString(dateToShow);
|
return convertDateToDateString(dateToShow);
|
||||||
},
|
},
|
||||||
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
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async gotoNextPage() {
|
async gotoNextPage() {
|
||||||
const maxPageIndex = Math.floor((this.daysLoaded - 1) / this.daysToAdd);
|
const maxPageIndex = Math.floor((this.daysLoaded - 1) / this.daysToAdd);
|
||||||
if (this.activePageIndex >= maxPageIndex) {
|
if (this.activePageIndex >= maxPageIndex) {
|
||||||
|
|
@ -572,66 +554,9 @@ export default {
|
||||||
timeSlotInputChanged(timeSlot) {
|
timeSlotInputChanged(timeSlot) {
|
||||||
this.selectTimeSlotForDay(timeSlot);
|
this.selectTimeSlotForDay(timeSlot);
|
||||||
},
|
},
|
||||||
async loadInitialData(config) {
|
|
||||||
/*
|
|
||||||
** NOTE: this _could_ be called by a parent before fully loaded, so data or computeds might not be available
|
|
||||||
*/
|
|
||||||
let todayDateString;
|
|
||||||
const todayDateObject = new Date();
|
|
||||||
const calendarViewDirection = 'future';
|
|
||||||
const initialDays = 15;
|
|
||||||
|
|
||||||
if (this.todayString) {
|
|
||||||
todayDateString = this.todayString;
|
|
||||||
} else if (config.todayOverrideDateString) {
|
|
||||||
todayDateString = config.todayOverrideDateString;
|
|
||||||
} else {
|
|
||||||
todayDateString = convertDateToDateString(todayDateObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialViewStartDate = todayDateString;
|
|
||||||
const initialEndDate = new Date();
|
|
||||||
initialEndDate.setDate(initialEndDate.getDate() + (initialDays - 1));
|
|
||||||
let initialViewEndDate = convertDateToDateString(initialEndDate);
|
|
||||||
|
|
||||||
const endDateObject = this.getEndDateForExistingDate(
|
|
||||||
todayDateObject,
|
|
||||||
config.preSelectedDate,
|
|
||||||
initialDays
|
|
||||||
);
|
|
||||||
|
|
||||||
if (endDateObject.endDateString !== initialViewEndDate) {
|
|
||||||
initialViewEndDate = endDateObject.endDateString;
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadInitialDataPromise = new Promise((resolve) => {
|
|
||||||
const response = config.customSelectableDatesCallback(
|
|
||||||
initialViewStartDate,
|
|
||||||
initialViewEndDate,
|
|
||||||
useMainStore().order.serviceLocation.appointmentType,
|
|
||||||
useMainStore().order.serviceLocation.provider.providerNumber
|
|
||||||
);
|
|
||||||
resolve(response);
|
|
||||||
});
|
|
||||||
|
|
||||||
return loadInitialDataPromise.then((response) => {
|
|
||||||
const initialData = {
|
|
||||||
todayDate: todayDateString,
|
|
||||||
initialViewStartDate,
|
|
||||||
initialViewEndDate,
|
|
||||||
calendarViewDirection,
|
|
||||||
initialShopTimeSlotsResponse: response,
|
|
||||||
preSelectedDate: config.preSelectedDate,
|
|
||||||
initialDaysLoaded: endDateObject.newDaysLoaded || initialDays,
|
|
||||||
daysFromStart: endDateObject.daysFromStart || null
|
|
||||||
};
|
|
||||||
|
|
||||||
return initialData;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async setCalendarData(config = {}) {
|
async setCalendarData(config = {}) {
|
||||||
const initialMql = window.matchMedia('(min-width: 1200px)');
|
// const initialMql = window.matchMedia('(min-width: 1200px)');
|
||||||
this.isMobileView = !initialMql.matches;
|
// this.isMobileView = !initialMql.matches;
|
||||||
config.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
|
config.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
|
||||||
const dateObjectToPush = {
|
const dateObjectToPush = {
|
||||||
date: selectableDate.date,
|
date: selectableDate.date,
|
||||||
|
|
@ -899,7 +824,7 @@ export default {
|
||||||
border-radius: $border-radius-list-button;
|
border-radius: $border-radius-list-button;
|
||||||
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, .2);
|
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, .2);
|
||||||
color: #525656;
|
color: #525656;
|
||||||
padding: 0.5rem 0;
|
padding: 0.625rem 0;
|
||||||
margin-top: 0.625rem;
|
margin-top: 0.625rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
||||||
|
|
@ -306,6 +306,7 @@ function mapStringToState(str) {
|
||||||
const valueFromStore = getStoreValueFromString(match[2]);
|
const valueFromStore = getStoreValueFromString(match[2]);
|
||||||
if (!valueFromStore) {
|
if (!valueFromStore) {
|
||||||
console.warn('Unable to resolve global state data.');
|
console.warn('Unable to resolve global state data.');
|
||||||
|
console.warn(`Tried to resolve: ${match[2]}`);
|
||||||
return ''; // if we can't map our string to state data, return an empty string.
|
return ''; // if we can't map our string to state data, return an empty string.
|
||||||
}
|
}
|
||||||
const stringWithReplacement = str.replace(match[0], valueFromStore);
|
const stringWithReplacement = str.replace(match[0], valueFromStore);
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,16 @@ export async function getAvailabilityRating(
|
||||||
providerNumber
|
providerNumber
|
||||||
) {
|
) {
|
||||||
// For a given shop provider number and date range, get the appointment time slots available
|
// For a given shop provider number and date range, get the appointment time slots available
|
||||||
|
console.log('Getting shop time slots for availability rating...');
|
||||||
|
console.log(`Provider Number: ${providerNumber}`);
|
||||||
|
console.log(`Start Date: ${startDate}`);
|
||||||
|
console.log(`End Date: ${endDate}`);
|
||||||
|
console.log(`Shop Appointment Type: ${shopAppointmentType}`);
|
||||||
const shopTimeSlots = await useMainStore().getShopTimeSlots(startDate, endDate, shopAppointmentType, providerNumber);
|
const shopTimeSlots = await useMainStore().getShopTimeSlots(startDate, endDate, shopAppointmentType, providerNumber);
|
||||||
|
|
||||||
const numberOfDaysToEvaluate = 2;
|
const numberOfDaysToEvaluate = 2;
|
||||||
const isGoodAvailability =
|
const isGoodAvailability =
|
||||||
shopTimeSlots.data.days.filter((x) => x.timeSlots.length > 0).length
|
shopTimeSlots.data.days.filter((x) => x.timeSlots.length > 6).length
|
||||||
>= numberOfDaysToEvaluate;
|
>= numberOfDaysToEvaluate;
|
||||||
|
|
||||||
const shopStatus = isGoodAvailability ? 'high' : 'low';
|
const shopStatus = isGoodAvailability ? 'high' : 'low';
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,19 @@
|
||||||
cmsWidgetName="ScheduleSubHeaderWidget"
|
cmsWidgetName="ScheduleSubHeaderWidget"
|
||||||
secondaryTextClasses="text-center small sub-text"
|
secondaryTextClasses="text-center small sub-text"
|
||||||
class="mt-4" />
|
class="mt-4" />
|
||||||
<div class="main-content-container">
|
<div class="service-location-content-container">
|
||||||
|
<serviceLocation
|
||||||
|
ref="serviceLocation"
|
||||||
|
@appointmentTypeChanged="appointmentTypeChangedFromServiceLocation"
|
||||||
|
@mobileZipUpdated="mobileZipUpdatedFromChild"
|
||||||
|
@providerChanged="providerChangedFromChild"
|
||||||
|
@serviceLocationUpdated="serviceLocationUpdatedFromChild" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-show="hasNeededServiceLocationData"
|
||||||
|
class="date-picker-container iss-heritage-content-container-width">
|
||||||
|
<div class="date-picker-content-container">
|
||||||
<locationAlerts
|
<locationAlerts
|
||||||
ref="locationAlerts"
|
ref="locationAlerts"
|
||||||
cmsWidgetPrefix="LocationAlert-" />
|
cmsWidgetPrefix="LocationAlert-" />
|
||||||
|
|
@ -25,21 +37,23 @@
|
||||||
customComponentId="dateQuestion"
|
customComponentId="dateQuestion"
|
||||||
selectableDatesSetting="custom"
|
selectableDatesSetting="custom"
|
||||||
class="text-link-small"
|
class="text-link-small"
|
||||||
|
:isMobileView="isMobileView"
|
||||||
:showTimeSlotError="showDatePickerError"
|
:showTimeSlotError="showDatePickerError"
|
||||||
:customSelectableDatesCallback="
|
:customSelectableDatesCallback="getAvailableDatesMethod"
|
||||||
getAvailableDatesMethod
|
|
||||||
"
|
|
||||||
@dateSelected="dateSelectedFromPicker"
|
@dateSelected="dateSelectedFromPicker"
|
||||||
@timeSlotSelected="timeSlotSelectedFromPicker" />
|
@timeSlotSelected="timeSlotSelectedFromPicker" />
|
||||||
<siteFooter
|
|
||||||
ref="navbar"
|
|
||||||
class="mt-5"
|
|
||||||
cmsWidgetName="SiteFooterWidget"
|
|
||||||
:isForwardButtonNavigationDisabled="!isFormValid"
|
|
||||||
@backClicked="navigateBack"
|
|
||||||
@forwardClicked="forwardButtonAction" />
|
|
||||||
</div>
|
</div>
|
||||||
</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"
|
||||||
|
@forwardClicked="forwardButtonAction" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
@ -50,6 +64,7 @@ import siteHeader from '@/iss-components/site-header/site-header.vue';
|
||||||
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-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 locationAlerts from '@/layouts/schedule-page/location-alerts/location-alerts.vue';
|
||||||
import datePicker from '@/digital-components/date-picker/date-picker.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 siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||||
|
|
||||||
// Supporting files
|
// Supporting files
|
||||||
|
|
@ -65,9 +80,22 @@ import {
|
||||||
} from '@/helpers/cms-content-helper';
|
} from '@/helpers/cms-content-helper';
|
||||||
import {
|
import {
|
||||||
calcDaysBetweenDates,
|
calcDaysBetweenDates,
|
||||||
|
convertDateToDateString,
|
||||||
|
// convertDateToShortMonth,
|
||||||
|
// convertDateToTwoDigitDay,
|
||||||
|
// convertDateToTwoDigitMonth,
|
||||||
|
// getDisplayTextForDurationLength,
|
||||||
|
// isAfternoon,
|
||||||
|
// militaryToTwelveHourTime,
|
||||||
sumDateString
|
sumDateString
|
||||||
} from '@/helpers/date-helper';
|
} from '@/helpers/date-helper';
|
||||||
import settleAllPromises from '@/helpers/layout-helper';
|
import settleAllPromises from '@/helpers/layout-helper';
|
||||||
|
import {
|
||||||
|
getPricedMobileFeePart,
|
||||||
|
getServiceabilityDetails,
|
||||||
|
getZipCodeData,
|
||||||
|
getMobileZipCodeData
|
||||||
|
} from '@/helpers/service-location-helper';
|
||||||
import { Form } from 'vee-validate';
|
import { Form } from 'vee-validate';
|
||||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
|
|
@ -182,6 +210,7 @@ export default {
|
||||||
siteSubHeader,
|
siteSubHeader,
|
||||||
locationAlerts,
|
locationAlerts,
|
||||||
datePicker,
|
datePicker,
|
||||||
|
serviceLocation,
|
||||||
siteFooter,
|
siteFooter,
|
||||||
// eslint-disable-next-line vue/no-reserved-component-names
|
// eslint-disable-next-line vue/no-reserved-component-names
|
||||||
Form
|
Form
|
||||||
|
|
@ -195,17 +224,14 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||||
|
const serviceZipCode = useMainStore().order.serviceLocation.zipCode || useMainStore().order.customer.address.zipCode;
|
||||||
const datePickerInitialDataPromise =
|
const zipCodeData = getZipCodeData(serviceZipCode);
|
||||||
await datePicker.methods.loadInitialData({
|
const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode);
|
||||||
selectableDatesSetting: 'custom',
|
const serviceabilityDetailsPromise = getServiceabilityDetails(serviceZipCode);
|
||||||
initialViewRowsToShow: 5,
|
const getGlassFeesPromise = useMainStore().getGlassFees();
|
||||||
customSelectableDatesCallback: getAvailableDates,
|
const providersPromise = useMainStore().getProviders(serviceZipCode);
|
||||||
preSelectedDate
|
|
||||||
});
|
|
||||||
|
|
||||||
const premiumFeePromise = useMainStore().getMobilePremiumFee();
|
const premiumFeePromise = useMainStore().getMobilePremiumFee();
|
||||||
|
|
||||||
const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
|
const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
|
||||||
if (result.data) {
|
if (result.data) {
|
||||||
return useMainStore().getCombinedQuote(result.data);
|
return useMainStore().getCombinedQuote(result.data);
|
||||||
|
|
@ -213,24 +239,35 @@ export default {
|
||||||
return result.data;
|
return result.data;
|
||||||
});
|
});
|
||||||
|
|
||||||
const alertReasonsPromise = locationAlerts.methods.loadInitialData(
|
|
||||||
useMainStore().order.serviceLocation.zipCodeCtu,
|
|
||||||
useMainStore().order.serviceLocation.provider?.address?.zipCodeCtu
|
|
||||||
);
|
|
||||||
|
|
||||||
// Settle promises and get results
|
// Settle promises and get results
|
||||||
const promiseResultMap = [
|
const promiseResultMap = [
|
||||||
{
|
{
|
||||||
resultKey: 'cmsContent',
|
resultKey: 'cmsContent',
|
||||||
promise: cmsContentPromise
|
promise: cmsContentPromise
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// resultKey: 'datePickerInitialData',
|
||||||
|
// promise: datePickerInitialDataPromise
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
resultKey: 'alertReasons',
|
resultKey: 'mobileFeePart',
|
||||||
promise: alertReasonsPromise
|
promise: mobileFeePartPromise
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resultKey: 'datePickerInitialData',
|
resultKey: 'glassFees',
|
||||||
promise: datePickerInitialDataPromise
|
promise: getGlassFeesPromise
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: 'serviceabilityDetails',
|
||||||
|
promise: serviceabilityDetailsPromise
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: 'zipCodeData',
|
||||||
|
promise: zipCodeData
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: 'providers',
|
||||||
|
promise: providersPromise
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resultKey: 'premiumFeeWithPrice',
|
resultKey: 'premiumFeeWithPrice',
|
||||||
|
|
@ -240,14 +277,26 @@ export default {
|
||||||
|
|
||||||
// use resultMap to populate layout content.
|
// use resultMap to populate layout content.
|
||||||
const resultMap = await settleAllPromises(promiseResultMap);
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
next((vm) => {
|
const serviceLocationData = {
|
||||||
|
glassFees: resultMap.glassFees,
|
||||||
|
mobileFeePart: resultMap.mobileFeePart,
|
||||||
|
providers: resultMap.providers,
|
||||||
|
serviceabilityDetails: resultMap.serviceabilityDetails,
|
||||||
|
zipCodeData: resultMap.zipCodeData
|
||||||
|
};
|
||||||
|
useMainStore().updateIsSafeliteProvider(true);
|
||||||
|
next(async (vm) => {
|
||||||
|
const initialServiceLocationObj = {
|
||||||
|
provider: resultMap.providers?.shopProviders[0],
|
||||||
|
zipCode: useMainStore().order.serviceLocation.zipCode || useMainStore().order.customer.address.zipCode,
|
||||||
|
zipCodeCtu: resultMap.zipCodeData?.zipCodeCtu
|
||||||
|
};
|
||||||
|
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
|
// vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
|
||||||
vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
|
// vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
|
||||||
vm.setData(
|
vm.$refs.serviceLocation.initializeComponent(serviceLocationData);
|
||||||
resultMap.datePickerInitialData.initialShopTimeSlotsResponse,
|
await vm.setData(resultMap.premiumFeeWithPrice, initialServiceLocationObj);
|
||||||
resultMap.premiumFeeWithPrice
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
|
|
@ -256,23 +305,51 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedDate: this.getSelectedDate(),
|
isMobileView: false,
|
||||||
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
|
mobilePremiumAppointmentFee: null,
|
||||||
selectableDatesData: [],
|
selectableDatesData: [],
|
||||||
showDatePickerError: false,
|
selectedAppointmentType: this.getAppointmentType(),
|
||||||
mobilePremiumAppointmentFee: null
|
selectedDate: this.getSelectedDate(),
|
||||||
|
selectedProvider: this.getSelectedProvider(),
|
||||||
|
selectedServiceLocation: this.getServiceLocation(),
|
||||||
|
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
|
||||||
|
showDatePickerError: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
ChangeShopLinkText() {
|
|
||||||
return this.getCmsContent('ChangeShopLink', 'Text');
|
|
||||||
},
|
|
||||||
ChangeShopLink() {
|
|
||||||
return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
|
|
||||||
},
|
|
||||||
appointmentType() {
|
appointmentType() {
|
||||||
return useMainStore().order.serviceLocation.appointmentType;
|
return useMainStore().order.serviceLocation.appointmentType;
|
||||||
},
|
},
|
||||||
|
daysToAdd() {
|
||||||
|
return this.isMobileView ? this.daysInViewMobile : this.daysInViewStandard;
|
||||||
|
},
|
||||||
|
hasNeededServiceLocationData() {
|
||||||
|
const serviceLocationToUse = this.selectedServiceLocation;
|
||||||
|
if (!serviceLocationToUse || !this.selectedAppointmentType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const serviceLocationPreReqs = serviceLocationToUse.zipCode !== null
|
||||||
|
&& serviceLocationToUse.zipCodeCtu !== null
|
||||||
|
&& serviceLocationToUse.appointmentType !== null
|
||||||
|
&& (serviceLocationToUse.appointmentType === AppointmentTypeStrings.MOBILE
|
||||||
|
|| serviceLocationToUse.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
|
||||||
|
|| serviceLocationToUse.provider.providerNumber);
|
||||||
|
|
||||||
|
const damageInfo = useMainStore().order.damage.isRepair
|
||||||
|
|| (useMainStore().order.lineItems?.glassParts != null && useMainStore().order.lineItems.glassParts.length > 0);
|
||||||
|
|
||||||
|
const supportingItems = this.supportingItems !== null;
|
||||||
|
|
||||||
|
console.log('Has Needed Service Location Data Check:', {
|
||||||
|
serviceLocationPreReqs,
|
||||||
|
supportingItems,
|
||||||
|
damageInfo
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Result:', (serviceLocationPreReqs && supportingItems && damageInfo));
|
||||||
|
|
||||||
|
return (serviceLocationPreReqs && supportingItems && damageInfo);
|
||||||
|
},
|
||||||
isFormValid() {
|
isFormValid() {
|
||||||
const hasTimeSlotSelected = this.selectedTimeSlotInfo?.timeSlot?.routeCode != null;
|
const hasTimeSlotSelected = this.selectedTimeSlotInfo?.timeSlot?.routeCode != null;
|
||||||
return hasTimeSlotSelected;
|
return hasTimeSlotSelected;
|
||||||
|
|
@ -281,34 +358,50 @@ export default {
|
||||||
return useMainStore().lineItems.supportingItems;
|
return useMainStore().lineItems.supportingItems;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.mql = window.matchMedia('(min-width: 1200px)');
|
||||||
|
this.isMobileView = !this.mql.matches;
|
||||||
|
this.mql.addEventListener('change', this.handleMqlChange);
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
if (this.mql) {
|
||||||
|
this.mql.removeEventListener('change', this.handleMqlChange);
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
splitCopyOnCMSPlaceHolder,
|
splitCopyOnCMSPlaceHolder,
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
const { serviceLocation } = useMainStore().order;
|
return useMainStore().order.serviceLocation.zipCode !== null;
|
||||||
const serviceLocationPreReqs =
|
|
||||||
serviceLocation.zipCode
|
|
||||||
&& serviceLocation.zipCodeCtu
|
|
||||||
&& serviceLocation.appointmentType
|
|
||||||
&& (serviceLocation.appointmentType
|
|
||||||
=== AppointmentTypeStrings.MOBILE
|
|
||||||
|| serviceLocation.appointmentType
|
|
||||||
=== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
|
|
||||||
|| serviceLocation.provider.providerNumber);
|
|
||||||
const supportingItems = this.supportingItems !== null;
|
|
||||||
const damageInfo =
|
|
||||||
useMainStore().order.damage.isRepair
|
|
||||||
|| (useMainStore().order.lineItems?.glassParts != null
|
|
||||||
&& useMainStore().order.lineItems.glassParts.length > 0);
|
|
||||||
|
|
||||||
return serviceLocationPreReqs && supportingItems && damageInfo;
|
|
||||||
},
|
},
|
||||||
setData(initialShopTimeSlotsResponse, premiumFeeWithPriceResponse) {
|
async setData(premiumFeeWithPriceResponse, initialServiceLocationObj) {
|
||||||
this.selectableDatesData = initialShopTimeSlotsResponse;
|
// this.selectableDatesData = initialShopTimeSlotsResponse;
|
||||||
this.mobilePremiumAppointmentFee = premiumFeeWithPriceResponse
|
this.mobilePremiumAppointmentFee = premiumFeeWithPriceResponse
|
||||||
? premiumFeeWithPriceResponse[0]
|
? premiumFeeWithPriceResponse[0]
|
||||||
: null;
|
: null;
|
||||||
|
this.selectedServiceLocation = initialServiceLocationObj;
|
||||||
|
|
||||||
|
if (this.selectedAppointmentType !== AppointmentTypeStrings.MOBILE
|
||||||
|
&& this.selectedAppointmentType !== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
|
||||||
|
const initialData = await this.getDatePickerInitialData(initialServiceLocationObj.provider?.providerNumber);
|
||||||
|
this.selectableDatesData = initialData.initialShopTimeSlotsResponse;
|
||||||
|
this.$refs.datePicker.setCalendarData(initialData);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
appointmentTypeChangedFromServiceLocation(newAppointmentType) {
|
||||||
|
console.log('Parent - Appointment Type Changed from Service Location:', newAppointmentType);
|
||||||
|
this.selectedAppointmentType = newAppointmentType;
|
||||||
|
this.shouldRefreshDatePicker();
|
||||||
|
},
|
||||||
|
dateSelectedFromPicker(date) {
|
||||||
|
this.selectedDate = date;
|
||||||
|
this.showDatePickerError = false;
|
||||||
|
},
|
||||||
|
getAppointmentType() {
|
||||||
|
return this.mainStore.order?.serviceLocation?.appointmentType;
|
||||||
},
|
},
|
||||||
async getAvailableDatesMethod(startDate, endDate) {
|
async getAvailableDatesMethod(startDate, endDate) {
|
||||||
|
console.log('Fetching Available Dates from Method...');
|
||||||
|
console.log('More Data concatenation called with Start Date:', startDate, 'End Date:', endDate);
|
||||||
const newShopTimeSlots = await getAvailableDates(
|
const newShopTimeSlots = await getAvailableDates(
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
|
|
@ -321,12 +414,103 @@ export default {
|
||||||
return newShopTimeSlots;
|
return newShopTimeSlots;
|
||||||
},
|
},
|
||||||
getAvailableDates,
|
getAvailableDates,
|
||||||
|
async getDatePickerInitialData(defaultProviderNumber = null) {
|
||||||
|
console.log('Fetching Date Picker Initial Data...');
|
||||||
|
console.log('defaultProviderNumber:', defaultProviderNumber);
|
||||||
|
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.mainStore.order.schedule.date;
|
||||||
|
|
||||||
|
const endDateObject = this.getEndDateForExistingDate(
|
||||||
|
todayDateObject,
|
||||||
|
preSelectedDate,
|
||||||
|
initialDays
|
||||||
|
);
|
||||||
|
|
||||||
|
if (endDateObject.endDateString !== initialViewEndDate) {
|
||||||
|
initialViewEndDate = endDateObject.endDateString;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialDataPickerDataPromise = new Promise((resolve) => {
|
||||||
|
const response = getAvailableDates(
|
||||||
|
initialViewStartDate,
|
||||||
|
initialViewEndDate,
|
||||||
|
this.selectedAppointmentType || AppointmentTypeStrings.IN_SHOP,
|
||||||
|
this.selectedProvider.providerNumber || defaultProviderNumber
|
||||||
|
);
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
const initialData = await initialDataPickerDataPromise.then((response) => ({
|
||||||
|
todayDate: todayDateString,
|
||||||
|
initialViewStartDate,
|
||||||
|
initialViewEndDate,
|
||||||
|
calendarViewDirection,
|
||||||
|
initialShopTimeSlotsResponse: response,
|
||||||
|
preSelectedDate,
|
||||||
|
initialDaysLoaded: endDateObject.newDaysLoaded || initialDays,
|
||||||
|
daysFromStart: endDateObject.daysFromStart || null
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log('Date Picker Initial Data:');
|
||||||
|
console.log(initialData);
|
||||||
|
|
||||||
|
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() {
|
getServiceZipCtuCodeFromStore() {
|
||||||
return this.mainStore.order.serviceLocation.zipCodeCtu;
|
return this.mainStore.order.serviceLocation.zipCodeCtu;
|
||||||
},
|
},
|
||||||
getSelectedDate() {
|
getSelectedDate() {
|
||||||
return this.mainStore.order.schedule.date;
|
return this.mainStore.order.schedule.date;
|
||||||
},
|
},
|
||||||
|
getSelectedProvider() {
|
||||||
|
return this.mainStore.order.serviceLocation.provider;
|
||||||
|
},
|
||||||
getSelectedTimeSlotInfo() {
|
getSelectedTimeSlotInfo() {
|
||||||
const isPremiumAppointment =
|
const isPremiumAppointment =
|
||||||
!!(
|
!!(
|
||||||
|
|
@ -341,9 +525,29 @@ export default {
|
||||||
|
|
||||||
return selectedTimeSlotInfo;
|
return selectedTimeSlotInfo;
|
||||||
},
|
},
|
||||||
dateSelectedFromPicker(date) {
|
getServiceLocation() {
|
||||||
this.selectedDate = date;
|
return this.mainStore.order.serviceLocation;
|
||||||
this.showDatePickerError = false;
|
},
|
||||||
|
handleMqlChange(e) {
|
||||||
|
this.isMobileView = !e.matches;
|
||||||
|
},
|
||||||
|
mobileZipUpdatedFromChild(newMobileZip) {
|
||||||
|
console.log('Parent - Mobile Zip Updated from Child:', newMobileZip);
|
||||||
|
},
|
||||||
|
providerChangedFromChild(newProvider) {
|
||||||
|
console.log('Parent - Provider Changed from Child:', newProvider);
|
||||||
|
this.selectedProvider = newProvider;
|
||||||
|
// this.shouldRefreshDatePicker();
|
||||||
|
},
|
||||||
|
serviceLocationUpdatedFromChild(serviceLocationFromChild) {
|
||||||
|
this.selectedServiceLocation = serviceLocationFromChild;
|
||||||
|
},
|
||||||
|
async shouldRefreshDatePicker() {
|
||||||
|
if (this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP && 1 === 2) {
|
||||||
|
const initialData = await this.getDatePickerInitialData();
|
||||||
|
this.selectableDatesData = initialData.initialShopTimeSlotsResponse;
|
||||||
|
this.$refs.datePicker.initializeComponent(initialData);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
timeSlotSelectedFromPicker(timeSlot) {
|
timeSlotSelectedFromPicker(timeSlot) {
|
||||||
this.selectedTimeSlotInfo = timeSlot;
|
this.selectedTimeSlotInfo = timeSlot;
|
||||||
|
|
@ -369,11 +573,12 @@ export default {
|
||||||
$page-side-padding: 1.5rem;
|
$page-side-padding: 1.5rem;
|
||||||
|
|
||||||
.iss-heritage-container-width {
|
.iss-heritage-container-width {
|
||||||
|
padding-right: 0.9375rem;
|
||||||
|
padding-left: 0.9375rem;
|
||||||
|
|
||||||
.schedule-page-container {
|
.schedule-page-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 1px;
|
min-height: 1px;
|
||||||
padding-left: .9375rem;
|
|
||||||
padding-right: .9375rem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useMainStore } from '@/store';
|
|
||||||
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
|
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
|
import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
|
||||||
import { experimentSettings } from '@/constants/experiments';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'appointment-type-question',
|
name: 'appointment-type-question',
|
||||||
|
|
@ -63,12 +61,17 @@ export default {
|
||||||
this.$emit('update:modelValue', newValue);
|
this.$emit('update:modelValue', newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.appointment-type-question {
|
.appointment-type-question {
|
||||||
margin-bottom: 1.25rem;
|
margin-top: .625rem;
|
||||||
|
|
||||||
|
:deep(.list-button-content) {
|
||||||
|
padding-top: .625rem;
|
||||||
|
padding-bottom: .625rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -79,8 +79,6 @@ import modal from '@/digital-components/modal/modal.vue';
|
||||||
import alert from '@/ux-components/alert/alert.vue';
|
import alert from '@/ux-components/alert/alert.vue';
|
||||||
import { useField } from 'vee-validate';
|
import { useField } from 'vee-validate';
|
||||||
import addressQuestions from '@/iss-components/address-questions/address-questions.vue';
|
import addressQuestions from '@/iss-components/address-questions/address-questions.vue';
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
import vehicleProtectedQuestion from '@/layouts/service-location/mobile-location-modal-questions/vehicle-protected-question/vehicle-protected-question.vue';
|
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import { experimentSettings } from '@/constants/experiments';
|
import { experimentSettings } from '@/constants/experiments';
|
||||||
|
|
@ -90,10 +88,11 @@ import { useMainStore } from '@/store';
|
||||||
import {
|
import {
|
||||||
getMobileZipCodeData,
|
getMobileZipCodeData,
|
||||||
getPricedMobileFeePart,
|
getPricedMobileFeePart,
|
||||||
getServiceabilityDetails,
|
getServiceabilityDetails
|
||||||
getZipCodeData
|
|
||||||
} from '@/helpers/service-location-helper';
|
} from '@/helpers/service-location-helper';
|
||||||
import { deepClone } from '@/helpers/object-helper.js';
|
import { deepClone } from '@/helpers/object-helper.js';
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
import vehicleProtectedQuestion from '@/layouts/schedule-page/service-location/mobile-location-modal-question/vehicle-protected-question/vehicle-protected-question.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'mobile-location-modal-questions',
|
name: 'mobile-location-modal-questions',
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
/* eslint-env jest */
|
/* eslint-env jest */
|
||||||
import baseMixin from '@/mixins/base-mixin';
|
import baseMixin from '@/mixins/base-mixin';
|
||||||
import { mount, flushPromises } from '@vue/test-utils';
|
import { mount } from '@vue/test-utils';
|
||||||
import { createTestingPinia } from '@pinia/testing';
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
||||||
import navigationScenarios from '@/router/router-constants/navigation-scenarios';
|
import navigationScenarios from '@/router/router-constants/navigation-scenarios';
|
||||||
import routerParams from '@/router/router-constants/router-params';
|
import routerParams from '@/router/router-constants/router-params';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
import serviceLocation from '@/layouts/service-location/service-location.vue';
|
import serviceLocation from '@/layouts/schedule-page/service-location/service-location.vue';
|
||||||
import { getZipCodeData } from '@/helpers/service-location-helper';
|
|
||||||
|
|
||||||
const mockGetServiceabilityDetails = () => {
|
const mockGetServiceabilityDetails = () => {
|
||||||
const serviceabilityDetails = {
|
const serviceabilityDetails = {
|
||||||
|
|
@ -50,43 +49,41 @@ const mockZipcodeData = (zip) => {
|
||||||
state: null,
|
state: null,
|
||||||
zipCodeCtu: null
|
zipCodeCtu: null
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
const mockProviders = () => {
|
const mockProviders = () => Promise.resolve([
|
||||||
return Promise.resolve([
|
{
|
||||||
{
|
address: {
|
||||||
"address": {
|
city: 'COLUMBUS',
|
||||||
"city": "COLUMBUS",
|
country: 'US',
|
||||||
"country": "US",
|
state: 'OH',
|
||||||
"state": "OH",
|
streetAddress: '6826 Sawmill Rd',
|
||||||
"streetAddress": "6826 Sawmill Rd",
|
streetAddress2: '',
|
||||||
"streetAddress2": "",
|
zipCode: '43235',
|
||||||
"zipCode": "43235",
|
zipCodeCtu: '03357'
|
||||||
"zipCodeCtu": "03357"
|
|
||||||
},
|
|
||||||
"distanceInMiles": 4.136335989015438,
|
|
||||||
"providerNumber": "003357",
|
|
||||||
"companyName": "SAFELITE AUTOGLASS - COLUMBUS, OH",
|
|
||||||
"phoneNumber": "6142336400",
|
|
||||||
"isSafeliteShop": true
|
|
||||||
},
|
},
|
||||||
{
|
distanceInMiles: 4.136335989015438,
|
||||||
"address": {
|
providerNumber: '003357',
|
||||||
"city": "Lewis Center",
|
companyName: 'SAFELITE AUTOGLASS - COLUMBUS, OH',
|
||||||
"country": "US",
|
phoneNumber: '6142336400',
|
||||||
"state": "OH",
|
isSafeliteShop: true
|
||||||
"streetAddress": "1343 Cameron Ave",
|
},
|
||||||
"streetAddress2": "",
|
{
|
||||||
"zipCode": "43035",
|
address: {
|
||||||
"zipCodeCtu": "03357"
|
city: 'Lewis Center',
|
||||||
},
|
country: 'US',
|
||||||
"distanceInMiles": 8.193072412262042,
|
state: 'OH',
|
||||||
"providerNumber": "003417",
|
streetAddress: '1343 Cameron Ave',
|
||||||
"companyName": "SAFELITE AUTOGLASS - LEWIS CENTER, OH",
|
streetAddress2: '',
|
||||||
"phoneNumber": "6147815433",
|
zipCode: '43035',
|
||||||
"isSafeliteShop": true
|
zipCodeCtu: '03357'
|
||||||
}
|
},
|
||||||
])
|
distanceInMiles: 8.193072412262042,
|
||||||
}
|
providerNumber: '003417',
|
||||||
|
companyName: 'SAFELITE AUTOGLASS - LEWIS CENTER, OH',
|
||||||
|
phoneNumber: '6147815433',
|
||||||
|
isSafeliteShop: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
jest.mock(
|
jest.mock(
|
||||||
'@/helpers/service-location-helper',
|
'@/helpers/service-location-helper',
|
||||||
() => ({
|
() => ({
|
||||||
|
|
@ -138,13 +135,13 @@ const mountOptions = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
function setupMocks({ appointmentType = AppointmentTypeStrings.IN_SHOP }) {
|
function setupMocks({ appointmentType = AppointmentTypeStrings.IN_SHOP }) {
|
||||||
mountOptions.global.plugins = [createTestingPinia({
|
mountOptions.global.plugins = [createTestingPinia({
|
||||||
initialState: {
|
initialState: {
|
||||||
main: {
|
main: {
|
||||||
order: {
|
order: {
|
||||||
serviceLocation: {
|
serviceLocation: {
|
||||||
appointmentType: appointmentType
|
appointmentType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +201,7 @@ describe('service-location.vue', () => {
|
||||||
|
|
||||||
expect(wrapper.vm.zipContainsMilitaryBase).toBe(false);
|
expect(wrapper.vm.zipContainsMilitaryBase).toBe(false);
|
||||||
|
|
||||||
const newMobileServiceZipCode = '45433'
|
const newMobileServiceZipCode = '45433';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
mobileServiceZipCodeQuestion.vm.$emit('update:modelValue', newMobileServiceZipCode);
|
mobileServiceZipCodeQuestion.vm.$emit('update:modelValue', newMobileServiceZipCode);
|
||||||
|
|
@ -1,166 +1,142 @@
|
||||||
<template>
|
<template>
|
||||||
<Form
|
<div class="service-location">
|
||||||
ref="theForm"
|
<alert
|
||||||
v-slot="{ meta }"
|
v-if="displayRecalibrationWarning"
|
||||||
@submit="onSubmit"
|
ref="alertRecalNoMobile"
|
||||||
@invalidSubmit="onInvalidSubmit">
|
cmsWidgetName="AlertRecalNoMobileWidget"
|
||||||
<div class="fade-on-route-transition">
|
alertClass="alert-warning"
|
||||||
<div class="justify-content-center">
|
@text-link-clicked="openModalAction" />
|
||||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
<alert
|
||||||
|
v-if="displayBigTruckNoShops"
|
||||||
|
ref="alertBigTruckNoShops"
|
||||||
|
cmsWidgetName="AlertBigTruckNoShopsWidget"
|
||||||
|
alertClass="alert-warning" />
|
||||||
|
<div style="display: none;">
|
||||||
|
isServiceableMobile: {{ isServiceableMobile }}<br />
|
||||||
|
isServiceableInshop: {{ isServiceableInshop }}<br />
|
||||||
|
requiresInshopRecalibration: {{ requiresInshopRecalibration }}<br />
|
||||||
|
selectedAppointmentType: {{ selectedAppointmentType }}<br />
|
||||||
|
</div>
|
||||||
|
<div class="appointment-type">
|
||||||
|
<div class="appointment-type-question-text d-flex">
|
||||||
|
<span
|
||||||
|
v-if="recalibrationRequired"
|
||||||
|
class="recal-text">{{ scheduleRecalText }}</span>
|
||||||
|
<span
|
||||||
|
v-if="!requiresInshopRecalibration">{{ appointmentQuestionText }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="iss-heritage-container-width">
|
<alert
|
||||||
<div class="service-location-container iss-heritage-content-container-width">
|
v-if="displayServiceableInshopOnly"
|
||||||
<siteSubHeader
|
ref="alertInshopOnly"
|
||||||
cmsWidgetName="SiteSubHeaderWidget"
|
cmsWidgetName="AlertInshopOnlyWidget"
|
||||||
class="subheader" />
|
:manualCopy="inShopOnlyCopy"
|
||||||
<alert
|
:isCollapsible="true"
|
||||||
v-if="displayRecalibrationWarning"
|
alertClass="alert-warning" />
|
||||||
ref="alertRecalNoMobile"
|
<alert
|
||||||
class="my-5"
|
v-if="displayServiceableMobileOnly"
|
||||||
cmsWidgetName="AlertRecalNoMobileWidget"
|
ref="alertMobileOnly"
|
||||||
alertClass="alert-warning"
|
cmsWidgetName="AlertMobileOnlyWidget"
|
||||||
@text-link-clicked="openModalAction" />
|
:manualCopy="mobileOnlyCopy"
|
||||||
<alert
|
:isCollapsible="true"
|
||||||
v-if="displayBigTruckNoShops"
|
alertClass="alert-warning" />
|
||||||
ref="alertBigTruckNoShops"
|
<appointmentTypeQuestion
|
||||||
class="my-5"
|
v-if="!requiresInshopRecalibration && isServiceableMobile"
|
||||||
cmsWidgetName="AlertBigTruckNoShopsWidget"
|
ref="appointmentTypeQuestion"
|
||||||
alertClass="alert-warning" />
|
v-model="selectedAppointmentType"
|
||||||
<div class="appointment-type">
|
groupName="appointmentTypeQuestion"
|
||||||
<div class="appointment-type-question-text d-flex">
|
cmsWidgetName="AppointmentTypeQuestionWidget"
|
||||||
<span class="w-100 recal-text" v-if="recalibrationRequired">{{ scheduleRecalText }}</span>
|
validationRules="option-required" />
|
||||||
<span class="w-100" v-if="!requiresInshopRecalibration">{{ appointmentQuestionText }}</span>
|
</div>
|
||||||
</div>
|
<div
|
||||||
<alert
|
v-if="isInshop">
|
||||||
v-if="displayServiceableInshopOnly"
|
<alert
|
||||||
ref="alertInshopOnly"
|
v-if="displayLowAvailabilityInshop"
|
||||||
cmsWidgetName="AlertInshopOnlyWidget"
|
ref="alertLowAvailabilityInshop"
|
||||||
:manualCopy="inShopOnlyCopy"
|
cmsWidgetName="AlertLowAvailabilityInshopWidget"
|
||||||
:isCollapsible="true"
|
:isCollapsible="true"
|
||||||
alertClass="alert-warning" />
|
alertClass="alert-warning" />
|
||||||
<alert
|
<shopAddress
|
||||||
v-if="displayServiceableMobileOnly"
|
ref="shopAddress"
|
||||||
ref="alertMobileOnly"
|
v-model="selectedProvider"
|
||||||
cmsWidgetName="AlertMobileOnlyWidget"
|
:serviceZipcode="zipCode"
|
||||||
:manualCopy="mobileOnlyCopy"
|
:selectedAppointmentType="selectedAppointmentType"
|
||||||
:isCollapsible="true"
|
modalWidgetName="ChangeLocationModalWidget"
|
||||||
alertClass="alert-warning" />
|
cmsWidgetName="ShopAddressWidget"
|
||||||
<appointmentTypeQuestion
|
@zip-updated="handleInShopZipUpdated" />
|
||||||
v-if="!requiresInshopRecalibration && isServiceableMobile"
|
<!-- INTEGRATION TODO: Put this right under the calendar -->
|
||||||
ref="appointmentTypeQuestion"
|
<alert
|
||||||
v-model="selectedAppointmentType"
|
v-if="selectedProvider === null"
|
||||||
groupName="appointmentTypeQuestion"
|
ref="alertNoAvailableShops"
|
||||||
cmsWidgetName="AppointmentTypeQuestionWidget"
|
cmsWidgetName="AlertNoAvailableShopsWidget"
|
||||||
validationRules="option-required" />
|
:isCollapsible="true"
|
||||||
</div>
|
alertClass="alert-danger" />
|
||||||
<div
|
</div>
|
||||||
v-if="isInshop">
|
<div
|
||||||
<alert
|
v-if="isMobile">
|
||||||
v-if="displayLowAvailabilityInshop"
|
<div class="expandable-link-container">
|
||||||
ref="alertLowAvailabilityInshop"
|
<a
|
||||||
cmsWidgetName="AlertLowAvailabilityInshopWidget"
|
v-if="displayMilitaryZipAlert && !militaryBaseWarningExpanded"
|
||||||
:isCollapsible="true"
|
href="#"
|
||||||
alertClass="alert-warning" />
|
class="expandable-link"
|
||||||
<shopAddress
|
@click.prevent="militaryBaseWarningExpanded = true">
|
||||||
ref="shopAddress"
|
{{ militaryBaseWarningLinkText }}
|
||||||
v-model="selectedProvider"
|
</a>
|
||||||
:serviceZipcode="zipCode"
|
<div
|
||||||
:selectedAppointmentType="selectedAppointmentType"
|
v-if="displayMilitaryZipAlert && militaryBaseWarningExpanded"
|
||||||
modalWidgetName="ChangeLocationModalWidget"
|
class="expandable-link-text">
|
||||||
cmsWidgetName="ShopAddressWidget"
|
{{ militaryBaseWarningText }}
|
||||||
@zip-updated="handleInShopZipUpdated" />
|
|
||||||
<!-- INTEGRATION TODO: Put this right under the calendar -->
|
|
||||||
<alert
|
|
||||||
v-if="selectedProvider === null"
|
|
||||||
ref="alertNoAvailableShops"
|
|
||||||
cmsWidgetName="AlertNoAvailableShopsWidget"
|
|
||||||
:isCollapsible="true"
|
|
||||||
alertClass="alert-danger" />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="isMobile">
|
|
||||||
<div class="expandable-link-container">
|
|
||||||
<a
|
|
||||||
v-if="displayMilitaryZipAlert && !militaryBaseWarningExpanded"
|
|
||||||
href="#"
|
|
||||||
class="expandable-link"
|
|
||||||
@click.prevent="militaryBaseWarningExpanded = true">
|
|
||||||
{{ militaryBaseWarningLinkText }}
|
|
||||||
</a>
|
|
||||||
<div
|
|
||||||
v-if="displayMilitaryZipAlert && militaryBaseWarningExpanded"
|
|
||||||
class="expandable-link-text">
|
|
||||||
{{ militaryBaseWarningText }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<serviceZipQuestion
|
|
||||||
ref="mobileServiceZipCodeQuestion"
|
|
||||||
v-model="mobileZipCode"
|
|
||||||
customInputId="mobileServiceZipCode"
|
|
||||||
class="mobile-service-zip-question"
|
|
||||||
:placeholderText="mobileZipPlaceholder"
|
|
||||||
:serviceZipFormatErrorMessage="errorMessages.MOBILE_SERVICE_ZIP_FORMAT"
|
|
||||||
:hasError="mobileZipError !== ''"
|
|
||||||
cmsWidgetName="MobileZipWidget" />
|
|
||||||
<div
|
|
||||||
v-if="mobileZipError"
|
|
||||||
ref="errorMessageDiv"
|
|
||||||
class="row my-1 form-test-error">
|
|
||||||
<span
|
|
||||||
class="d-inline-flex mt-0"
|
|
||||||
role="alert">{{ mobileZipError }}</span>
|
|
||||||
</div>
|
|
||||||
<textBlock
|
|
||||||
v-if="displayMobileFeeDisclaimer"
|
|
||||||
cmsWidgetName="MobileFeeDisclaimerWidget"
|
|
||||||
typeStyle="disclaimer" />
|
|
||||||
</div>
|
|
||||||
<contentGroupModal
|
|
||||||
:ref="RECAL_MODAL_REF_NAME"
|
|
||||||
cssModalHeadlineClass="text-center"
|
|
||||||
cmsWidgetName="RecalModal" />
|
|
||||||
<siteFooter
|
|
||||||
:ref="SITE_FOOTER_REF_NAME"
|
|
||||||
class="mt-5"
|
|
||||||
cmsWidgetName="SiteFooterWidget"
|
|
||||||
:isForwardActionDisabled="
|
|
||||||
!meta.valid || displayNoShopsAlert || displayBigTruckNoShops
|
|
||||||
"
|
|
||||||
@backClicked="navigateBack(this, navigateBackScenario)"
|
|
||||||
@forwardClicked="forwardButtonAction" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<serviceZipQuestion
|
||||||
|
ref="mobileServiceZipCodeQuestion"
|
||||||
|
v-model="mobileZipCode"
|
||||||
|
customInputId="mobileServiceZipCode"
|
||||||
|
class="mobile-service-zip-question"
|
||||||
|
:placeholderText="mobileZipPlaceholder"
|
||||||
|
:serviceZipFormatErrorMessage="errorMessages.MOBILE_SERVICE_ZIP_FORMAT"
|
||||||
|
:hasError="mobileZipError !== ''"
|
||||||
|
cmsWidgetName="MobileZipWidget" />
|
||||||
|
<div
|
||||||
|
v-if="mobileZipError"
|
||||||
|
ref="errorMessageDiv"
|
||||||
|
class="row my-1 form-test-error">
|
||||||
|
<span
|
||||||
|
class="d-inline-flex mt-0"
|
||||||
|
role="alert">{{ mobileZipError }}</span>
|
||||||
|
</div>
|
||||||
|
<textBlock
|
||||||
|
v-if="displayMobileFeeDisclaimer"
|
||||||
|
cmsWidgetName="MobileFeeDisclaimerWidget"
|
||||||
|
typeStyle="disclaimer" />
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
<contentGroupModal
|
||||||
|
:ref="RECAL_MODAL_REF_NAME"
|
||||||
|
cssModalHeadlineClass="text-center"
|
||||||
|
cmsWidgetName="RecalModal" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
// Import Supporting Files
|
// Import Supporting Files
|
||||||
import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
|
import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
|
||||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
|
||||||
import settleAllPromises from '@/helpers/layout-helper';
|
|
||||||
import errorMessages from '@/constants/error-messages';
|
import errorMessages from '@/constants/error-messages';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
import {
|
import {
|
||||||
|
getAvailabilityRating,
|
||||||
getPricedMobileFeePart,
|
getPricedMobileFeePart,
|
||||||
getServiceabilityDetails,
|
getServiceabilityDetails,
|
||||||
getZipCodeData,
|
getZipCodeData,
|
||||||
getMobileZipCodeData
|
getMobileZipCodeData
|
||||||
} from '@/helpers/service-location-helper';
|
} from '@/helpers/service-location-helper';
|
||||||
import { toTitleCase } from '@/helpers/text-helper.js';
|
import { toTitleCase } from '@/helpers/text-helper.js';
|
||||||
import { getAvailabilityRating } from '@/helpers/service-location-helper';
|
|
||||||
|
|
||||||
// Import Component
|
// Import Component
|
||||||
import alert from '@/ux-components/alert/alert.vue';
|
import alert from '@/ux-components/alert/alert.vue';
|
||||||
import textBlock from '@/digital-components/text-block/text-block.vue';
|
import textBlock from '@/digital-components/text-block/text-block.vue';
|
||||||
import appointmentTypeQuestion from '@/layouts/service-location/appointment-type-question/appointment-type-question.vue';
|
import appointmentTypeQuestion from '@/layouts/schedule-page/service-location/appointment-type-question/appointment-type-question.vue';
|
||||||
import baseFormMixin from '@/mixins/base-form-mixin';
|
import baseFormMixin from '@/mixins/base-form-mixin';
|
||||||
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
|
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
|
||||||
import { Form, defineRule } from 'vee-validate';
|
import shopAddress from '@/layouts/schedule-page/service-location/shop-address/shop-address.vue';
|
||||||
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
import serviceZipQuestion from '@/layouts/schedule-page/service-location/service-zip-question/service-zip-question.vue';
|
||||||
import siteHeader from '@/iss-components/site-header/site-header.vue';
|
|
||||||
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
|
|
||||||
import shopAddress from '@/layouts/service-location/shop-address/shop-address.vue';
|
|
||||||
import serviceZipQuestion from '@/layouts/service-location/service-zip-question/service-zip-question.vue';
|
|
||||||
import widgetFields from '@/constants/cms-widget-fields';
|
import widgetFields from '@/constants/cms-widget-fields';
|
||||||
|
|
||||||
const RECAL_MODAL_REF_NAME = 'RecalModal';
|
const RECAL_MODAL_REF_NAME = 'RecalModal';
|
||||||
|
|
@ -173,66 +149,11 @@ export default {
|
||||||
textBlock,
|
textBlock,
|
||||||
appointmentTypeQuestion,
|
appointmentTypeQuestion,
|
||||||
contentGroupModal,
|
contentGroupModal,
|
||||||
siteFooter,
|
|
||||||
siteHeader,
|
|
||||||
siteSubHeader,
|
|
||||||
// eslint-disable-next-line vue/no-reserved-component-names
|
|
||||||
Form,
|
|
||||||
shopAddress,
|
shopAddress,
|
||||||
serviceZipQuestion
|
serviceZipQuestion
|
||||||
},
|
},
|
||||||
mixins: [baseFormMixin],
|
mixins: [baseFormMixin],
|
||||||
async beforeRouteEnter(to, from, next) {
|
emits: ['service-location-updated', 'appointment-type-changed', 'mobile-zip-updated', 'provider-changed'],
|
||||||
// Call APIs
|
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
|
||||||
const serviceZipCode = useMainStore().order.serviceLocation.zipCode || useMainStore().order.customer.address.zipCode;
|
|
||||||
const zipCodeData = getZipCodeData(serviceZipCode);
|
|
||||||
const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode);
|
|
||||||
const serviceabilityDetailsPromise = getServiceabilityDetails(serviceZipCode);
|
|
||||||
const getGlassFeesPromise = useMainStore().getGlassFees();
|
|
||||||
const providersPromise = useMainStore().getProviders(serviceZipCode);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const resultMap = await settleAllPromises(promiseResultMap);
|
|
||||||
useMainStore().updateIsSafeliteProvider(true);
|
|
||||||
next(async (vm) => {
|
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
|
||||||
await vm.setData(
|
|
||||||
resultMap.zipCodeData,
|
|
||||||
resultMap.serviceabilityDetails,
|
|
||||||
resultMap.mobileFeePart,
|
|
||||||
resultMap.glassFees,
|
|
||||||
resultMap.providers
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setup() {
|
setup() {
|
||||||
const mainStore = useMainStore();
|
const mainStore = useMainStore();
|
||||||
return { mainStore };
|
return { mainStore };
|
||||||
|
|
@ -284,10 +205,7 @@ export default {
|
||||||
},
|
},
|
||||||
isServiceableInshop() {
|
isServiceableInshop() {
|
||||||
if (this.isRecalibrationServiceableInshop !== null) {
|
if (this.isRecalibrationServiceableInshop !== null) {
|
||||||
return (
|
return (this.isGlassServiceableInshop && this.isRecalibrationServiceableInshop);
|
||||||
this.isGlassServiceableInshop
|
|
||||||
&& this.isRecalibrationServiceableInshop
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.isGlassServiceableInshop;
|
return this.isGlassServiceableInshop;
|
||||||
|
|
@ -299,7 +217,7 @@ export default {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
isMobile() {
|
isMobile() {
|
||||||
return this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
|
return this.selectedAppointmentType === AppointmentTypeStrings.MOBILE;
|
||||||
},
|
},
|
||||||
requiresInshopRecalibration() {
|
requiresInshopRecalibration() {
|
||||||
// Specifically check for isRecalibrationServiceableMobile === false, not null or true.
|
// Specifically check for isRecalibrationServiceableMobile === false, not null or true.
|
||||||
|
|
@ -355,11 +273,10 @@ export default {
|
||||||
return this.getCmsContent('WhereWouldYouLikeServiceWidget', widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT);
|
return this.getCmsContent('WhereWouldYouLikeServiceWidget', widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT);
|
||||||
},
|
},
|
||||||
scheduleRecalText() {
|
scheduleRecalText() {
|
||||||
if(this.requiresInshopRecalibration) {
|
if (this.requiresInshopRecalibration) {
|
||||||
return this.getCmsContent('WhereWouldYouLikeServiceWidget', widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
|
return this.getCmsContent('WhereWouldYouLikeServiceWidget', widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
|
||||||
} else {
|
|
||||||
return this.getCmsContent('WhereWouldYouLikeServiceWidget', widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
|
|
||||||
}
|
}
|
||||||
|
return this.getCmsContent('WhereWouldYouLikeServiceWidget', widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
|
||||||
},
|
},
|
||||||
inShopOnlyCopy() {
|
inShopOnlyCopy() {
|
||||||
let content = this.getCmsContent('AlertInshopOnlyWidget', widgetFields.ALERT_WIDGET.BODY_TEXT);
|
let content = this.getCmsContent('AlertInshopOnlyWidget', widgetFields.ALERT_WIDGET.BODY_TEXT);
|
||||||
|
|
@ -375,11 +292,45 @@ export default {
|
||||||
return this.mainStore.hasRecalibrationPart;
|
return this.mainStore.hasRecalibrationPart;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
mobileZipCode(newZip) {
|
||||||
|
console.log('Mobile Zip Changed:', newZip);
|
||||||
|
if (newZip !== '') {
|
||||||
|
this.updateMobileZip();
|
||||||
|
this.$emit('mobile-zip-updated', newZip);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectedAppointmentType() {
|
||||||
|
console.log('Appointment Type Changed:', this.selectedAppointmentType);
|
||||||
|
this.mobileZipCode = '';
|
||||||
|
if (this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP && this.selectedProvider && this.availabilityRating === null) {
|
||||||
|
console.log('Fetching availability rating for in-shop appointment type...');
|
||||||
|
const startDate = new Date();
|
||||||
|
const endDate = new Date();
|
||||||
|
endDate.setDate(startDate.getDate() + 6);
|
||||||
|
const formattedStartDate = startDate.toISOString().split('T')[0];
|
||||||
|
const formattedEndDate = endDate.toISOString().split('T')[0];
|
||||||
|
getAvailabilityRating(
|
||||||
|
formattedStartDate,
|
||||||
|
formattedEndDate,
|
||||||
|
AppointmentTypeStrings.IN_SHOP,
|
||||||
|
this.selectedProvider ? this.selectedProvider.providerNumber : null
|
||||||
|
).then((rating) => {
|
||||||
|
this.availabilityRating = rating;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.$emit('appointment-type-changed', this.selectedAppointmentType);
|
||||||
|
},
|
||||||
|
selectedProvider(newProvider, oldProvider) {
|
||||||
|
if (newProvider !== oldProvider) {
|
||||||
|
console.log('Selected Provider Changed:', newProvider);
|
||||||
|
this.$emit('provider-changed', newProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
arePagePrerequisitesValid() {
|
initializeComponent(initialData) {
|
||||||
return (
|
this.setData(initialData);
|
||||||
useMainStore().order.serviceLocation.zipCode !== null
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
let provider = this.selectedProvider;
|
let provider = this.selectedProvider;
|
||||||
|
|
@ -411,11 +362,6 @@ export default {
|
||||||
appointmentType: this.selectedAppointmentType,
|
appointmentType: this.selectedAppointmentType,
|
||||||
provider
|
provider
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$router.navigate(
|
|
||||||
this.navigationScenarios.CLICKED_FORWARD,
|
|
||||||
this.$route
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
openModalAction(modalName) {
|
openModalAction(modalName) {
|
||||||
this.$refs[modalName].openModal();
|
this.$refs[modalName].openModal();
|
||||||
|
|
@ -451,50 +397,45 @@ export default {
|
||||||
setCtuForMobile(val) {
|
setCtuForMobile(val) {
|
||||||
this.zipCodeCtu = val;
|
this.zipCodeCtu = val;
|
||||||
},
|
},
|
||||||
async setData(
|
setData(initialData) {
|
||||||
zipCodeData,
|
if (initialData.zipCodeData) {
|
||||||
serviceabilityDetails,
|
this.zipContainsMilitaryBase = initialData.zipCodeData.containsMilitaryBase;
|
||||||
mobileFeePart,
|
this.zipCodeCtu = initialData.zipCodeData.zipCodeCtu;
|
||||||
glassFees,
|
this.city = initialData.zipCodeData.city;
|
||||||
providers
|
|
||||||
) {
|
|
||||||
if (zipCodeData) {
|
|
||||||
this.zipContainsMilitaryBase = zipCodeData.containsMilitaryBase;
|
|
||||||
this.zipCodeCtu = zipCodeData.zipCodeCtu;
|
|
||||||
this.city = zipCodeData.city;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serviceabilityDetails) {
|
if (initialData.serviceabilityDetails) {
|
||||||
this.setServiceabilityDetails(serviceabilityDetails);
|
this.setServiceabilityDetails(initialData.serviceabilityDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mobileFeePart) {
|
if (initialData.mobileFeePart) {
|
||||||
this.mobileFeePart = mobileFeePart;
|
this.mobileFeePart = initialData.mobileFeePart;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (providers) {
|
if (initialData.providers) {
|
||||||
this.setMobileProviderNumber(providers.mobileProviderNumber);
|
this.setMobileProviderNumber(initialData.providers.mobileProviderNumber);
|
||||||
let foundMatch = false;
|
let foundMatch = false;
|
||||||
if(this.selectedProvider && this.selectedProvider.providerNumber) {
|
if (this.selectedProvider && this.selectedProvider.providerNumber) {
|
||||||
const matchedProvider = providers.shopProviders.find(
|
// eslint-disable-next-line max-len
|
||||||
(provider) => provider.providerNumber === this.selectedProvider.providerNumber
|
const matchedProvider = initialData.providers.shopProviders.find((provider) => provider.providerNumber === this.selectedProvider.providerNumber);
|
||||||
);
|
|
||||||
if (matchedProvider) {
|
if (matchedProvider) {
|
||||||
foundMatch = true;
|
foundMatch = true;
|
||||||
this.selectedProvider = matchedProvider;
|
this.selectedProvider = matchedProvider;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(providers.shopProviders.length > 0 && !foundMatch) {
|
if (initialData.providers.shopProviders.length > 0 && !foundMatch) {
|
||||||
this.selectedProvider = providers.shopProviders[0];
|
// eslint-disable-next-line prefer-destructuring
|
||||||
}
|
this.selectedProvider = initialData.providers.shopProviders[0];
|
||||||
else if(providers.shopProviders.length === 0) {
|
} else if (initialData.providers.shopProviders.length === 0) {
|
||||||
this.selectedProvider = null;
|
this.selectedProvider = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glassFees) {
|
if (initialData.glassFees) {
|
||||||
const pricedGlassFees = await useMainStore().getCombinedQuote(glassFees);
|
useMainStore().getCombinedQuote(initialData.glassFees)
|
||||||
this.setGlassFeeItems(pricedGlassFees);
|
.then((combinedQuote) => {
|
||||||
|
this.setGlassFeeItems(combinedQuote);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setContainsMilitaryBase(val) {
|
setContainsMilitaryBase(val) {
|
||||||
|
|
@ -512,14 +453,10 @@ export default {
|
||||||
this.mobileProviderNumber = providerNumber;
|
this.mobileProviderNumber = providerNumber;
|
||||||
},
|
},
|
||||||
setServiceabilityDetails(serviceabilityDetails) {
|
setServiceabilityDetails(serviceabilityDetails) {
|
||||||
this.isGlassServiceableInshop =
|
this.isGlassServiceableInshop = serviceabilityDetails.isGlassServiceableInshop;
|
||||||
serviceabilityDetails.isGlassServiceableInshop;
|
this.isRecalibrationServiceableInshop = serviceabilityDetails.isRecalibrationServiceableInshop;
|
||||||
this.isRecalibrationServiceableInshop =
|
this.isGlassServiceableMobile = serviceabilityDetails.isGlassServiceableMobile;
|
||||||
serviceabilityDetails.isRecalibrationServiceableInshop;
|
this.isRecalibrationServiceableMobile = serviceabilityDetails.isRecalibrationServiceableMobile;
|
||||||
this.isGlassServiceableMobile =
|
|
||||||
serviceabilityDetails.isGlassServiceableMobile;
|
|
||||||
this.isRecalibrationServiceableMobile =
|
|
||||||
serviceabilityDetails.isRecalibrationServiceableMobile;
|
|
||||||
if (!this.isServiceableMobile) {
|
if (!this.isServiceableMobile) {
|
||||||
this.selectedAppointmentType = AppointmentTypeStrings.IN_SHOP;
|
this.selectedAppointmentType = AppointmentTypeStrings.IN_SHOP;
|
||||||
}
|
}
|
||||||
|
|
@ -552,10 +489,10 @@ export default {
|
||||||
const providers = result.data;
|
const providers = result.data;
|
||||||
if (providers) {
|
if (providers) {
|
||||||
this.setMobileProviderNumber(providers.mobileProviderNumber);
|
this.setMobileProviderNumber(providers.mobileProviderNumber);
|
||||||
if(providers.shopProviders.length > 0) {
|
if (providers.shopProviders.length > 0) {
|
||||||
|
// eslint-disable-next-line prefer-destructuring
|
||||||
this.selectedProvider = providers.shopProviders[0];
|
this.selectedProvider = providers.shopProviders[0];
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this.selectedProvider = null;
|
this.selectedProvider = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -577,66 +514,42 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
mobileZipCode(newZip) {
|
|
||||||
if(newZip !== '') {
|
|
||||||
this.updateMobileZip();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectedAppointmentType() {
|
|
||||||
this.mobileZipCode = '';
|
|
||||||
if(this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP && this.selectedProvider) {
|
|
||||||
const startDate = new Date();
|
|
||||||
const endDate = new Date();
|
|
||||||
endDate.setDate(startDate.getDate() + 6);
|
|
||||||
const formattedStartDate = startDate.toISOString().split('T')[0];
|
|
||||||
const formattedEndDate = endDate.toISOString().split('T')[0];
|
|
||||||
getAvailabilityRating(
|
|
||||||
formattedStartDate,
|
|
||||||
formattedEndDate,
|
|
||||||
AppointmentTypeStrings.IN_SHOP,
|
|
||||||
this.selectedProvider ? this.selectedProvider.providerNumber : null
|
|
||||||
).then((rating) => {
|
|
||||||
this.availabilityRating = rating;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
$page-side-padding: 1.5rem;
|
$page-side-padding: 1.5rem;
|
||||||
.iss-heritage-container-width {
|
|
||||||
.service-location-container {
|
|
||||||
position: relative;
|
|
||||||
min-height: 1px;
|
|
||||||
padding-left: .9375rem;
|
|
||||||
padding-right: .9375rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.service-location-container {
|
.service-location {
|
||||||
.subheader {
|
> div {
|
||||||
margin: 1.25rem 0;
|
margin-top: 1.25rem;
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
.form-test-error {
|
.form-test-error {
|
||||||
font-weight: $font-weight-bold;
|
font-weight: $font-weight-bold;
|
||||||
}
|
}
|
||||||
|
:deep(.alert-header) {
|
||||||
|
button {
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
.appointment-type-question-text {
|
.appointment-type-question-text {
|
||||||
color: $black;
|
color: $black;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 1rem;
|
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
line-height: 1.625rem;
|
line-height: 1.625rem;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
.recal-text {
|
.recal-text {
|
||||||
margin-bottom: 1.25rem;
|
|
||||||
font-weight: $font-weight-bold;
|
font-weight: $font-weight-bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.mobile-service-zip-question {
|
.mobile-service-zip-question {
|
||||||
|
:deep(.input-wrapper.has-text-button) {
|
||||||
|
button {
|
||||||
|
background-color: #1574a1;
|
||||||
|
}
|
||||||
|
}
|
||||||
:deep(.form-test-error span) {
|
:deep(.form-test-error span) {
|
||||||
font-weight: $font-weight-bold;
|
font-weight: $font-weight-bold;
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { mount } from '@vue/test-utils';
|
import { mount } from '@vue/test-utils';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import serviceZipModalQuestion from '@/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue';
|
import serviceZipModalQuestion from '@/layouts/schedule-page/service-location/service-zip-modal-question/service-zip-modal-question.vue';
|
||||||
|
|
||||||
global.crypto = crypto;
|
global.crypto = crypto;
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import textLink from '@/ux-components/text-link/text-link.vue';
|
import textLink from '@/ux-components/text-link/text-link.vue';
|
||||||
import serviceZipQuestion from '@/layouts/service-location/service-zip-question/service-zip-question.vue';
|
import serviceZipQuestion from '@/layouts/schedule-page/service-location/service-zip-question/service-zip-question.vue';
|
||||||
import modal from '@/digital-components/modal/modal.vue';
|
import modal from '@/digital-components/modal/modal.vue';
|
||||||
import alert from '@/ux-components/alert/alert.vue';
|
import alert from '@/ux-components/alert/alert.vue';
|
||||||
|
|
||||||
|
|
@ -177,6 +177,7 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "@/styles/ux-variables-svg-strings.scss";
|
||||||
a#serviceZipLinkPromptId {
|
a#serviceZipLinkPromptId {
|
||||||
line-height: 26px;
|
line-height: 26px;
|
||||||
}
|
}
|
||||||
|
|
@ -186,7 +187,7 @@ a#serviceZipLinkPromptId {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 13 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.49635 1.00142e-07C5.64734 -0.000153295 4.80722 0.175918 4.0274 0.517444C3.24757 0.858969 2.54443 1.35877 1.96099 1.98626C0.765713 3.27588 0.0999756 4.98141 0.0999756 6.75394C0.0999756 8.52646 0.765713 10.232 1.96099 11.5216L5.98324 15.777C6.04954 15.8475 6.12918 15.9036 6.21736 15.9419C6.30555 15.9802 6.40045 16 6.49635 16C6.59225 16 6.68716 15.9802 6.77534 15.9419C6.86353 15.9036 6.94317 15.8475 7.00946 15.777L11.0317 11.52C12.2391 10.2383 12.909 8.52914 12.8999 6.75394C12.9094 4.97818 12.2394 3.26832 11.0317 1.98626C10.4481 1.35899 9.74493 0.859347 8.96514 0.517839C8.18535 0.176331 7.34532 0.000130509 6.49635 1.00142e-07V1.00142e-07ZM6.49635 9.13131C6.02507 9.13131 5.56437 8.98913 5.17251 8.72275C4.78065 8.45637 4.47524 8.07776 4.29488 7.63479C4.11453 7.19181 4.06734 6.70438 4.15928 6.23412C4.25123 5.76387 4.47817 5.33191 4.81142 4.99287C5.14467 4.65384 5.56925 4.42295 6.03148 4.32941C6.49371 4.23587 6.97282 4.28388 7.40823 4.46736C7.84364 4.65085 8.21579 4.96157 8.47762 5.36023C8.73945 5.7589 8.87921 6.2276 8.87921 6.70707C8.87921 7.34974 8.62837 7.96611 8.18185 8.4207C7.73532 8.87528 7.12964 9.13088 6.49794 9.13131H6.49635Z' fill='%231574A1'/%3E%3C/svg%3E%0A");
|
background-image: url($svg-update-zip-text-link);
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import serviceZipQuestion from '@/layouts/service-location/service-zip-question/service-zip-question.vue';
|
import serviceZipQuestion from '@/layouts/schedule-page/service-location/service-zip-question/service-zip-question.vue';
|
||||||
|
|
||||||
describe('service-zip-question.vue', () => {
|
describe('service-zip-question.vue', () => {
|
||||||
it('Should get the modelValue', async () => {
|
it('Should get the modelValue', async () => {
|
||||||
|
|
@ -8,8 +8,8 @@
|
||||||
mask="#####"
|
mask="#####"
|
||||||
isRequired
|
isRequired
|
||||||
:hasError="hasError"
|
:hasError="hasError"
|
||||||
@clickEvent="updateModelValue"
|
:validationRules="`zip-required|${cmsWidgetName}-zip-format`"
|
||||||
:validationRules="`zip-required|${cmsWidgetName}-zip-format`" />
|
@clickEvent="updateModelValue" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -41,16 +41,11 @@ export default {
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
emits: ['update:modelValue'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
internalZipcode: this.modelValue
|
internalZipcode: this.modelValue
|
||||||
}
|
};
|
||||||
},
|
|
||||||
emits: ['update:modelValue'],
|
|
||||||
methods: {
|
|
||||||
updateModelValue() {
|
|
||||||
this.$emit('update:modelValue', this.internalZipcode);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
modelValue(newValue) {
|
modelValue(newValue) {
|
||||||
|
|
@ -59,6 +54,12 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
defineRule(`${this.cmsWidgetName}-zip-format`, regex(/^\d{5}$/, this.serviceZipFormatErrorMessage));
|
defineRule(`${this.cmsWidgetName}-zip-format`, regex(/^\d{5}$/, this.serviceZipFormatErrorMessage));
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateModelValue() {
|
||||||
|
console.log('Service Zip Updated:', this.internalZipcode);
|
||||||
|
this.$emit('update:modelValue', this.internalZipcode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -5,7 +5,9 @@
|
||||||
<div
|
<div
|
||||||
class="shop-address"
|
class="shop-address"
|
||||||
aria-live="polite">
|
aria-live="polite">
|
||||||
<div class="address-header">{{ questionText }}</div>
|
<div class="address-header">
|
||||||
|
{{ questionText }}
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="modelValue"
|
v-if="modelValue"
|
||||||
class="current-address">
|
class="current-address">
|
||||||
|
|
@ -13,7 +15,9 @@
|
||||||
<span class="shop-name">{{ displayedShopName }}</span>
|
<span class="shop-name">{{ displayedShopName }}</span>
|
||||||
<span class="shop-distance">{{ modelValue.distanceInMiles?.toFixed(2) }} mi</span>
|
<span class="shop-distance">{{ modelValue.distanceInMiles?.toFixed(2) }} mi</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="address-line">{{ getProviderAddress(modelValue) }}</div>
|
<div class="address-line">
|
||||||
|
{{ getProviderAddress(modelValue) }}
|
||||||
|
</div>
|
||||||
<div class="address-line">
|
<div class="address-line">
|
||||||
{{ getProviderCityZipState(modelValue) }}
|
{{ getProviderCityZipState(modelValue) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -29,9 +33,9 @@
|
||||||
:variant="'primary'"
|
:variant="'primary'"
|
||||||
@clickEvent="openModal" />
|
@clickEvent="openModal" />
|
||||||
<alert
|
<alert
|
||||||
class="alert-shop-distance"
|
|
||||||
v-if="modelValue?.distanceInMiles > 30"
|
v-if="modelValue?.distanceInMiles > 30"
|
||||||
ref="alertShopDistance"
|
ref="alertShopDistance"
|
||||||
|
class="alert-shop-distance"
|
||||||
cmsWidgetName="AlertShopDistanceWidget"
|
cmsWidgetName="AlertShopDistanceWidget"
|
||||||
alertClass="alert-warning" />
|
alertClass="alert-warning" />
|
||||||
<modal
|
<modal
|
||||||
|
|
@ -48,9 +52,9 @@
|
||||||
:markers="providerAddresses"
|
:markers="providerAddresses"
|
||||||
:zipCode="internalZipcode" />
|
:zipCode="internalZipcode" />
|
||||||
<dropdownQuestion
|
<dropdownQuestion
|
||||||
inputId="searchRadiusDropdown"
|
|
||||||
ref="searchRadiusQuestion"
|
ref="searchRadiusQuestion"
|
||||||
v-model="searchRadiusInMiles"
|
v-model="searchRadiusInMiles"
|
||||||
|
inputId="searchRadiusDropdown"
|
||||||
:cmsWidgetName="searchRadiusQuestionWidgetName"
|
:cmsWidgetName="searchRadiusQuestionWidgetName"
|
||||||
:variant="dropdownVariants.compact"
|
:variant="dropdownVariants.compact"
|
||||||
:options="searchRadiusOptions" />
|
:options="searchRadiusOptions" />
|
||||||
|
|
@ -93,7 +97,7 @@
|
||||||
import alert from '@/ux-components/alert/alert.vue';
|
import alert from '@/ux-components/alert/alert.vue';
|
||||||
import buttonMain from '@/ux-components/button-main/button-main.vue';
|
import buttonMain from '@/ux-components/button-main/button-main.vue';
|
||||||
import modal from '@/digital-components/modal/modal.vue';
|
import modal from '@/digital-components/modal/modal.vue';
|
||||||
import serviceZipQuestion from '@/layouts/service-location/service-zip-question/service-zip-question.vue';
|
import serviceZipQuestion from '@/layouts/schedule-page/service-location/service-zip-question/service-zip-question.vue';
|
||||||
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
|
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
|
||||||
import shopListButton from '@/iss-components/shop-list-button/shop-list-button.vue';
|
import shopListButton from '@/iss-components/shop-list-button/shop-list-button.vue';
|
||||||
import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question.vue';
|
import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question.vue';
|
||||||
|
|
@ -136,8 +140,9 @@ export default {
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
modalWidgetName: String,
|
modalWidgetName: String,
|
||||||
selectedAppointmentType: String,
|
selectedAppointmentType: String
|
||||||
},
|
},
|
||||||
|
emits: ['update:modelValue', 'zip-updated'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
toTitleCase,
|
toTitleCase,
|
||||||
|
|
@ -147,7 +152,7 @@ export default {
|
||||||
searchRadiusQuestionWidgetName: 'SearchRadiusQuestionWidget',
|
searchRadiusQuestionWidgetName: 'SearchRadiusQuestionWidget',
|
||||||
textboxQuestionWidgetName: 'ChangeLocationZipQuestionWidget',
|
textboxQuestionWidgetName: 'ChangeLocationZipQuestionWidget',
|
||||||
shopListButton: markRaw(shopListButton),
|
shopListButton: markRaw(shopListButton),
|
||||||
searchRadiusInMiles: "25",
|
searchRadiusInMiles: '25',
|
||||||
nearbyShops: [],
|
nearbyShops: [],
|
||||||
modalPositions,
|
modalPositions,
|
||||||
dropdownVariants,
|
dropdownVariants,
|
||||||
|
|
@ -157,7 +162,6 @@ export default {
|
||||||
SERVICE_ZIP_QUESTION_REF_NAME
|
SERVICE_ZIP_QUESTION_REF_NAME
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue', 'zip-updated'],
|
|
||||||
computed: {
|
computed: {
|
||||||
questionText() {
|
questionText() {
|
||||||
return this.getCmsContent(this.cmsWidgetName, widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT);
|
return this.getCmsContent(this.cmsWidgetName, widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT);
|
||||||
|
|
@ -166,12 +170,13 @@ export default {
|
||||||
return this.getCmsContent('ShowMoreShopsLinkWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
return this.getCmsContent('ShowMoreShopsLinkWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||||
},
|
},
|
||||||
displayedShopName() {
|
displayedShopName() {
|
||||||
if(this.modelValue.isSafeliteShop) {
|
if (this.modelValue.isSafeliteShop) {
|
||||||
return this.getCmsContent('SafeliteShopNameWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
return this.getCmsContent('SafeliteShopNameWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||||
}
|
}
|
||||||
return toTitleCase(this.modelValue.companyName);
|
return toTitleCase(this.modelValue.companyName);
|
||||||
},
|
},
|
||||||
modalHeaderText() {
|
modalHeaderText() {
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
return this.getCmsContent(this.modalWidgetName, widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT).replaceAll('{custom:serviceZipcode}', this.internalZipcode);
|
return this.getCmsContent(this.modalWidgetName, widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT).replaceAll('{custom:serviceZipcode}', this.internalZipcode);
|
||||||
},
|
},
|
||||||
modalFooterText() {
|
modalFooterText() {
|
||||||
|
|
@ -193,7 +198,7 @@ export default {
|
||||||
availabilityRatingCallback: getAvailabilityRating,
|
availabilityRatingCallback: getAvailabilityRating,
|
||||||
startDate: formattedStartDate,
|
startDate: formattedStartDate,
|
||||||
endDate: formattedEndDate,
|
endDate: formattedEndDate,
|
||||||
shopAppointmentType: "InshopOrDropoff"
|
shopAppointmentType: 'InshopOrDropoff'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
serviceZipPrompt() {
|
serviceZipPrompt() {
|
||||||
|
|
@ -218,8 +223,8 @@ export default {
|
||||||
},
|
},
|
||||||
searchRadiusOptions() {
|
searchRadiusOptions() {
|
||||||
const optionsObj = {};
|
const optionsObj = {};
|
||||||
if(this.searchRadiusArray) {
|
if (this.searchRadiusArray) {
|
||||||
this.searchRadiusArray.forEach(option => {
|
this.searchRadiusArray.forEach((option) => {
|
||||||
optionsObj[option.Name] = option.Text;
|
optionsObj[option.Name] = option.Text;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -231,11 +236,11 @@ export default {
|
||||||
fullAddress: this.getFullProviderAddress(provider),
|
fullAddress: this.getFullProviderAddress(provider),
|
||||||
addressLines: [this.getProviderAddress(provider), this.getProviderCityZipState(provider)]
|
addressLines: [this.getProviderAddress(provider), this.getProviderCityZipState(provider)]
|
||||||
})) ?? [];
|
})) ?? [];
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
async internalZipcode() {
|
async internalZipcode() {
|
||||||
if(this.openingModal) {
|
if (this.openingModal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const shopsUpdated = await this.updateShops();
|
const shopsUpdated = await this.updateShops();
|
||||||
|
|
@ -245,27 +250,28 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async searchRadiusInMiles() {
|
async searchRadiusInMiles() {
|
||||||
if(this.openingModal) {
|
if (this.openingModal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.updateShops();
|
await this.updateShops();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// eslint-disable-next-line consistent-return
|
||||||
async updateShops(autoExpand = false) {
|
async updateShops(autoExpand = false) {
|
||||||
this.errorMessage = '';
|
this.errorMessage = '';
|
||||||
let result = await this.getNearbyShops(this.searchRadiusInMiles);
|
let result = await this.getNearbyShops(this.searchRadiusInMiles);
|
||||||
let currentSearchIndex = this.searchRadiusArray.findIndex(option => option.Name === this.searchRadiusInMiles);
|
let currentSearchIndex = this.searchRadiusArray.findIndex((option) => option.Name === this.searchRadiusInMiles);
|
||||||
while (autoExpand && result.length === 0 && currentSearchIndex < this.searchRadiusArray.length - 1) {
|
while (autoExpand && result.length === 0 && currentSearchIndex < this.searchRadiusArray.length - 1) {
|
||||||
const newSearchRadius = this.searchRadiusArray[currentSearchIndex + 1].Name;
|
const newSearchRadius = this.searchRadiusArray[currentSearchIndex + 1].Name;
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
result = await this.getNearbyShops(newSearchRadius);
|
result = await this.getNearbyShops(newSearchRadius);
|
||||||
currentSearchIndex++;
|
currentSearchIndex += 1;
|
||||||
}
|
}
|
||||||
if (result.length === 0) {
|
if (result.length === 0) {
|
||||||
this.errorMessage = errorMessages.ZIP_CODE_NOT_SERVICED_FOR_VEHICLE;
|
this.errorMessage = errorMessages.ZIP_CODE_NOT_SERVICED_FOR_VEHICLE;
|
||||||
}
|
} else {
|
||||||
else {
|
if (!result.find((shop) => shop.providerNumber === this.internalProviderNumber)) {
|
||||||
if (!result.find(shop => shop.providerNumber === this.internalProviderNumber)) {
|
|
||||||
this.internalProviderNumber = '';
|
this.internalProviderNumber = '';
|
||||||
await this.$nextTick();
|
await this.$nextTick();
|
||||||
}
|
}
|
||||||
|
|
@ -283,7 +289,7 @@ export default {
|
||||||
onModalOpened() {
|
onModalOpened() {
|
||||||
this.openingModal = true;
|
this.openingModal = true;
|
||||||
this.internalZipcode = this.serviceZipcode;
|
this.internalZipcode = this.serviceZipcode;
|
||||||
this.searchRadiusInMiles = "25";
|
this.searchRadiusInMiles = '25';
|
||||||
this.nearbyShops = [];
|
this.nearbyShops = [];
|
||||||
this.updateShops(true).then(() => {
|
this.updateShops(true).then(() => {
|
||||||
this.internalProviderNumber = this.nearbyShops[0]?.providerNumber;
|
this.internalProviderNumber = this.nearbyShops[0]?.providerNumber;
|
||||||
|
|
@ -295,7 +301,7 @@ export default {
|
||||||
this.forceServiceZipRerender();
|
this.forceServiceZipRerender();
|
||||||
},
|
},
|
||||||
async updateSelectedProvider() {
|
async updateSelectedProvider() {
|
||||||
const selectedShop = this.nearbyShops.find(shop => shop.providerNumber === this.internalProviderNumber);
|
const selectedShop = this.nearbyShops.find((shop) => shop.providerNumber === this.internalProviderNumber);
|
||||||
if (selectedShop) {
|
if (selectedShop) {
|
||||||
this.$emit('update:modelValue', selectedShop);
|
this.$emit('update:modelValue', selectedShop);
|
||||||
this.$emit('zip-updated', this.internalZipcode);
|
this.$emit('zip-updated', this.internalZipcode);
|
||||||
|
|
@ -303,7 +309,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getNearbyShops(radiusInMiles) {
|
async getNearbyShops(radiusInMiles) {
|
||||||
const result = await useMainStore().getProviders(this.internalZipcode, radiusInMiles);
|
const result = await useMainStore().getProviders(this.internalZipcode, radiusInMiles);
|
||||||
return result.data.shopProviders;
|
return result.data.shopProviders;
|
||||||
},
|
},
|
||||||
getFullProviderAddress(provider) {
|
getFullProviderAddress(provider) {
|
||||||
|
|
@ -341,7 +347,7 @@ export default {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.renderServiceZip = true;
|
this.renderServiceZip = true;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -354,7 +354,7 @@ describe('vehicle-questions-mixin', () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
[issPageValues.PART_QUESTIONS, issPageValues.VEHICLE_PARTS, false],
|
[issPageValues.PART_QUESTIONS, issPageValues.VEHICLE_PARTS, false],
|
||||||
[issPageValues.VEHICLE_PARTS, issPageValues.VEHICLE_PARTS, false],
|
[issPageValues.VEHICLE_PARTS, issPageValues.VEHICLE_PARTS, false],
|
||||||
[issPageValues.VEHICLE_PARTS, issPageValues.SERVICE_LOCATION, true],
|
[issPageValues.VEHICLE_PARTS, issPageValues.SCHEDULE_PAGE, true],
|
||||||
[issPageValues.VEHICLE_PARTS, issPageValues.PART_QUESTIONS, true],
|
[issPageValues.VEHICLE_PARTS, issPageValues.PART_QUESTIONS, true],
|
||||||
[issPageValues.PART_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, false],
|
[issPageValues.PART_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, false],
|
||||||
[issPageValues.MOLDING_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, false]
|
[issPageValues.MOLDING_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, false]
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ const issPageValues = Object.freeze({
|
||||||
POLICY_HOLDER_DETAILS: 'policy-holder-details',
|
POLICY_HOLDER_DETAILS: 'policy-holder-details',
|
||||||
PROVIDER_PREFERENCE: 'provider-preference',
|
PROVIDER_PREFERENCE: 'provider-preference',
|
||||||
REVEAL: 'reveal',
|
REVEAL: 'reveal',
|
||||||
SERVICE_LOCATION: 'service-location',
|
|
||||||
TPA_CONFIRMATION: 'tpa-confirmation',
|
TPA_CONFIRMATION: 'tpa-confirmation',
|
||||||
SERVICE_PACKAGES: 'service-packages',
|
SERVICE_PACKAGES: 'service-packages',
|
||||||
SCHEDULE_PAGE: 'schedule-page',
|
SCHEDULE_PAGE: 'schedule-page',
|
||||||
|
|
|
||||||
|
|
@ -534,7 +534,7 @@ const routingTable = () => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE,
|
scenario: navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE,
|
||||||
destinationIssPageValue: issPageValues.SERVICE_LOCATION
|
destinationIssPageValue: issPageValues.SCHEDULE_PAGE
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
|
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
|
||||||
|
|
@ -559,7 +559,7 @@ const routingTable = () => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE,
|
scenario: navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE,
|
||||||
destinationIssPageValue: issPageValues.SERVICE_LOCATION
|
destinationIssPageValue: issPageValues.SCHEDULE_PAGE
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED,
|
scenario: navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED,
|
||||||
|
|
@ -572,7 +572,7 @@ const routingTable = () => [
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
issPageValue: issPageValues.SERVICE_LOCATION,
|
issPageValue: issPageValues.SCHEDULE_PAGE,
|
||||||
maps: [
|
maps: [
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_BACK_CANNOT_REACH_TPA_FLOW,
|
scenario: navigationScenarios.CLICKED_BACK_CANNOT_REACH_TPA_FLOW,
|
||||||
|
|
@ -582,26 +582,9 @@ const routingTable = () => [
|
||||||
scenario: navigationScenarios.CLICKED_BACK_CAN_REACH_TPA_FLOW,
|
scenario: navigationScenarios.CLICKED_BACK_CAN_REACH_TPA_FLOW,
|
||||||
destinationIssPageValue: issPageValues.PROVIDER_PREFERENCE
|
destinationIssPageValue: issPageValues.PROVIDER_PREFERENCE
|
||||||
},
|
},
|
||||||
{
|
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD,
|
|
||||||
destinationIssPageValue: issPageValues.SCHEDULE_PAGE
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
issPageValue: issPageValues.SCHEDULE_PAGE,
|
|
||||||
maps: [
|
|
||||||
{
|
|
||||||
scenario: navigationScenarios.CLICKED_BACK,
|
|
||||||
destinationIssPageValue: issPageValues.SERVICE_LOCATION
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD,
|
scenario: navigationScenarios.CLICKED_FORWARD,
|
||||||
destinationIssPageValue: issPageValues.CONTACT_DETAILS
|
destinationIssPageValue: issPageValues.CONTACT_DETAILS
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: navigationScenarios.CLICKED_CHANGE_LOCATION,
|
|
||||||
destinationIssPageValue: issPageValues.SERVICE_LOCATION
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -750,7 +733,7 @@ const routingTable = () => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP,
|
scenario: navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP,
|
||||||
destinationIssPageValue: issPageValues.SERVICE_LOCATION
|
destinationIssPageValue: issPageValues.SCHEDULE_PAGE
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
|
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue