Merge pull request #815 from Safelite/bug/brydon/SSR-1440

Bug/brydon/ssr 1440
This commit is contained in:
michaela-brydon-safelite 2024-08-19 12:58:19 -04:00 committed by GitHub
commit f65d43d2e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 1025 additions and 751 deletions

View file

@ -24,7 +24,7 @@ export default {
} }
const imageUrl = (this.mainStore.hasSubmittedOrder()) const imageUrl = (this.mainStore.hasSubmittedOrder())
? this.mainStore.submittedOrder.vehicle.imageUrl ? this.mainStore.getSubmittedOrder().vehicle.imageUrl
: this.mainStore.order.vehicle.imageUrl; : this.mainStore.order.vehicle.imageUrl;
if (!imageUrl || imageUrl === 'NULL') { if (!imageUrl || imageUrl === 'NULL') {
@ -54,7 +54,7 @@ export default {
}, },
methods: { methods: {
getUnmatchedVehicleIcon() { getUnmatchedVehicleIcon() {
const category = this.mainStore.submittedOrder?.vehicle.category ?? this.mainStore.order.vehicle.category; const category = this.mainStore.getSubmittedOrder()?.vehicle.category ?? this.mainStore.order.vehicle.category;
switch (category) { switch (category) {
case this.vehicleCategories.CAR: case this.vehicleCategories.CAR:
return this.carUnmatchedVehicleIcon; return this.carUnmatchedVehicleIcon;

View file

@ -2,10 +2,11 @@
import calendarOptions from '@/constants/calendar-options'; import calendarOptions from '@/constants/calendar-options';
// Supporting Files // Supporting Files
import { shallowMount } from '@vue/test-utils'; import { shallowMount, mount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import addToCalendar from '@/layouts/order-confirmation/add-to-calendar/add-to-calendar.vue'; import addToCalendar from '@/layouts/order-confirmation/add-to-calendar/add-to-calendar.vue';
import { createTestingPinia } from '@pinia/testing';
const appointmentText = 'Appointment content'; const appointmentText = 'Appointment content';
function setupMocks({ customMountOptions }) { function setupMocks({ customMountOptions }) {
@ -24,6 +25,59 @@ function setupMocks({ customMountOptions }) {
return { wrapper }; return { wrapper };
} }
const calendarModalQuestionStub = {
render: () => {}
};
const mockMixin = {
methods: {
getCmsContent: jest.fn().mockImplementation(() => appointmentText)
}
};
function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}, mixin = mockMixin) {
const mountOptions = getMountOptions({
router: {
navigate: jest.fn(),
navigateToExternalUrl: jest.fn()
}
});
mountOptions.global.stubs = {
// siteFooter: footerStub,
// siteHeader: headerStub,
// vehicleBanner: vehicleBannerStub,
// addToCalendar: addToCalendarStub
calendarModalQuestion: calendarModalQuestionStub
};
const testingPinia = createTestingPinia({
initialState: {
main: mainInitialState
}
});
useMainStore(testingPinia);
methodToRun();
mountOptions.global.mixins[0].methods.getSettingValue = jest.fn(() => 'false');
mountOptions.global.plugins = [testingPinia];
mountOptions.mixins = [mixin];
mountOptions.data = () => (
initialData
);
// const apiResponses = {
// supportingItems: []
// };
//const apiPromise = Promise.resolve(apiResponses);
// settleAllPromises.mockImplementation(() => apiPromise);
//fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
const wrapper = shallowMount(addToCalendar, mountOptions);
wrapper.vm.$refs.calendarModalQuestion.openModal = jest.fn();
return { wrapper };
}
beforeEach(() => { beforeEach(() => {
jest.restoreAllMocks(); jest.restoreAllMocks();
jest.clearAllMocks(); jest.clearAllMocks();
@ -76,10 +130,52 @@ afterEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
const sessionStorage = {
schedule: {
date: '2019-01-01',
startTime: '09:00',
endTime: '10:00',
routeCode: '000'
},
lineItems: {
glassParts: [
{
partNumber: 'ABC123'
}
],
supportingItems: []
},
serviceLocation: {
address: '',
address2: null,
city: '',
state: 'AZ',
appointmentType: 'Inshop',
zipCode: '12345',
zipCodeCtu: '01234',
provider: {
providerNumber: '123',
address: {
streetAddress: 'test1',
city: 'test',
state: 'AZ',
zipCode: '12345',
zipCodeCtu: '01234'
}
}
},
damage: {
isRepair: false
},
referralNumber: '1234567',
payment: {
isInsurance: true
}
};
describe('Add-to-calendar methods...', () => { describe('Add-to-calendar methods...', () => {
test('Add-to-calendar should trigger openModal method', () => { test('Add-to-calendar should trigger openModal method', () => {
// Arrange // Arrange
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
customMountOptions: { customMountOptions: {
propsData: { propsData: {

View file

@ -30,8 +30,6 @@ import { getDateFormat,
addMinutes } from '@/helpers/date-helper'; addMinutes } from '@/helpers/date-helper';
import { AppointmentTypeStrings, RouteCodeFlags } from '@/constants/schedule-constants'; import { AppointmentTypeStrings, RouteCodeFlags } from '@/constants/schedule-constants';
import { getCalendarFile, download } from '@/helpers/add-to-calendar-helper'; import { getCalendarFile, download } from '@/helpers/add-to-calendar-helper';
import { useMainStore } from '@/store';
import serviceType from '@/constants/service-type'; import serviceType from '@/constants/service-type';
import applicationConfig from '@/constants/application-config.js'; import applicationConfig from '@/constants/application-config.js';
import calendarModalQuestion from '@/layouts/order-confirmation/add-to-calendar/calendar-modal-question/calendar-modal-question.vue'; import calendarModalQuestion from '@/layouts/order-confirmation/add-to-calendar/calendar-modal-question/calendar-modal-question.vue';
@ -53,12 +51,11 @@ export default {
appointmentType: String, appointmentType: String,
scheduleDate: String, scheduleDate: String,
scheduleStartTime: String, scheduleStartTime: String,
scheduleEndTime: String scheduleEndTime: String,
}, hasRecalibrationPart: Boolean,
setup() { uniqueId: String,
const mainStore = useMainStore(); isRepair: Boolean,
const { submittedOrder } = mainStore; routeCode: String
return { mainStore, submittedOrder };
}, },
data() { data() {
return { return {
@ -116,23 +113,15 @@ export default {
AddToCalendar_SameDayDropOff_Body() { AddToCalendar_SameDayDropOff_Body() {
return this.getCmsContent(this.sameDayDropOffWidgetName, 'BodyText'); return this.getCmsContent(this.sameDayDropOffWidgetName, 'BodyText');
}, },
UniqueId() {
return this.submittedOrder.referralNumber?.toString();
},
ServiceType() { ServiceType() {
const { isRepair } = this.submittedOrder.damage; if (!this.isRepair) {
const { hasRecalibrationPart } = this.mainStore; if (this.hasRecalibrationPart) {
if (!isRepair) {
if (hasRecalibrationPart) {
return serviceType.REPLACEMENT_AND_RECALIBRATION; return serviceType.REPLACEMENT_AND_RECALIBRATION;
} }
return serviceType.REPLACEMENT; return serviceType.REPLACEMENT;
} }
return serviceType.REPAIR; return serviceType.REPAIR;
}, },
RouteCode() {
return this.submittedOrder.schedule.routeCode;
},
Appointment() { Appointment() {
let subject = ''; let subject = '';
let location = ''; let location = '';
@ -153,10 +142,10 @@ export default {
} else { } else {
location = this.providerFullAddress?.replace('<br/>', ''); location = this.providerFullAddress?.replace('<br/>', '');
if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) { if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) {
if (this.RouteCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) { if (this.routeCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
subject = this.AddToCalendar_OvernightDropOff_Subject; subject = this.AddToCalendar_OvernightDropOff_Subject;
body = this.AddToCalendar_OvernightDropOff_Body; body = this.AddToCalendar_OvernightDropOff_Body;
} else if (this.RouteCode.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) { } else if (this.routeCode.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
if (this.IsSameDayDropOff) { if (this.IsSameDayDropOff) {
subject = this.AddToCalendar_SameDayDropOff_Subject; subject = this.AddToCalendar_SameDayDropOff_Subject;
endDateTime = addMinutes(startDateTime, 120); endDateTime = addMinutes(startDateTime, 120);
@ -196,7 +185,7 @@ export default {
Location: location, Location: location,
StartDate: startDateTime, StartDate: startDateTime,
EndDate: endDateTime, EndDate: endDateTime,
RefrrlSeqNum: this.UniqueId, RefrrlSeqNum: this.uniqueId,
Body: body, Body: body,
IsHTML: isHTML, IsHTML: isHTML,
Duration: duration Duration: duration
@ -287,10 +276,6 @@ export default {
const calBody = getCalendarFile(calFile); const calBody = getCalendarFile(calFile);
download('SafeliteAppointment.ics', calBody); download('SafeliteAppointment.ics', calBody);
} }
// getInShopAppointmentText() {
// const test = this.getCmsContent('AddToCalendar_InShop_TEST', 'Text');
// return test;
// }
} }
}; };
</script> </script>

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@
<div class="container-fluid fade-on-route-transition"> <div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2"> <div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" /> <siteHeader :cmsWidgetName="widgets.siteHeader" />
</div> </div>
</div> </div>
<div class="row justify-content-center"> <div class="row justify-content-center">
@ -21,13 +21,13 @@
<div class="appointment-details"> <div class="appointment-details">
<div> <div>
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" :cmsWidgetName="widgets.vehicleBanner"
:displayGenericVehicleImage="false"> :displayGenericVehicleImage="false">
</vehicleBanner> </vehicleBanner>
</div> </div>
<div class="appointment-date-time text-center mt-4"> <div class="appointment-date-time text-center mt-4">
<p>{{ appointmentDateFormatted }}</p> <p>{{ formatDate(schedule.date) }}</p>
<p class="mt-2">{{ appointmentTimeFormatted }}</p> <p class="mt-2">{{ appointmentTimeText }}</p>
</div> </div>
<addToCalendar <addToCalendar
mobileWidgetName="AddToCalendar_Mobile" mobileWidgetName="AddToCalendar_Mobile"
@ -36,14 +36,16 @@
overnightDropOffWidgetName="AddToCalendar_OvernightDropOff" overnightDropOffWidgetName="AddToCalendar_OvernightDropOff"
allDayDropOffWidgetName="AddToCalendar_AllDayDropOff" allDayDropOffWidgetName="AddToCalendar_AllDayDropOff"
sameDayDropOffWidgetName="AddToCalendar_SameDayDropOff" sameDayDropOffWidgetName="AddToCalendar_SameDayDropOff"
:serviceLocationFullAddress=" :serviceLocationFullAddress="serviceLocationFullAddress"
serviceLocationFullAddress
"
:providerFullAddress="providerFullAddress" :providerFullAddress="providerFullAddress"
:appointmentType="appointmentType" :appointmentType="appointmentType"
:scheduleDate="appointmentDate" :scheduleDate="schedule.date"
:scheduleStartTime="appointmentStartTime" :scheduleStartTime="schedule.startTime"
:scheduleEndTime="appointmentEndTime" /> :scheduleEndTime="schedule.endTime"
:routeCode="schedule.routeCode"
:hasRecalibrationPart="hasRecalibrationPart"
:uniqueId="referralNumber"
:isRepair="isRepair" />
<div <div
class="appointment-text text-center lh-base" class="appointment-text text-center lh-base"
v-html="appointmentWordingText"></div> v-html="appointmentWordingText"></div>
@ -54,7 +56,7 @@
<hr class="mb-0" /> <hr class="mb-0" />
<div> <div>
<cartDropdown <cartDropdown
:showAsPaid="isPayInAdvance" :showAsPaid="payment.isPayInAdvance"
:readOnly="true" :readOnly="true"
:isInitiallyExpanded="false" :isInitiallyExpanded="false"
:showDropdownHeader="true" :showDropdownHeader="true"
@ -69,7 +71,7 @@
<siteFooter <siteFooter
v-if="carrierUrl" v-if="carrierUrl"
ref="siteFooter" ref="siteFooter"
cmsWidgetName="SiteFooterWidget" :cmsWidgetName="widgets.siteFooter"
:isStackedVertically="true" :isStackedVertically="true"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction" @ForwardClicked="forwardButtonAction"
@ -90,7 +92,8 @@ import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
// Supporting files // Supporting files
import { import {
fetchCmsContentForPage, fetchCmsContentForPage,
processIfStatements processIfStatements,
getStringWithCustomValues
} from '@/helpers/cms-content-helper'; } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper'; import settleAllPromises from '@/helpers/layout-helper';
import { Form } from 'vee-validate'; import { Form } from 'vee-validate';
@ -105,7 +108,7 @@ import {
import { toTitleCase } from '@/helpers/text-helper.js'; import { toTitleCase } from '@/helpers/text-helper.js';
import { AppointmentTypeStrings } from '@/constants/schedule-constants'; import { AppointmentTypeStrings } from '@/constants/schedule-constants';
import applicationConfig from '@/constants/application-config'; import applicationConfig from '@/constants/application-config';
import submitType from '@/constants/submit-type'; import widgetFields from '@/constants/cms-widget-fields.js';
export default { export default {
name: 'order-confirmation', name: 'order-confirmation',
@ -139,193 +142,169 @@ export default {
}, },
setup() { setup() {
const mainStore = useMainStore(); const mainStore = useMainStore();
const { submittedOrder } = mainStore; const submittedOrder = mainStore.getSubmittedOrder();
return { mainStore, submittedOrder }; return { mainStore, submittedOrder };
}, },
data() {
var {
vehicle,
serviceLocation,
schedule,
customer,
payment,
customerPortalLoginToken,
damage,
referralNumber } = this.submittedOrder;
var { issConfig, hasRecalibrationPart } = this.mainStore;
return {
vehicle,
customerEmail: customer?.emailAddress,
payment,
schedule,
serviceLocation,
appointmentType: serviceLocation.appointmentType,
providerAddress: serviceLocation?.provider?.address,
customerPortalLoginToken,
carrierName: issConfig.clientName,
carrierUrl: issConfig.successReturnURL,
isRepair: damage.isRepair,
hasRecalibrationPart,
referralNumber: referralNumber?.toString(),
widgets: {
siteHeader: 'SiteHeaderWidget',
vehicleBanner: 'VehicleBannerWidget',
emailConfirmation: 'EmailConfirmationWordingWidget',
orderConfirmation: 'OrderConfirmationContent',
mobile: 'MobileWordingWidget',
dropOffAndInShop: 'DropOffAndInShopWordingWidget',
siteFooter: 'SiteFooterWidget'
},
}
},
computed: { computed: {
carrierName() { customValueMap() {
return this.mainStore.issConfig.clientName; return {
}, inShopAppointment: this.isInShopAppointment,
carrierUrl() { dropOffAppointment: this.isDropOffAppointment,
return this.mainStore.issConfig.successReturnURL; vehicleYear: this.vehicle?.year,
vehicleMake: this.vehicle?.make,
vehicleModel: this.vehicle?.model,
address: this.appointmentLocation,
inShopDuration: this.inShopAppointmentDuration,
email: this.customerEmail,
CUSTOMER_PORTAL_URL: applicationConfig.CUSTOMER_PORTAL_URL,
CUSTOMER_PORTAL_LOGIN_TOKEN: this.customerPortalLoginToken
}
}, },
confirmationEmailText() { confirmationEmailText() {
return this.getCmsContent( var content = this.getCmsContentWithCustomValues(
'EmailConfirmationWordingWidget', this.widgets.emailConfirmation,
'BodyText' widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
) return content
?.replaceAll(
'{custom:CUSTOMER_PORTAL_URL}',
applicationConfig.CUSTOMER_PORTAL_URL
)
?.replaceAll(
'{custom:CUSTOMER_PORTAL_LOGIN_TOKEN}',
this.submittedOrder.customerPortalLoginToken
)
?.replaceAll('&lt;', '<') ?.replaceAll('&lt;', '<')
?.replaceAll('&gt;', '>'); ?.replaceAll('&gt;', '>');
}, },
orderConfirmationHeaderText() { orderConfirmationHeaderText() {
return this.getCmsContent('OrderConfirmationContent', 'HeaderText'); return this.getCmsContent(
this.widgets.orderConfirmation,
widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT);
}, },
orderConfirmationImage() { orderConfirmationImage() {
return this.getCmsContent('OrderConfirmationContent', 'Image'); return this.getCmsContent(
}, this.widgets.orderConfirmation,
appointmentType() { widgetFields.CONTENT_GROUP_WIDGET.IMAGE);
return this.submittedOrder.serviceLocation.appointmentType;
},
appointmentDate() {
return this.submittedOrder.schedule.date;
},
appointmentStartTime() {
return this.submittedOrder.schedule.startTime;
},
appointmentEndTime() {
return this.submittedOrder.schedule.endTime;
},
appointmentDateFormatted() {
// This conversion ensures we don't get get GMT induced date changes
const dateObject = convertDateStringToDate(this.appointmentDate);
// Ex: Tuesday, April 22
return dateObject.toLocaleDateString('en-us', {
weekday: 'long',
month: 'long',
day: 'numeric'
});
},
appointmentTimeFormatted() {
const formattedTime = this.formatAppointmentTime(this.appointmentType);
return formattedTime;
}, },
mobileWordingText() { mobileWordingText() {
return this.getCmsContent('MobileWordingWidget', 'BodyText'); return this.getCmsContentWithCustomValues(
this.widgets.mobile,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
}, },
mobileWordingText2() { mobileWordingText2() {
return this.getCmsContent('MobileWordingWidget', 'BodyText2');
},
dropOffAndInShopWordingText() {
return this.getCmsContent( return this.getCmsContent(
'DropOffAndInShopWordingWidget', this.widgets.mobile,
'BodyText' widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
);
}, },
dropOffAndInShopWordingText2() { nonMobileWordingText() {
return this.getBodyText2FromCms('DropOffAndInShopWordingWidget'); return this.getCmsContentWithCustomValues(
this.widgets.dropOffAndInShop,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
}, },
serviceLocationAddress() { nonMobileWordingText2() {
return this.submittedOrder.serviceLocation.address; return this.getCmsContentWithCustomValues(
this.widgets.dropOffAndInShop,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
}, },
serviceLocationAddress2() { appointmentTimeText() {
return this.submittedOrder.serviceLocation.address2; const { startTime, endTime } = this.schedule;
if (this.isDropOffAppointment){
return 'Drop off before 9:30 AM';
}
if (this.isInShopAppointment){
const formattedStartTime = get12HourTimeFormat(startTime);
return `at ${formattedStartTime}`
}
if (this.isMobileAppointment) {
const mobileStartTime = get12HourTimeMobileFormat(startTime);
const mobileEndTime = get12HourTimeMobileFormat(endTime);
return `Between ${mobileStartTime} - ${mobileEndTime}`;
}
return null;
}, },
serviceLocationCity() { appointmentLocation() {
return this.submittedOrder.serviceLocation.city; if (this.isMobileAppointment){
}, return this.serviceLocationFullAddress;
serviceLocationState() { }
return this.submittedOrder.serviceLocation.state; if (this.isDropOffAppointment || this.isInShopAppointment){
}, return this.providerFullAddress;
serviceLocationZipCode() { }
return this.submittedOrder.serviceLocation.zipCode; return null
}, },
serviceLocationFullAddress() { serviceLocationFullAddress() {
// eslint-disable-next-line max-len var { address, address2, city, state, zipCode } = this.serviceLocation;
return `${this.serviceLocationAddress}, ${ return `${address ?? ''}, ${address2 ? `${address2},` : ''}<br/> ${city ?? ''}, ${state ?? ''} ${zipCode ?? ''}`;
this.serviceLocationAddress2
? `${this.serviceLocationAddress2},`
: ''
}<br/> ${this.serviceLocationCity}, ${this.serviceLocationState} ${
this.serviceLocationZipCode
}`;
},
providerAddress() {
return toTitleCase(this.submittedOrder.serviceLocation.provider.address
.streetAddress);
},
providerCity() {
return toTitleCase(this.submittedOrder.serviceLocation.provider.address.city);
},
providerState() {
return this.submittedOrder.serviceLocation.provider.address.state;
},
providerZipCode() {
return this.submittedOrder.serviceLocation.provider.address.zipCode;
}, },
providerFullAddress() { providerFullAddress() {
// eslint-disable-next-line max-len var { streetAddress, city, state, zipCode } = this.providerAddress;
return this.submittedOrder.serviceLocation?.provider?.address return streetAddress
? `${this.providerAddress},<br/> ${this.providerCity}, ${this.providerState} ${this.providerZipCode}` ? `${toTitleCase(streetAddress)},<br/> ${toTitleCase(city)}, ${state ?? ''} ${zipCode ?? ''}`
: ''; : '';
}, },
appointmentWordingText() { appointmentWordingText() {
switch (this.appointmentType) { if (this.isMobileAppointment){
case AppointmentTypeStrings.MOBILE: return this.mobileWordingText;
case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP:
return this.mobileWordingText?.replaceAll(
'{custom:address}',
this.serviceLocationFullAddress
);
case AppointmentTypeStrings.DROP_OFF:
return this.dropOffAndInShopWordingText?.replaceAll(
'{custom:address}',
this.providerFullAddress
);
case AppointmentTypeStrings.IN_SHOP:
return this.dropOffAndInShopWordingText?.replaceAll(
'{custom:address}',
this.providerFullAddress
);
default:
return null;
} }
if (this.isInShopAppointment || this.isDropOffAppointment){
return this.nonMobileWordingText;
}
return null;
}, },
appointmentWordingText2() { appointmentWordingText2() {
switch (this.appointmentType) { if (this.isMobileAppointment){
case AppointmentTypeStrings.MOBILE: return this.mobileWordingText2;
case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP:
return this.mobileWordingText2;
case AppointmentTypeStrings.DROP_OFF:
return this.dropOffAndInShopWordingText2;
case AppointmentTypeStrings.IN_SHOP:
return this.dropOffAndInShopWordingText2?.replaceAll(
'{custom:inShopDuration}',
this.inShopAppointmentDuration
);
default:
return null;
} }
if (this.isInShopAppointment || this.isDropOffAppointment){
return this.nonMobileWordingText2;
}
return null;
}, },
mobileAppointment() { isMobileAppointment() {
return ( const mobileAppointmentTypes = [
this.submittedOrder.serviceLocation.appointmentType AppointmentTypeStrings.MOBILE,
=== AppointmentTypeStrings.MOBILE AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
|| this.submittedOrder.serviceLocation.appointmentType ]
=== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP return mobileAppointmentTypes.includes(this.appointmentType);
);
}, },
inShopAppointment() { isInShopAppointment() {
return ( return this.appointmentType === AppointmentTypeStrings.IN_SHOP;
this.submittedOrder.serviceLocation.appointmentType
=== AppointmentTypeStrings.IN_SHOP
);
}, },
dropOffAppointment() { isDropOffAppointment() {
return ( return this.appointmentType === AppointmentTypeStrings.DROP_OFF;
this.submittedOrder.serviceLocation.appointmentType
=== AppointmentTypeStrings.DROP_OFF
);
}, },
inShopAppointmentDuration() { inShopAppointmentDuration() {
const inshopDurationTime = getDisplayTextForDurationLength( return getDisplayTextForDurationLength(
this.submittedOrder.schedule.jobMinMinutes, this.schedule.jobMinMinutes,
this.submittedOrder.schedule.jobMaxMinutes this.schedule.jobMaxMinutes
); );
return inshopDurationTime;
},
isPayInAdvance() {
return this.submittedOrder.payment.isPayInAdvance;
},
selectedVaps() {
return this.submittedOrder.lineItems.vaps;
} }
}, },
mounted() { mounted() {
@ -404,38 +383,24 @@ export default {
forwardButtonAction() { forwardButtonAction() {
this.$router.navigateToExternalUrl(this.carrierUrl); this.$router.navigateToExternalUrl(this.carrierUrl);
}, },
formatAppointmentTime(appointmentType) { getCmsContentWithCustomValues(widgetName, widgetField) {
switch (appointmentType) { const rawText = this.getCmsContent(widgetName, widgetField);
case AppointmentTypeStrings.MOBILE: const processedIfStatements = processIfStatements(
case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: rawText,
// eslint-disable-next-line max-len
return `Between ${get12HourTimeMobileFormat(this.appointmentStartTime)} - ${get12HourTimeMobileFormat(this.appointmentEndTime)}`;
case AppointmentTypeStrings.DROP_OFF:
return 'Drop off before 9:30 AM';
case AppointmentTypeStrings.IN_SHOP:
return `at ${get12HourTimeFormat(this.appointmentStartTime)}`;
default:
return null;
}
},
processIfStatements,
getBodyText2FromCms(cmsWidgetName) {
const body2Text = this.getCmsContent(cmsWidgetName, 'BodyText2');
return this.processIfStatements(
body2Text,
'custom', 'custom',
this.getCustomValueFromString (v) => { return this.customValueMap[v] }
); );
return getStringWithCustomValues(processedIfStatements, this.customValueMap);
}, },
getCustomValueFromString(str) { formatDate(date) {
switch (str) { // This conversion ensures we don't get get GMT induced date changes
case 'inShopAppointment': const dateObject = convertDateStringToDate(date);
return this.inShopAppointment; // Ex: Tuesday, April 22
case 'dropOffAppointment': return dateObject.toLocaleDateString('en-us', {
return this.dropOffAppointment; weekday: 'long',
default: month: 'long',
return null; day: 'numeric'
} });
} }
} }
}; };

View file

@ -22,7 +22,11 @@ jest.mock('@/helpers/order-helper.js', () => ({
function setupMocks({ customMountOptions = {}, queryString }, mainInitialState = {}, customMixin = null) { function setupMocks({ customMountOptions = {}, queryString }, mainInitialState = {}, customMixin = null) {
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
...customMountOptions, ...customMountOptions,
route: { query: { issPage: issPageValues.PAYMENT_METHOD, ...queryString }, params: {} } route: { query: { issPage: issPageValues.PAYMENT_METHOD, ...queryString }, params: {} },
router: {
navigate: jest.fn(),
navigateToExternalUrl: jest.fn()
}
}); });
const testingPinia = createTestingPinia({ const testingPinia = createTestingPinia({

View file

@ -301,20 +301,18 @@ export default {
if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) { if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) {
try { try {
await submitWorkOrder({ submitType: submitType.SAFELITE }).then(() => { await submitWorkOrder({ submitType: submitType.SAFELITE });
this.$router.navigate( this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD, this.navigationScenarios.CLICKED_FORWARD,
this.$route this.$route
); );
}).catch((submitError) => {
useMainStore().setBailout(bailoutMessage.saveSessionError(submitError.data));
this.$router.navigate(
this.navigationScenarios.SAVE_SESSION_FAILED,
this.$route,
{ issPage: issPageValues.PAYMENT_METHOD }
);
});
} catch (error) { } catch (error) {
useMainStore().setBailout(bailoutMessage.saveSessionError(error.data));
this.$router.navigate(
this.navigationScenarios.SAVE_SESSION_FAILED,
this.$route,
{ issPage: issPageValues.PAYMENT_METHOD }
);
console.error(`error: response from submit work order:${error.message}`); console.error(`error: response from submit work order:${error.message}`);
} }
} else { } else {

View file

@ -8,8 +8,8 @@ import settleAllPromises from '@/helpers/layout-helper.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing'; import { createTestingPinia } from '@pinia/testing';
import bailoutMessage from '@/constants/bailoutMessage';
import coverageStatuses from '@/constants/coverage-statuses'; import coverageStatuses from '@/constants/coverage-statuses';
import { deepClone } from '@/helpers/object-helper';
jest.mock('@/helpers/layout-helper.js', () => jest.fn()); jest.mock('@/helpers/layout-helper.js', () => jest.fn());
@ -54,11 +54,6 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
} }
}); });
const store = useMainStore(testingPinia); const store = useMainStore(testingPinia);
store.submittedOrder = {
...JSON.parse(JSON.stringify(store.order)),
isVerified: store.isVerified,
isUnverified: store.isUnverified
};
store.order = getDefaultState().order; store.order = getDefaultState().order;
store.hasSubmittedOrder = jest.fn().mockReturnValue(true); store.hasSubmittedOrder = jest.fn().mockReturnValue(true);
methodToRun(); methodToRun();
@ -80,12 +75,33 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
return { wrapper }; return { wrapper };
} }
const defaultOrder = {
serviceLocation: {
provider: {
companyName: "Hershey",
phoneNumber: "726-117-0377"
}
},
currentDeductible: 479,
isVerified: false,
carrierPhoneNumber: "757-277-0388",
vehicle: {
imageUrl: 'url for image',
category: 'car'
}
}
describe('TPAConfirmation.vue', () => { describe('TPAConfirmation.vue', () => {
describe('Rendering', () => { describe('Rendering', () => {
let wrapper;
let mockStoreActions;
beforeEach(() => {
mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => defaultOrder);
};
wrapper = getMountedComponent({}, {}, mockStoreActions).wrapper;
});
test('Should render Site Header', () => { test('Should render Site Header', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act // Act
const siteHeader = wrapper.findComponent({ ref: 'siteHeader' }); const siteHeader = wrapper.findComponent({ ref: 'siteHeader' });
@ -93,9 +109,6 @@ describe('TPAConfirmation.vue', () => {
expect(siteHeader.exists()).toBe(true); expect(siteHeader.exists()).toBe(true);
}); });
test('Should render Vehicle Banner', () => { test('Should render Vehicle Banner', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act // Act
const vehicleBanner = wrapper.findComponent({ ref: 'vehicleBanner' }); const vehicleBanner = wrapper.findComponent({ ref: 'vehicleBanner' });
@ -103,9 +116,6 @@ describe('TPAConfirmation.vue', () => {
expect(vehicleBanner.exists()).toBe(true); expect(vehicleBanner.exists()).toBe(true);
}); });
test('Should render Confirmation Body One', () => { test('Should render Confirmation Body One', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act // Act
const bodyOne = wrapper.findComponent({ ref: 'tpaConfirmationBodyOne' }); const bodyOne = wrapper.findComponent({ ref: 'tpaConfirmationBodyOne' });
@ -113,9 +123,6 @@ describe('TPAConfirmation.vue', () => {
expect(bodyOne.exists()).toBe(true); expect(bodyOne.exists()).toBe(true);
}); });
test('Should render Confirmation Body Two', () => { test('Should render Confirmation Body Two', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act // Act
const bodyTwo = wrapper.findComponent({ ref: 'tpaConfirmationBodyTwo' }); const bodyTwo = wrapper.findComponent({ ref: 'tpaConfirmationBodyTwo' });
@ -123,9 +130,6 @@ describe('TPAConfirmation.vue', () => {
expect(bodyTwo.exists()).toBe(true); expect(bodyTwo.exists()).toBe(true);
}); });
test('Should render Order Details title', () => { test('Should render Order Details title', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act // Act
const orderDetailsTitle = wrapper.findComponent({ ref: 'tpaConfirmationOrderDetailsTitle' }); const orderDetailsTitle = wrapper.findComponent({ ref: 'tpaConfirmationOrderDetailsTitle' });
@ -133,9 +137,6 @@ describe('TPAConfirmation.vue', () => {
expect(orderDetailsTitle.exists()).toBe(true); expect(orderDetailsTitle.exists()).toBe(true);
}); });
test('Should render Order Details body', () => { test('Should render Order Details body', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act // Act
const orderDetailsBody = wrapper.findComponent({ ref: 'tpaConfirmationOrderDetailsBody' }); const orderDetailsBody = wrapper.findComponent({ ref: 'tpaConfirmationOrderDetailsBody' });
@ -143,9 +144,6 @@ describe('TPAConfirmation.vue', () => {
expect(orderDetailsBody.exists()).toBe(true); expect(orderDetailsBody.exists()).toBe(true);
}); });
test('Should render Deductible Box', () => { test('Should render Deductible Box', () => {
// Arrange
const { wrapper } = getMountedComponent({});
// Act // Act
const deductibleBox = wrapper.findComponent({ ref: 'deductibleBox' }); const deductibleBox = wrapper.findComponent({ ref: 'deductibleBox' });
@ -160,7 +158,7 @@ describe('TPAConfirmation.vue', () => {
successReturnURL: carrierReturnUrl successReturnURL: carrierReturnUrl
} }
}; };
const { wrapper } = getMountedComponent(initialStore); wrapper = getMountedComponent(initialStore, {}, mockStoreActions).wrapper;
// Act // Act
const siteFooter = wrapper.findComponent({ ref: 'siteFooter' }); const siteFooter = wrapper.findComponent({ ref: 'siteFooter' });
@ -169,9 +167,6 @@ describe('TPAConfirmation.vue', () => {
expect(siteFooter.exists()).toBe(true); expect(siteFooter.exists()).toBe(true);
}); });
test('If Essential flow, should not display Site Footer', () => { test('If Essential flow, should not display Site Footer', () => {
// Arrange
const { wrapper } = getMountedComponent();
// Act // Act
const siteFooter = wrapper.findComponent({ ref: 'siteFooter' }); const siteFooter = wrapper.findComponent({ ref: 'siteFooter' });
@ -190,7 +185,10 @@ describe('TPAConfirmation.vue', () => {
} }
} }
}; };
const { wrapper } = getMountedComponent(initialStore); const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => defaultOrder);
};
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
const expected = 'Verifying coverage'; const expected = 'Verifying coverage';
// Assert // Assert
@ -207,7 +205,12 @@ describe('TPAConfirmation.vue', () => {
currentDeductible currentDeductible
} }
}; };
const { wrapper } = getMountedComponent(initialStore); const order = deepClone(defaultOrder);
order.isVerified = true;
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
const notExpected = 'Verifying coverage'; const notExpected = 'Verifying coverage';
// Assert // Assert
@ -216,26 +219,22 @@ describe('TPAConfirmation.vue', () => {
}); });
}); });
describe('Methods', () => { describe('Methods', () => {
describe('getCustomValueFromString', () => { describe.only('getCustomValueFromString', () => {
describe.each([ describe.each([
[false, coverageStatuses.PENDING, 0], [false, false, 0],
[false, coverageStatuses.PENDING, 500], [false, false, 500],
[false, coverageStatuses.NO_COVERAGE, 0], [false, true, 0],
[false, coverageStatuses.NO_COVERAGE, 500], [true, true, 500]
[false, coverageStatuses.VERIFIED, 0], ])('with argument deductibleAboveZero', (expected, isVerified, deductible) => {
[true, coverageStatuses.VERIFIED, 500]
])('with argument deductibleAboveZero', (expected, status, deductible) => {
test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} and currentDeductible is ${deductible}`, () => { test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} and currentDeductible is ${deductible}`, () => {
// Arrange // Arrange
const initialStore = { const order = deepClone(defaultOrder);
order: { order.isVerified = isVerified;
insuranceCoverage: { order.currentDeductible = deductible;
coverageStatus: status const mockStoreActions = () => {
}, useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
currentDeductible: deductible
}
}; };
const { wrapper } = getMountedComponent(initialStore); const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const argument = 'deductibleAboveZero'; const argument = 'deductibleAboveZero';
// Act // Act
@ -247,24 +246,20 @@ describe('TPAConfirmation.vue', () => {
}); });
describe('with argument zeroDeductible', () => { describe('with argument zeroDeductible', () => {
describe.each([ describe.each([
[false, coverageStatuses.PENDING, 0], [false, false, 0],
[false, coverageStatuses.PENDING, 500], [false, false, 500],
[false, coverageStatuses.NO_COVERAGE, 0], [true, true, 0],
[false, coverageStatuses.NO_COVERAGE, 500], [false, true, 500]
[true, coverageStatuses.VERIFIED, 0], ])('with argument zeroDeductible', (expected, isVerified, deductible) => {
[false, coverageStatuses.VERIFIED, 500]
])('with argument zeroDeductible', (expected, status, deductible) => {
test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} and currentDeductible is ${deductible}`, () => { test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} and currentDeductible is ${deductible}`, () => {
// Arrange // Arrange
const initialStore = { const order = deepClone(defaultOrder);
order: { order.isVerified = isVerified;
insuranceCoverage: { order.currentDeductible = deductible;
coverageStatus: status const mockStoreActions = () => {
}, useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
currentDeductible: deductible
}
}; };
const { wrapper } = getMountedComponent(initialStore); const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const argument = 'zeroDeductible'; const argument = 'zeroDeductible';
// Act // Act
@ -277,21 +272,18 @@ describe('TPAConfirmation.vue', () => {
}); });
describe('with argument verifyingCoverage', () => { describe('with argument verifyingCoverage', () => {
describe.each([ describe.each([
[true, coverageStatuses.PENDING], [true, false],
[true, coverageStatuses.NO_COVERAGE], [false, true]
[false, coverageStatuses.VERIFIED] ])('with argument zeroDeductible', (expected, isVerified) => {
])('with argument zeroDeductible', (expected, status) => {
test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)}`, () => { test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)}`, () => {
// Arrange // Arrange
const initialStore = { const order = deepClone(defaultOrder);
order: { order.isVerified = isVerified;
insuranceCoverage: { order.currentDeductible = 123;
coverageStatus: status const mockStoreActions = () => {
}, useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
currentDeductible: 123
}
}; };
const { wrapper } = getMountedComponent(initialStore); const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const argument = 'verifyingCoverage'; const argument = 'verifyingCoverage';
// Act // Act
@ -304,6 +296,9 @@ describe('TPAConfirmation.vue', () => {
}); });
}); });
describe('Navigation', () => { describe('Navigation', () => {
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => defaultOrder);
};
test('If Advanced flow, forward button action navigates to carrier URL', () => { test('If Advanced flow, forward button action navigates to carrier URL', () => {
// Arrange // Arrange
const carrierReturnUrl = 'testURL'; const carrierReturnUrl = 'testURL';
@ -312,7 +307,7 @@ describe('TPAConfirmation.vue', () => {
successReturnURL: carrierReturnUrl successReturnURL: carrierReturnUrl
} }
}; };
const { wrapper } = getMountedComponent(initialStore); const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
// Act // Act
wrapper.vm.forwardButtonAction(); wrapper.vm.forwardButtonAction();

View file

@ -127,7 +127,7 @@ export default {
}, },
setup() { setup() {
const mainStore = useMainStore(); const mainStore = useMainStore();
const { submittedOrder } = mainStore; const submittedOrder = mainStore.getSubmittedOrder();
return { mainStore, submittedOrder }; return { mainStore, submittedOrder };
}, },
computed: { computed: {

View file

@ -50,7 +50,7 @@ const routes = [
// Intercept all navigation if a submitted order exists in storage // Intercept all navigation if a submitted order exists in storage
if (useMainStore().hasSubmittedOrder()) { if (useMainStore().hasSubmittedOrder()) {
if (to.query.issPage !== issPageValues.ENTRY_PAGE) { if (to.query.issPage !== issPageValues.ENTRY_PAGE) {
return await GoToConfirmationPage(next, useMainStore().submittedOrder); return await GoToConfirmationPage(next, useMainStore().getSubmittedOrder());
} }
} }

View file

@ -423,8 +423,7 @@ export const useMainStore = defineStore({
experimentSettings: (state) => state.applicationUser.experiments experimentSettings: (state) => state.applicationUser.experiments
.filter((x) => !!x.isActive) .filter((x) => !!x.isActive)
.map((x) => x.settings) .map((x) => x.settings)
.reduce((r, c) => Object.assign(r, c), {}) ?? {}, .reduce((r, c) => Object.assign(r, c), {}) ?? {}
submittedOrder: () => JSON.parse(window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER))
}, },
actions: actions:
{ {
@ -2651,6 +2650,10 @@ export const useMainStore = defineStore({
return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null;
}, },
getSubmittedOrder() {
return JSON.parse(window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER));
},
createSubmittedOrder(submitType) { createSubmittedOrder(submitType) {
if (this.hasSubmittedOrder()) { if (this.hasSubmittedOrder()) {
return; return;