-
- {{ deductibleLabel }}
- {{ getDisplayed(deductible) }}
-
-
- {{ basePriceLabel }}
- {{ getDisplayed(servicePrice) }}
-
+ {{ deductibleLabel }}
+ {{ getDisplayed(deductible) }}
+
+
+
+
+ {{ basePriceLabel }}
+ {{ getDisplayed(servicePrice) }}
+
+
+
+
+ {{ recalibrationLabel }}
+ {{ formatAmountInDollars(recalibrationPrice) }}
-
+ class="cart-item packaged">
-
-
-
- {{ item?.name ?? '' }}
+ {{ item?.name ?? '' }}
{{ formatAmountInDollars(item?.subTotal ?? 0) }}
-
-
-
-
- {{ item?.name ?? '' }}
- {{ formatAmountInDollars(item?.subTotal ?? 0) }}
-
-
-
- {{ item?.name ?? '' }}
-
-
-
+
+ {{ deductibleLabel }}:
+ {{ getDisplayed(deductible) }}
@@ -117,7 +96,6 @@ import contentGroupModal from '@/iss-components/content-group-modal/content-grou
import textBlock from '@/digital-components/text-block/text-block.vue';
import textLink from '@/ux-components/text-link/text-link.vue';
import { formatAmountInDollars } from '@/helpers/text-helper.js';
-import { getHighestFullySatisfiedTier, getPackageContents } from '@/helpers/service-package-helper.js';
// Constants
import { experimentSettings } from '@/constants/experiments';
@@ -128,6 +106,7 @@ import {
getCartTotal,
getDeductible,
getLineItems, getMobileFeeLineItem,
+ getRecalibrationTotal,
getRecycleFeeLineItem, getSalesTax,
getServiceLineItems, getSubtotal, isOrderITAC, isOrderNoComp,
isOrderUnverified
@@ -136,19 +115,15 @@ import { getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculat
import { processIfStatements } from '@/helpers/cms-content-helper';
const VERIFYING_COVERAGE = 'Verifying coverage';
-const RECYCLING_MODAL_REF_NAME = 'RecycleModal';
export default {
name: 'confirmation-cart',
components: {
- contentGroupModal,
- textBlock,
textLink
},
props: {
readOnly: Boolean,
showAsPaid: Boolean,
- recyclingModalCmsWidgetName: String,
submittedOrder: Object
},
data() {
@@ -158,6 +133,7 @@ export default {
amountPaid: 'AmountPaidTextWidget',
deductible: 'DeductibleWidget',
basePrice: 'BasePriceWidget',
+ recalibration: 'RecalibrationWidget',
subtotal: 'SubtotalWidget',
salesTax: 'SalesTaxWidget',
recycleFee: 'RecycleFeeWidget',
@@ -167,8 +143,7 @@ export default {
warrantyText: 'WarrantyCartItemTextWidget',
guaranteeText: 'GuaranteeCartItemTextWidget'
},
- cartItemType,
- RECYCLING_MODAL_REF_NAME
+ cartItemType
};
},
computed: {
@@ -181,9 +156,18 @@ export default {
deductible() {
return getDeductible(this.cartOrder);
},
+ isDeductibleOnly() {
+ return this.cartItems.length === 0;
+ },
showDeductibleCartItem() {
return this.isUnverified || (!this.isNoComp && !this.isITAC);
},
+ showRecalibrationCartItem() {
+ return this.recalibrationPrice > 0;
+ },
+ recalibrationPrice() {
+ return getRecalibrationTotal(this.cartOrder);
+ },
lineItems() {
return getLineItems(this.cartOrder);
},
@@ -191,7 +175,8 @@ export default {
return getRecycleFeeLineItem(this.cartOrder);
},
servicePrice() {
- return getPriceOfLineItems(getServiceLineItems(this.cartOrder)) ?? 0;
+ const price = getPriceOfLineItems(getServiceLineItems(this.cartOrder)) ?? 0;
+ return price - this.recalibrationPrice;
},
isUnverified() {
return isOrderUnverified(this.cartOrder);
@@ -229,47 +214,21 @@ export default {
];
return result;
},
- vehicleDamage() {
- return this.cartOrder.damage;
- },
- servicePackageTier() {
- const { glassToReplace, isRepair } = this.vehicleDamage;
- const { vaps } = this.lineItems;
- return getHighestFullySatisfiedTier(
- glassToReplace ?? [],
- this.availableLineItems,
- isRepair,
- vaps ?? []
- );
- },
- partTypesInServicePackage() {
- const { glassToReplace, isRepair } = this.vehicleDamage;
- return getPackageContents(
- glassToReplace ?? [],
- this.availableLineItems,
- isRepair,
- this.servicePackageTier
- ) ?? [];
- },
- servicePackageCartItems() {
+ cartItems() {
const items = [];
- if (this.partTypesInServicePackage.includes(partTypeStrings.FRONT_WIPER) ?? this.frontWipersCartItem) {
- items.push(this.frontWipersCartItem);
+ const isRecycleFeeHidden = this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_HIDDEN) === 'true';
+ const isMobileFeeHidden = this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_HIDDEN) === 'true';
+ if (this.isITAC || this.isNoComp) {
+ items.push(this.warrantyCartItem);
}
- if (this.partTypesInServicePackage.includes(partTypeStrings.REAR_WIPER) ?? this.rearWipersCartItem) {
- items.push(this.rearWipersCartItem);
+ if (this.recycleFeeCartItem && !isRecycleFeeHidden) {
+ items.push(this.recycleFeeCartItem);
}
- if (this.partTypesInServicePackage.includes(partTypeStrings.RAIN_DEFENSE) ?? this.rainDefenseCartItem) {
- items.push(this.rainDefenseCartItem);
+ if (this.mobileFeeCartItem && !isMobileFeeHidden) {
+ items.push(this.mobileFeeCartItem);
}
- return items;
- },
- nonServicePackageCartItems() {
const vapPartTypesInOrder = Array.from(new Set(this.lineItems.vaps?.map((vap) => vap.partType) ?? []));
- const vapPartTypesInOrderButNotPackage = vapPartTypesInOrder
- .filter((partType) => !this.partTypesInServicePackage.includes(partType))
- ?? [];
- const vapsCartItemsNotInPackage = vapPartTypesInOrderButNotPackage.map((partType) => {
+ const vapsCartItems = vapPartTypesInOrder.map((partType) => {
switch (partType) {
case partTypeStrings.FRONT_WIPER:
return this.frontWipersCartItem;
@@ -281,18 +240,7 @@ export default {
return null;
}
});
- const items = vapsCartItemsNotInPackage.filter((item) => item != null);
- const isRecycleFeeHidden = this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_HIDDEN) === 'true';
- const isMobileFeeHidden = this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_HIDDEN) === 'true';
- if (this.recycleFeeCartItem && !isRecycleFeeHidden) {
- items.push(this.recycleFeeCartItem);
- }
- if (this.mobileFeeCartItem && !isMobileFeeHidden) {
- items.push(this.mobileFeeCartItem);
- }
- if (this.isITAC || this.isNoComp) {
- items.push(this.warrantyCartItem);
- }
+ items.push(...vapsCartItems.filter((item) => item != null));
return items;
},
frontWipersCartItem() {
@@ -304,12 +252,6 @@ export default {
rainDefenseCartItem() {
return this.getCartItemForVapsPart(partTypeStrings.RAIN_DEFENSE);
},
- allCartItems() {
- return [
- ...this.servicePackageCartItems,
- ...this.nonServicePackageCartItems
- ];
- },
amountDueLabel() {
return this.getCmsContent(this.widget.amountDue, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
},
@@ -327,27 +269,15 @@ export default {
this.getCustomValueFromString
);
},
+ recalibrationLabel() {
+ return this.getCmsContent(this.widget.recalibration, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
+ },
subtotalLabel() {
return this.getCmsContent(this.widget.subtotal, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
},
salesTaxLabel() {
return this.getCmsContent(this.widget.salesTax, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
},
- servicePackageNames() {
- return this.getCmsContent(
- this.widget.servicePackage,
- widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
- );
- },
- servicePackageLabelWidget() {
- if (!this.servicePackageNames) {
- return '';
- }
- const currentPackage = this.servicePackageNames
- ?.find((entry) => entry?.Name === this.servicePackageTier);
-
- return currentPackage?.SubWidgetName ?? '';
- },
recycleFeeCartItem() {
return this.recycleFeeLineItem
? this.getCartItem(
@@ -452,8 +382,6 @@ export default {
diff --git a/src/layouts/tpa-submit/contact-details-drawer/__snapshots__/contact-details-drawer.spec.js.snap b/src/iss-components/contact-details-drawer/__snapshots__/contact-details-drawer.spec.js.snap
similarity index 88%
rename from src/layouts/tpa-submit/contact-details-drawer/__snapshots__/contact-details-drawer.spec.js.snap
rename to src/iss-components/contact-details-drawer/__snapshots__/contact-details-drawer.spec.js.snap
index 842c5af2..effbe1a8 100644
--- a/src/layouts/tpa-submit/contact-details-drawer/__snapshots__/contact-details-drawer.spec.js.snap
+++ b/src/iss-components/contact-details-drawer/__snapshots__/contact-details-drawer.spec.js.snap
@@ -2,6 +2,7 @@
exports[`contact-details-drawer snapshot matches returns the initial data 1`] = `
Object {
+ "detailsSaved": false,
"emailAddress": "fred.tay@gmail.com",
"extension": null,
"firstName": "Frederick",
@@ -15,8 +16,8 @@ Object {
"rules": Object {
"emailAddress": "email-required|email-address-format",
"extension": "extension-format",
- "firstName": "first-name-required",
- "lastName": "last-name-required",
+ "firstName": "policyholder-first-name-required",
+ "lastName": "policyholder-last-name-required",
"phoneNumber": "phone-number-required|phone-number-format",
},
"widget": Object {
diff --git a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js b/src/iss-components/contact-details-drawer/contact-details-drawer.spec.js
similarity index 98%
rename from src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js
rename to src/iss-components/contact-details-drawer/contact-details-drawer.spec.js
index 04fe6ce6..dd30a043 100644
--- a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js
+++ b/src/iss-components/contact-details-drawer/contact-details-drawer.spec.js
@@ -1,7 +1,7 @@
// Components
import { shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
-import contactDetailsDrawer from '@/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue';
+import contactDetailsDrawer from '@/iss-components/contact-details-drawer/contact-details-drawer.vue';
// Supporting Files
import { getMountOptions } from '@/helpers/unit-test-helper.js';
diff --git a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue b/src/iss-components/contact-details-drawer/contact-details-drawer.vue
similarity index 82%
rename from src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue
rename to src/iss-components/contact-details-drawer/contact-details-drawer.vue
index 7d5b0572..660ae1c3 100644
--- a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue
+++ b/src/iss-components/contact-details-drawer/contact-details-drawer.vue
@@ -9,25 +9,29 @@
@isModalOpened="setModalStatus"
@footerButtonEvent="clickFooterButtonEvent">
-
+
{{ nameSectionLabel }}
+
+ @backClick="navigateBackByVehicleQuestions"
+ @needHelpClick="requestCallbackBailout" />
+
+
\ No newline at end of file
diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js
index aa9c3058..a8b77aa5 100644
--- a/src/layouts/coverage-statement/coverage-statement.spec.js
+++ b/src/layouts/coverage-statement/coverage-statement.spec.js
@@ -63,7 +63,8 @@ const loadingModalStub = {
function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}) {
const mountOptions = getMountOptions({
router: {
- navigate: jest.fn()
+ navigate: jest.fn(),
+ navigateBailout: jest.fn()
}
});
@@ -134,7 +135,10 @@ describe('coverageStatement.vue', () => {
});
test('Should render site subheader', () => {
// Arrange
- const { wrapper } = getMountedComponent({});
+ const initialDataForTest = {
+ isPageLoading: false
+ };
+ const { wrapper } = getMountedComponent({}, initialDataForTest);
// Act
const subheader = wrapper.find({ ref: 'siteSubHeader' });
@@ -145,7 +149,10 @@ describe('coverageStatement.vue', () => {
test('Should render explanatory text', () => {
// Arrange
- const { wrapper } = getMountedComponent({});
+ const initialDataForTest = {
+ isPageLoading: false
+ };
+ const { wrapper } = getMountedComponent({}, initialDataForTest);
// Act
const explanatoryText = wrapper.find({ ref: 'explanatoryText' });
@@ -155,7 +162,10 @@ describe('coverageStatement.vue', () => {
});
test('Should render secondary text', () => {
// Arrange
- const { wrapper } = getMountedComponent({});
+ const initialDataForTest = {
+ isPageLoading: false
+ };
+ const { wrapper } = getMountedComponent({}, initialDataForTest);
// Act
const secondaryText = wrapper.find({ ref: 'secondaryText' });
@@ -430,6 +440,109 @@ describe('coverageStatement.vue', () => {
expect(result).toBe(expected);
});
});
+ describe('displayAfterpayBanner', () => {
+ test('returns true if ITAC', () => {
+ // Arrange
+ const mainInitialState = {
+ order: {
+ insuranceCoverage: {
+ coverageStatus: coverageStatuses.VERIFIED,
+ coverageType: coverageType.ITAC
+ }
+ }
+ };
+ const { wrapper } = getMountedComponent(mainInitialState);
+
+ // Act
+ const result = wrapper.vm.displayAfterpayBanner;
+
+ // Assert
+ expect(result).toBeTruthy();
+ });
+ test('returns true if No Comp', () => {
+ // Arrange
+ const mainInitialState = {
+ order: {
+ insuranceCoverage: {
+ coverageStatus: coverageStatuses.VERIFIED,
+ coverageType: coverageType.NO_COMP
+ }
+ }
+ };
+ const { wrapper } = getMountedComponent(mainInitialState);
+
+ // Act
+ const result = wrapper.vm.displayAfterpayBanner;
+
+ // Assert
+ expect(result).toBeTruthy();
+ });
+ test('returns true if deductible is > $0', () => {
+ // Arrange
+ const mainInitialState = {
+ order: {
+ insuranceCoverage: {
+ coverageStatus: coverageStatuses.VERIFIED,
+ coverageType: coverageType.Deductible
+ },
+ damage: {
+ isRepair: false
+ },
+ currentDeductible: {
+ replace: 500
+ }
+ }
+ };
+ const { wrapper } = getMountedComponent(mainInitialState);
+
+ // Act
+ const result = wrapper.vm.displayAfterpayBanner;
+
+ // Assert
+ expect(result).toBeTruthy();
+ });
+ test('returns false if deductible is <= $0', () => {
+ // Arrange
+ const mainInitialState = {
+ order: {
+ insuranceCoverage: {
+ coverageStatus: coverageStatuses.VERIFIED,
+ coverageType: coverageType.Deductible
+ },
+ damage: {
+ isRepair: false
+ },
+ currentDeductible: {
+ replace: 0
+ }
+ }
+ };
+ const { wrapper } = getMountedComponent(mainInitialState);
+
+ // Act
+ const result = wrapper.vm.displayAfterpayBanner;
+
+ // Assert
+ expect(result).toBeFalsy();
+ });
+ test('returns false if Unverified', () => {
+ // Arrange
+ const mainInitialState = {
+ order: {
+ insuranceCoverage: {
+ coverageStatus: coverageStatuses.UNVERIFIED,
+ }
+ }
+ };
+ const { wrapper } = getMountedComponent(mainInitialState);
+
+ // Act
+ const result = wrapper.vm.displayAfterpayBanner;
+
+ // Assert
+ expect(result).toBeFalsy();
+ });
+ });
});
describe('methods', () => {
describe('arePagePrerequisitesValid', () => {
@@ -578,7 +691,7 @@ describe('coverageStatement.vue', () => {
undefined
);
});
- test('If Verified ITAC, selected Cancel, navigate forward w/ CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP', () => {
+ test('If Verified ITAC, selected Cancel, navigateBailout', () => {
// Arrange
const deductible = servicePrice + 1;
const mainInitialState = {
@@ -604,11 +717,7 @@ describe('coverageStatement.vue', () => {
wrapper.vm.cancelClaim();
// Assert
- expect(wrapper.vm.$router.navigate)
- .toHaveBeenCalledWith(
- navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
- undefined
- );
+ expect(wrapper.vm.$router.navigateBailout).toHaveBeenCalled();
});
test('If No Comp and selected Safelite, navigate forward with CLICKED_FORWARD_WITH_SAFELITE scenario', () => {
// Arrange
@@ -641,7 +750,7 @@ describe('coverageStatement.vue', () => {
undefined
);
});
- test('If No comp and selected other shop, navigate forward with CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP ', () => {
+ test('If No comp and selected other shop, navigateBailout ', () => {
// Arrange
const mainInitialState = {
order: {
@@ -666,11 +775,7 @@ describe('coverageStatement.vue', () => {
wrapper.vm.cancelClaim();
// Assert
- expect(wrapper.vm.$router.navigate)
- .toHaveBeenCalledWith(
- navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
- undefined
- );
+ expect(wrapper.vm.$router.navigateBailout).toHaveBeenCalled();
});
});
describe('openCancelClaimModal', () => {
diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue
index c1c7abbd..832d9219 100644
--- a/src/layouts/coverage-statement/coverage-statement.vue
+++ b/src/layouts/coverage-statement/coverage-statement.vue
@@ -10,7 +10,8 @@
cmsWidgetName="SiteHeaderWidget" />
-
+
+
0);
}
},
watch: {
@@ -347,6 +360,9 @@ export default {
}
},
mounted() {
+ if (this.isPageLoading) {
+ showIssLoadingModal(true);
+ }
setupModalLinks(this);
},
methods: {
@@ -370,6 +386,7 @@ export default {
}
showIssLoadingModal(false);
+ this.isPageLoading = false;
},
async getPricedParts() {
const { glassParts, supportingItems } = this.mainStore.order.lineItems;
@@ -380,18 +397,7 @@ export default {
// We only call the ITAC pricing endpoint if we are not repair or we are NoComp
if (!this.isRepair || this.mainStore.isNoComp) {
- const pricingResults = await useMainStore().getITACPriceOrderItems(availableLineItems)
- .catch((err) => {
- useMainStore().setBailout(bailoutMessage.pricingResponseError(
- availableLineItems.map((li) => li.partNumber),
- {
- code: err.code,
- message: err.message,
- data: err.data
- }
- ));
- this.navigateWithScenario(navigationScenarios.PRICING_LOOKUP_ERROR);
- });
+ const pricingResults = await useMainStore().getITACPriceOrderItems(availableLineItems);
this.setBaseServiceLineItems(pricingResults);
}
},
@@ -402,8 +408,7 @@ export default {
this.mainStore.updateIsSafeliteProvider(true);
this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE);
} else {
- this.mainStore.setBailout(bailoutMessage.coverageStatementInvalidState());
- this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE);
+ this.$router.navigateBailout(bailoutMessage.coverageStatementInvalidState());
}
},
navigateWithScenario(scenario) {
@@ -457,8 +462,7 @@ export default {
},
cancelClaim() {
this.mainStore.updateIsSafeliteProvider(false);
- this.mainStore.setBailout(bailoutMessage.RequestCallback());
- this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP);
+ this.$router.navigateBailout(bailoutMessage.RequestCallback());
}
}
};
diff --git a/src/layouts/duplicate-check/duplicate-check.spec.js b/src/layouts/duplicate-check/duplicate-check.spec.js
index 10be35e2..95346c26 100644
--- a/src/layouts/duplicate-check/duplicate-check.spec.js
+++ b/src/layouts/duplicate-check/duplicate-check.spec.js
@@ -357,11 +357,15 @@ describe('duplicateCheck.vue', () => {
useMainStore().loadSession = jest.fn().mockImplementation(() => Promise.reject(error));
// Act
- await wrapper.vm.forwardButtonAction();
// Assert
+ expect.assertions(2);
+ try {
+ await wrapper.vm.forwardButtonAction();
+ } catch (e) {
+ expect(e).toMatch(error);
+ }
expect(wrapper.vm.mainStore.loadSession).toHaveBeenCalledTimes(1);
- expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
});
test('coverageType deductible and policy vehicles returned => CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES', async () => {
// Arrange
diff --git a/src/layouts/duplicate-check/duplicate-check.vue b/src/layouts/duplicate-check/duplicate-check.vue
index 1cac5a1e..3c4ead5f 100644
--- a/src/layouts/duplicate-check/duplicate-check.vue
+++ b/src/layouts/duplicate-check/duplicate-check.vue
@@ -140,18 +140,14 @@ export default {
return;
}
- try {
- const selectedReferral =
- this.mainStore.applicationUser.duplicateOrders.find((o) => o.correlationId === this.selectedAnswer);
+ const selectedReferral =
+ this.mainStore.applicationUser.duplicateOrders.find((o) => o.correlationId === this.selectedAnswer);
- if (selectedReferral) {
- await this.mainStore.loadSession(selectedReferral);
- }
- } catch (err) {
- console.error(`Error on loading session from duplicate check ${err}`);
- } finally {
- this.navigateForward();
+ if (selectedReferral) {
+ await this.mainStore.loadSession(selectedReferral);
}
+
+ this.navigateForward();
},
navigateForward() {
this.mainStore.updateDuplicateCheckVisited(true);
diff --git a/src/layouts/entry-page/entry-page.vue b/src/layouts/entry-page/entry-page.vue
index e9880117..47031709 100644
--- a/src/layouts/entry-page/entry-page.vue
+++ b/src/layouts/entry-page/entry-page.vue
@@ -34,44 +34,51 @@ export default {
computed: {
},
async mounted() {
- const queryStringParams = this.parseQueryParms();
-
- const { isAuthorized, clientData, decryptedParams } = await this.validateClientTagOnEntry(queryStringParams);
-
- this.unauthorized = !isAuthorized;
- if (!isAuthorized) {
- // Remove the loading animation if client tag validation fails so users can see the Unauthorized Access message.
- showIssLoadingModal(false);
- return;
- }
-
- this.populateISSConfigValues(clientData);
-
try {
- // Check cookie
- const issCookie = getISSCookie();
- if (issCookie !== null && issCookie.VehicleMake && issCookie.VehicleModel) {
- const clientParentAccountNumber = clientData.parentAccountNumber;
- const cookieParentAccountNumber = issCookie.ReferralParentAccountNumber;
+ const queryStringParams = this.parseQueryParms();
- if (clientParentAccountNumber === cookieParentAccountNumber) {
- const savedSessionTimeStamp = new Date(issCookie.SavedSessionTimeoutDate);
- const isSavedSessionTimedOut = new Date(new Date().toUTCString()) > savedSessionTimeStamp;
+ const { isAuthorized, clientData, decryptedParams } = await this.validateClientTagOnEntry(queryStringParams);
- if (!isSavedSessionTimedOut) {
- this.mainStore.issConfig.enableContinueFromCookie = true;
+ this.unauthorized = !isAuthorized;
+ if (!isAuthorized) {
+ // Remove the loading animation if client tag validation fails so users can see the Unauthorized Access message.
+ showIssLoadingModal(false);
+ return;
+ }
+
+ this.populateISSConfigValues(clientData);
+
+ try {
+ // Check cookie
+ const issCookie = getISSCookie();
+ if (issCookie !== null && issCookie.VehicleMake && issCookie.VehicleModel) {
+ const clientParentAccountNumber = clientData.parentAccountNumber;
+ const cookieParentAccountNumber = issCookie.ReferralParentAccountNumber;
+
+ if (clientParentAccountNumber === cookieParentAccountNumber) {
+ const savedSessionTimeStamp = new Date(issCookie.SavedSessionTimeoutDate);
+ const isSavedSessionTimedOut = new Date(new Date().toUTCString()) > savedSessionTimeStamp;
+
+ if (!isSavedSessionTimedOut) {
+ this.mainStore.issConfig.enableContinueFromCookie = true;
+ }
}
+ } else {
+ updateOrCreateISSCookie(true);
}
- } else {
+ } catch {
updateOrCreateISSCookie(true);
}
- } catch {
- updateOrCreateISSCookie(true);
- }
- if (clientData.parameters?.length > 0) {
- const finalParams = this.combineClientParameters(clientData.parameters, { ...queryStringParams, ...decryptedParams });
- this.populateStoreItemsFromParams(finalParams);
+ if (clientData.parameters?.length > 0) {
+ const finalParams = this.combineClientParameters(clientData.parameters, { ...queryStringParams, ...decryptedParams });
+ this.populateStoreItemsFromParams(finalParams);
+ }
+ } catch (e) {
+ global.$logger.logError('[Entry Page] Client Setup Error:', e);
+ this.unauthorized = true;
+ showIssLoadingModal(false);
+ return;
}
this.mainStore.applicationUser.coverageAttempts = 0;
@@ -151,37 +158,33 @@ export default {
this.mainStore.issConfig.isCoverageEnabled = data.coverageEnabled;
this.mainStore.issConfig.siteType = data.siteType;
- try {
- if (data.clientFlags) {
- const clientFlags = JSON.parse(data.clientFlags);
+ if (data.clientFlags) {
+ const clientFlags = JSON.parse(data.clientFlags);
- if (clientFlags.TPAEnabled) {
- this.mainStore.issConfig.enableTPAFlow = true;
- }
-
- if (clientFlags.ClientFullName != null) {
- this.mainStore.issConfig.clientFullName = clientFlags.ClientFullName;
- }
-
- if (clientFlags.ClientDisplayName != null) {
- this.mainStore.issConfig.clientDisplayName = clientFlags.ClientDisplayName;
- this.mainStore.issConfig.clientPossessiveName = toPossessive(clientFlags.ClientDisplayName);
- }
-
- if (clientFlags.ClientPossessiveName != null) {
- this.mainStore.issConfig.clientPossessiveName = clientFlags.ClientPossessiveName;
- }
-
- if (clientFlags.ClaimRegistrationRequired) {
- this.mainStore.issConfig.isClaimRegistrationRequired = true;
- }
-
- if (clientFlags.EnableNoCompQuote) {
- this.mainStore.issConfig.enableNoCompQuote = true;
- }
+ if (clientFlags.TPAEnabled) {
+ this.mainStore.issConfig.enableTPAFlow = true;
+ }
+
+ if (clientFlags.ClientFullName != null) {
+ this.mainStore.issConfig.clientFullName = clientFlags.ClientFullName;
+ }
+
+ if (clientFlags.ClientDisplayName != null) {
+ this.mainStore.issConfig.clientDisplayName = clientFlags.ClientDisplayName;
+ this.mainStore.issConfig.clientPossessiveName = toPossessive(clientFlags.ClientDisplayName);
+ }
+
+ if (clientFlags.ClientPossessiveName != null) {
+ this.mainStore.issConfig.clientPossessiveName = clientFlags.ClientPossessiveName;
+ }
+
+ if (clientFlags.ClaimRegistrationRequired) {
+ this.mainStore.issConfig.isClaimRegistrationRequired = true;
+ }
+
+ if (clientFlags.EnableNoCompQuote) {
+ this.mainStore.issConfig.enableNoCompQuote = true;
}
- } catch (e) {
- console.error(`Error parsing client flags: ${e}`);
}
},
combineClientParameters(configParams, queryStringParams) {
diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue
index 3fdce88e..44d6af81 100644
--- a/src/layouts/molding-questions/molding-questions.vue
+++ b/src/layouts/molding-questions/molding-questions.vue
@@ -10,8 +10,6 @@
v-model="selectedAnswers"
isRequired
:isMetaValid="meta.valid"
- :alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
- :alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
:questionsData="questionsData"
:validationRules="rules.optionRequired"
:index="currentGlassIndex"
@@ -71,18 +69,6 @@ export default {
};
},
computed: {
- AlertFewMoreQuestionsHeader() {
- return this.getCmsContent(
- 'AdditionalPartsQuestionsAlert',
- 'HeadlineText'
- );
- },
- AlertFewMoreQuestionsCopy() {
- return this.getCmsContent(
- 'AdditionalPartsQuestionsAlert',
- 'BodyText'
- );
- },
partsOrQuestionsData() {
return useMainStore().pageData(issPageValues.MOLDING_QUESTIONS).partsOrQuestions;
}
@@ -162,8 +148,7 @@ export default {
this.navigateForward(partsOrQuestions, null);
},
requestCallbackBailout() {
- this.mainStore.setBailout(bailoutMessage.RequestCallback());
- this.$router.navigate(navigationScenarios.CLICKED_NEED_HELP_WITH_BAILOUT, this.$route);
+ this.$router.navigateBailout(bailoutMessage.RequestCallback());
}
}
};
diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue
index 34ed6789..ab3d2bbe 100644
--- a/src/layouts/order-confirmation/order-confirmation.vue
+++ b/src/layouts/order-confirmation/order-confirmation.vue
@@ -94,6 +94,7 @@
diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue
index 1230016a..9bed6345 100644
--- a/src/layouts/part-questions/part-questions.vue
+++ b/src/layouts/part-questions/part-questions.vue
@@ -148,8 +148,7 @@ export default {
this.navigateForward(glassPartsForStore, null);
},
requestCallbackBailout() {
- this.mainStore.setBailout(bailoutMessage.RequestCallback());
- this.$router.navigate(navigationScenarios.CLICKED_NEED_HELP_WITH_BAILOUT, this.$route);
+ this.$router.navigateBailout(bailoutMessage.RequestCallback());
}
},
};
diff --git a/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue
index 0f834cbc..6bd161eb 100644
--- a/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue
+++ b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue
@@ -2,32 +2,30 @@
-
+ buttonWrapperClasses="list-group base-input-button list-button payment-method d-flex flex-column w-100 no-hover">
+
+
+
+
+
+ {{ getInlineAltText(token) }}
+
+
+ {{ token }}
+
+
+
![]()
-
-
-
-
-
- {{ getInlineAltText(token) }}
-
-
- {{ token }}
-
-
-
-
@@ -74,52 +72,41 @@ export default {
diff --git a/src/layouts/payment-method/payment-method-question/payment-method-question.vue b/src/layouts/payment-method/payment-method-question/payment-method-question.vue
index d8376879..33d82adf 100644
--- a/src/layouts/payment-method/payment-method-question/payment-method-question.vue
+++ b/src/layouts/payment-method/payment-method-question/payment-method-question.vue
@@ -19,6 +19,7 @@
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import widgetFields from '@/constants/cms-widget-fields.js';
import paymentMethodListButton from './payment-method-list-button/payment-method-list-button.vue';
+import { markRaw } from 'vue';
export default {
name: 'payment-method-question',
@@ -33,7 +34,7 @@ export default {
emits: ['update:modelValue'],
data() {
return {
- paymentMethodListButton
+ paymentMethodListButton: markRaw(paymentMethodListButton)
};
},
computed: {
diff --git a/src/layouts/payment-method/payment-method.spec.js b/src/layouts/payment-method/payment-method.spec.js
index 5acf7f33..7773a132 100644
--- a/src/layouts/payment-method/payment-method.spec.js
+++ b/src/layouts/payment-method/payment-method.spec.js
@@ -48,15 +48,19 @@ function setupMocks({ customMountOptions = {}, queryString }, mainInitialState =
})
}
};
+ const cmsMixin = {
+ methods: {
+ getCmsContent: jest.fn()
+ }
+ }
mountOptions.global.plugins = [testingPinia];
- mountOptions.global.mixins = [mockMixin];
+ mountOptions.mixins = [mockMixin, cmsMixin];
const wrapper = shallowMount(paymentMethod, mountOptions);
return wrapper;
}
-
beforeEach(() => {
const store = useMainStore();
const defaultState = getDefaultState();
diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue
index ba1f761b..fee96d3a 100644
--- a/src/layouts/payment-method/payment-method.vue
+++ b/src/layouts/payment-method/payment-method.vue
@@ -10,23 +10,32 @@
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
-
-
+
+
+
+ class="subheader"
+ cmsWidgetName="SiteSubHeaderWidget" />
-
-
-
-
-
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
![Wiper Offer Logo]()
+
+
+
+
{{ wiperOfferPanel.body }}
+
+
+
@@ -69,6 +130,11 @@ import reviewDropdown from '@/layouts/payment-method/review-dropdown/review-drop
import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
import paymentMethodQuestion from '@/layouts/payment-method/payment-method-question/payment-method-question.vue';
import alert from '@/ux-components/alert/alert.vue';
+import textBlock from '@/digital-components/text-block/text-block.vue';
+import buttonQuestion from '@/digital-components/button-question/button-question.vue';
+import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
+import contactDetailsDrawer from '@/iss-components/contact-details-drawer/contact-details-drawer.vue';
+import buttonMain from '@/ux-components/button-main/button-main.vue';
// Supporting Items
import settleAllPromises from '@/helpers/layout-helper';
@@ -86,6 +152,10 @@ import { experimentSettings } from '@/constants/experiments';
import submitType from '@/constants/submit-type';
import routerParams from '@/router/router-constants/router-params';
import { supportsApplePay } from '@/helpers/browser-helper';
+import { getCartTotal } from '@/helpers/cart-helper';
+import { formatAmountInDollars } from '@/helpers/text-helper';
+import widgetFields from '@/constants/cms-widget-fields';
+import MaskaFormattedMasks from '@/constants/maska-masks';
export default {
name: 'payment-method',
@@ -97,7 +167,12 @@ export default {
reviewDropdown,
cartDropdown,
paymentMethodQuestion,
- alert
+ alert,
+ textBlock,
+ buttonQuestion,
+ textboxQuestion,
+ contactDetailsDrawer,
+ buttonMain
},
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
@@ -126,20 +201,29 @@ export default {
paymentMethod: null,
widget: {
paymentMethod: 'PaymentMethodWidget',
- paymentMethodApplePay: 'PaymentMethodWidgetApplePay'
+ paymentMethodApplePay: 'PaymentMethodWidgetApplePay',
+ amountDue: 'AmountDueCartHeaderTextWidget',
+ payAtAppointment: 'PayAtAppointmentTextWidget',
+ smsOptInHeader: 'SMSOptInHeaderWidget',
+ smsOptInQuestion: 'SMSOptInQuestionWidget',
+ smsPhoneNumber: 'SMSPhoneNumberWidget',
+ smsDisclaimer: 'SMSDisclaimerWidget',
+ wiperOffer: 'WiperOfferPanelWidget'
},
rules: {
- optionRequired: globalRules.OPTION_REQUIRED
- }
+ optionRequired: globalRules.OPTION_REQUIRED,
+ phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`
+ },
+ smsOptIn: '',
+ smsPhoneNumber: ''
};
},
computed: {
customCallToActionButtonCopy() {
switch (this.paymentMethod) {
case paymentMethods.PayNow:
- return 'Continue to checkout';
case paymentMethods.AFTERPAY:
- return 'Continue to Afterpay';
+ return 'Continue to checkout';
default:
return null;
}
@@ -156,6 +240,60 @@ export default {
},
paymentMethodWidgetName() {
return supportsApplePay() ? this.widget.paymentMethodApplePay : this.widget.paymentMethod;
+ },
+ showCartTotal() {
+ return this.mainStore.isVerified && (this.mainStore.isITAC || this.mainStore.isNoComp
+ || this.mainStore.order.lineItems?.vaps?.length > 0);
+ },
+ cartHeaderText() {
+ if (this.isPayInAdvanceDisabled) {
+ return this.getCmsContent(
+ this.widget.payAtAppointment,
+ widgetFields.TEXT_BLOCK_WIDGET.TEXT
+ );
+ } else {
+ return this.getCmsContent(
+ this.widget.amountDue,
+ widgetFields.TEXT_BLOCK_WIDGET.TEXT
+ );
+ }
+ },
+ cartTotal() {
+ return formatAmountInDollars(getCartTotal(this.mainStore.order));
+ },
+ hideSMSOptIn() {
+ return false;
+ },
+ smsOptInHeaderText() {
+ return this.getCmsContent(
+ this.widget.smsOptInHeader,
+ widgetFields.TEXT_BLOCK_WIDGET.TEXT
+ );
+ },
+ smsOptinQuestionText() {
+ return this.getCmsContent(this.widget.smsOptInQuestion, widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT);
+ },
+ smsOptinQuestionAnswers() {
+ return this.getCmsContent(this.widget.smsOptInQuestion, widgetFields.INPUT_QUESTION_WIDGET.ANSWERS) || [];
+ },
+ phoneMask() {
+ return MaskaFormattedMasks.PHONE_NUMBER;
+ },
+ offerWipers() {
+ return !this.mainStore.lineItems.vaps?.some((part) => part.partType.toLowerCase().includes('wiper'));
+ },
+ wiperOfferPanel() {
+ const wiperImage = this.getCmsContent(this.widget.wiperOffer, widgetFields.CONTENT_GROUP_WIDGET.IMAGE);
+ const wiperHeader = this.getCmsContent(this.widget.wiperOffer, widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT);
+ const wiperBody = this.getCmsContent(this.widget.wiperOffer, widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
+ const wiperEdit = this.getCmsContent(this.widget.wiperOffer, widgetFields.CONTENT_GROUP_WIDGET.FOOTER_TEXT);
+
+ return {
+ image: wiperImage,
+ header: wiperHeader,
+ body: wiperBody,
+ edit: wiperEdit
+ };
}
},
watch: {
@@ -245,7 +383,12 @@ export default {
&& contactInfoReqs);
},
initializeComponent() {
- this.paymentMethod = this.getPaymentMethodFromStore();
+ const paymentMethodFromStore = this.getPaymentMethodFromStore();
+ // SMS Opt In defaults to 'no', but we don't actually want to use it if the user hasn't saved data form this page yet
+ if (paymentMethodFromStore) {
+ this.smsOptIn = this.getSMSOptInFromStore();
+ }
+ this.smsPhoneNumber = this.getSMSPhoneFromStore();
},
getPaymentMethodFromStore() {
if (this.isPayInAdvanceDisabled) {
@@ -258,27 +401,25 @@ export default {
this.$refs.siteFooter.updateButtonText(newValue);
},
async forwardButtonAction() {
- useMainStore().savePaymentMethodChoice(this.paymentMethod);
- if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) {
- try {
- await submitWorkOrder({ submitType: submitType.SAFELITE });
- this.$router.navigate(
- this.navigationScenarios.CLICKED_FORWARD,
- this.$route
- );
- } 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}`);
+ this.mainStore.savePaymentMethodChoice(this.paymentMethod);
+ if (!this.hideSMSOptIn) {
+ const requestTextUpdates = this.smsOptIn === 'Yes';
+ this.mainStore.updateContactInfo({ requestTextUpdates });
+ if (requestTextUpdates) {
+ this.mainStore.updatePhoneNumbers({ alternative: this.smsPhoneNumber, service: this.smsPhoneNumber });
}
+ }
+ if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) {
+ await submitWorkOrder({ submitType: submitType.SAFELITE });
+ this.$router.navigate(
+ this.navigationScenarios.CLICKED_FORWARD,
+ this.$route
+ );
} else {
await saveSession({
createWorkOrderNumberForPIA: true,
- shouldAwaitSaveSessionQueue: true
+ shouldAwaitSaveSessionQueue: true,
+ bailoutOnError: true
});
this.$router.navigate(
@@ -293,10 +434,56 @@ export default {
const scenario = this.mainStore.isMobileAppointment
? this.navigationScenarios.CLICKED_BACK_MOBILE
: this.navigationScenarios.CLICKED_BACK_INSHOP;
- this.$router.navigate(
+ this.$router.navigateWithSpinner(
scenario,
this.$route
);
+ },
+ getSMSOptInFromStore() {
+ return this.mainStore.contactInfo.requestTextUpdates ? 'Yes' : 'No';
+ },
+ getSMSPhoneFromStore() {
+ return this.mainStore.contactInfo.alternativePhone ?? this.mainStore.contactInfo.servicePhone;
+ },
+ handleEditClicked(section) {
+ switch (section) {
+ case 'location':
+ this.$router.navigateWithSpinner(
+ this.navigationScenarios.EDIT_SERVICE_LOCATION,
+ this.$route
+ );
+ break;
+ case 'schedule':
+ this.$router.navigateWithSpinner(
+ this.navigationScenarios.EDIT_SCHEDULE,
+ this.$route
+ );
+ break;
+ case 'vehicle':
+ this.$router.navigateWithSpinner(
+ this.navigationScenarios.EDIT_VEHICLE,
+ this.$route
+ );
+ break;
+ case 'customer':
+ this.openContactDetailsModal();
+ break;
+ case 'wipers':
+ this.$router.navigateWithSpinner(
+ this.navigationScenarios.EDIT_WIPERS,
+ this.$route
+ );
+ break;
+ }
+ },
+ openContactDetailsModal() {
+ this.$refs.contactDetailsDrawer.openModal();
+ },
+ refreshContactDetails() {
+ this.smsPhoneNumber = this.mainStore.contactInfo.servicePhone;
+ },
+ closeContactDetailsWithoutSaving() {
+ this.smsOptIn = 'No';
}
}
};
@@ -304,20 +491,145 @@ export default {
diff --git a/src/layouts/payment-method/review-dropdown/review-block/review-block.vue b/src/layouts/payment-method/review-dropdown/review-block/review-block.vue
index 2b7cf661..1ed4ddda 100644
--- a/src/layouts/payment-method/review-dropdown/review-block/review-block.vue
+++ b/src/layouts/payment-method/review-dropdown/review-block/review-block.vue
@@ -1,34 +1,55 @@
-
+
diff --git a/src/layouts/payment-method/review-dropdown/review-sections/schedule-review/schedule-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/schedule-review/schedule-review.vue
index e0c615df..3b0a5fee 100644
--- a/src/layouts/payment-method/review-dropdown/review-sections/schedule-review/schedule-review.vue
+++ b/src/layouts/payment-method/review-dropdown/review-sections/schedule-review/schedule-review.vue
@@ -1,7 +1,8 @@
+ :content="displayContent"
+ :editLinkText="editLinkText" />
diff --git a/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.spec.js
deleted file mode 100644
index 981980d0..00000000
--- a/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.spec.js
+++ /dev/null
@@ -1,47 +0,0 @@
-// Components
-import vehicleReview from '@/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.vue';
-
-// Supporting Files
-import { shallowMount } from '@vue/test-utils';
-import { getMountOptions } from '@/helpers/unit-test-helper.js';
-
-jest.mock('@/helpers/cms-content-helper', () => ({
- fetchCmsContentForPage: () => Promise.resolve('content')
-}));
-
-function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
- const mountOptions = getMountOptions({
- router: {
- navigate: jest.fn()
- }
- });
-
- methodToRun();
-
- mountOptions.data = () => (
- initialData
- );
-
- const wrapper = shallowMount(vehicleReview, mountOptions);
- wrapper.vm.setCmsContent = jest.fn();
- return { wrapper };
-}
-
-describe('Vehicle Review Block', () => {
- test('Correctly assembles vehicle info into a display string', async () => {
- // Arrange
- const { wrapper } = getShallowMountedComponent({
- vehicle: {
- year: '2019',
- make: 'Honda',
- model: 'Odyssey'
- }
- });
-
- // Act
- await wrapper.vm.$nextTick();
-
- // Assert
- expect(wrapper.vm.displayContent).toStrictEqual(['2019 Honda Odyssey']);
- });
-});
diff --git a/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.vue
index 56bee25e..b0500009 100644
--- a/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.vue
+++ b/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.vue
@@ -1,10 +1,13 @@
+ :customHeaderText="header"
+ :content="displayContent"
+ :editLinkText="editLinkText" />