diff --git a/src/constants/insurance.js b/src/constants/insurance.js index b23e1fddd..8f8cd80fd 100644 --- a/src/constants/insurance.js +++ b/src/constants/insurance.js @@ -79,6 +79,9 @@ export function coverageTypeEnum(strCoverageType) { } } +export const parentAccountNumbers = { + CONNECT: "560636", +}; export const NON_MANAGED_SHOW_CLAIM_NUMBER_PARENTS = [ { name: "KentuckyFarmBureau", value: "223499" }, ]; diff --git a/src/fmg-components/funnel-footer/funnel-footer.vue b/src/fmg-components/funnel-footer/funnel-footer.vue index 5d8d0cd80..45cac1bbd 100644 --- a/src/fmg-components/funnel-footer/funnel-footer.vue +++ b/src/fmg-components/funnel-footer/funnel-footer.vue @@ -28,7 +28,7 @@ href="https://www.safelite.com/ccpa-privacy-policy" target="_blank" /> -

© 2025 Safelite Group

+

© {{ currentYear }} Safelite Group

@@ -40,6 +40,11 @@ export default { components: { textLink, }, + computed: { + currentYear() { + return new Date().getFullYear(); + }, + }, }; diff --git a/src/layouts/bailout-success/bailout-success.vue b/src/layouts/bailout-success/bailout-success.vue index 97f186ca6..5def1ae22 100644 --- a/src/layouts/bailout-success/bailout-success.vue +++ b/src/layouts/bailout-success/bailout-success.vue @@ -13,7 +13,8 @@ id="btn-vehicle-not-listed" :isPrimary="true" :buttonText="ReturnToHomeButtonText" - class="mb-3" + loaderColor="white" + class="w-100 mb-3" @click-event="forwardButtonAction" /> @@ -27,6 +28,8 @@ import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import buttonMain from "@/ux-components/button-main/button-main"; import store from "@/store"; +import baseMixin from "@/mixins/base-mixin.js"; +import { storeActions } from "@/constants/store-actions"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { settleAllPromises } from "@/helpers/layout-helper"; @@ -39,6 +42,9 @@ export default { }, async beforeRouteEnter(to, from, next) { + // Clear order + await baseMixin.methods.dispatchStoreAction(storeActions.CREATE_SUBMITTED_STATE); + // Call APIs const cmsContentPromise = fetchCmsContentForPage(to.name); @@ -67,10 +73,11 @@ export default { }, arePagePrerequisitesValid() { return ( - store.getters.order.customer.firstName && - store.getters.order.customer.lastName && - store.getters.order.customer.emailAddress && - store.getters.order.customer.phoneNumber + (store.getters.order.customer.firstName && + store.getters.order.customer.lastName && + store.getters.order.customer.emailAddress && + store.getters.order.customer.phoneNumber) || + baseMixin.methods.hasSubmittedOrder() ); }, }, diff --git a/src/layouts/bailout/bailout.spec.js b/src/layouts/bailout/bailout.spec.js index 905f9e5a0..f71899e49 100644 --- a/src/layouts/bailout/bailout.spec.js +++ b/src/layouts/bailout/bailout.spec.js @@ -36,9 +36,21 @@ describe("bailout.vue", () => { expect(wrapper.findComponent({ name: "navbar" }).exists()).toBe(true); }); + test("arePagePrerequisitesValid should be false ", async () => { + //Arrange + const { wrapper } = setupMocks(); + + //Act + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(arePagePrerequisitesValid).toBe(false); + }); + test("arePagePrerequisitesValid should be true ", async () => { //Arrange const { wrapper } = setupMocks(); + wrapper.vm.getBailoutCodeFromStore = jest.fn().mockReturnValue("BAILOUT_CODE"); //Act let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); diff --git a/src/layouts/bailout/bailout.vue b/src/layouts/bailout/bailout.vue index ae5600e08..7c5edf07c 100644 --- a/src/layouts/bailout/bailout.vue +++ b/src/layouts/bailout/bailout.vue @@ -43,6 +43,8 @@ validationRules="phone-number-required" />
- - +
+ + +
+
+ + + + + +
+
+ +
+ + +
+
+
+ + + + + +
+ + + diff --git a/src/layouts/coverage-statement/customer-instructions/customer-instructions.vue b/src/layouts/coverage-statement/customer-instructions/customer-instructions.vue new file mode 100644 index 000000000..c584c0c19 --- /dev/null +++ b/src/layouts/coverage-statement/customer-instructions/customer-instructions.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/src/layouts/coverage-statement/price-display/price-display.vue b/src/layouts/coverage-statement/price-display/price-display.vue new file mode 100644 index 000000000..23d0ca3f2 --- /dev/null +++ b/src/layouts/coverage-statement/price-display/price-display.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/src/layouts/policy-vehicle/policy-vehicle.spec.js b/src/layouts/policy-vehicle/policy-vehicle.spec.js index 1fe1a5559..d11777667 100644 --- a/src/layouts/policy-vehicle/policy-vehicle.spec.js +++ b/src/layouts/policy-vehicle/policy-vehicle.spec.js @@ -50,11 +50,18 @@ function setupMocks() { FunnelHeaderWidget: { Text: "Header" }, FunnelSubHeaderWidget: { Text: "Subheader" }, FunnelFooterWidget: { Text: "Footer" }, + VehicleNotListedWidget: { Text: "Vehicle Not Listed" }, + CancelVerificationWidget: { Text: "Cancel Verification" }, + AmFamDisclaimerWidget: { Text: "Disclaimer" }, }; fetchCmsContentForPage.mockResolvedValue(mockCmsContent); settleAllPromises.mockResolvedValue({ cmsContent: mockCmsContent }); + const getCmsContentMock = jest.fn().mockImplementation((widgetName, cmsFieldName) => { + return mockCmsContent[widgetName][cmsFieldName]; + }); + const mountOptions = getMountOptions({ route: { name: "policy-vehicle", query: {}, params: {} }, router: { @@ -64,7 +71,13 @@ function setupMocks() { }, }); + mountOptions.global = mountOptions.global || {}; + mountOptions.global.mocks = { + ...(mountOptions.global.mocks || {}), + getCmsContent: getCmsContentMock, + }; + const wrapper = shallowMount(policyVehicle, mountOptions); - return { wrapper }; + return { wrapper, getCmsContentMock }; } diff --git a/src/layouts/policy-vehicle/policy-vehicle.vue b/src/layouts/policy-vehicle/policy-vehicle.vue index 954b04bc3..2b87e6692 100644 --- a/src/layouts/policy-vehicle/policy-vehicle.vue +++ b/src/layouts/policy-vehicle/policy-vehicle.vue @@ -4,16 +4,31 @@
- - + + + + + + + +
@@ -24,6 +39,11 @@ import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import navbar from "@/fmg-components/nav-bar/nav-bar"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; +import store from "@/store"; +import buttonMain from "@/ux-components/button-main/button-main"; +import textLink from "@/ux-components/text-link/text-link.vue"; +import { parentAccountNumbers } from "@/constants/insurance"; + import { Form } from "vee-validate"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; @@ -40,6 +60,8 @@ export default { funnelHeader, navbar, funnelSubHeader, + textLink, + buttonMain, }, // Ensure CMS content is fetched during route navigation without depending on `to`/`from` async beforeRouteEnter(to, from, next) { @@ -57,7 +79,34 @@ export default { }); }, + computed: { + vehicleNotListedQuestionText() { + return this.getCmsContent("VehicleNotListedWidget", "Text"); + }, + cancelVerificationCopy() { + return this.getCmsContent("CancelVerificationWidget", "Text"); + }, + amFamDisclaimerWidget() { + return this.getCmsContent("AmFamDisclaimerWidget", "Text"); + }, + showAmFamDisclaimer() { + return this.parentAccountNumberFromStore() === this.parentAccountNumbers.CONNECT; + }, + parentAccountNumbers() { + return parentAccountNumbers; + }, + }, + methods: { + parentAccountNumberFromStore() { + return store.getters.order?.payment?.parentAccountNumber; + }, + cancelVerificationAction() { + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_CANCEL_VERIFICATION, + this.pageName + ); + }, backButtonAction() { this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_BACK, @@ -76,3 +125,10 @@ export default { }, }; + + diff --git a/src/router/constants/navigation-scenarios.js b/src/router/constants/navigation-scenarios.js index e4aac41c1..8112cb98e 100644 --- a/src/router/constants/navigation-scenarios.js +++ b/src/router/constants/navigation-scenarios.js @@ -12,6 +12,7 @@ const navigationScenarios = { CLICKED_FORWARD: "CLICKED_FORWARD", CLICKED_FORWARD_WITH_CASH: "CLICKED_FORWARD_WITH_CASH", CLICKED_FORWARD_WITH_INSURANCE: "CLICKED_FORWARD_WITH_INSURANCE", + CLICKED_CANCEL_VERIFICATION: "CLICKED_CANCEL_VERIFICATION", // Bailout BAILOUT: "BAILOUT", diff --git a/src/router/constants/routing-table.js b/src/router/constants/routing-table.js index 877802995..fcd259790 100644 --- a/src/router/constants/routing-table.js +++ b/src/router/constants/routing-table.js @@ -1,5 +1,6 @@ import { routeData } from "@/router/constants/routes"; import { navigationScenarios } from "@/router/constants/navigation-scenarios"; +import { FUNNEL_START_PAGE } from "@/router/constants/routes"; import store from "@/store"; import { paymentMethods } from "@/constants/payment-method-constants"; @@ -88,6 +89,10 @@ const routingTable = function () { scenario: navigationScenarios.CLICKED_VIN_RETRY, destinationPageData: routeData.ESTIMATE, }, + { + scenario: navigationScenarios.BAILOUT, + destinationPageData: routeData.BAILOUT, + }, ], }, { @@ -128,6 +133,10 @@ const routingTable = function () { scenario: navigationScenarios.CLICKED_VIN_RETRY, destinationPageData: routeData.ESTIMATE, }, + { + scenario: navigationScenarios.BAILOUT, + destinationPageData: routeData.BAILOUT, + }, ], }, { @@ -483,6 +492,10 @@ const routingTable = function () { scenario: navigationScenarios.CLICKED_FORWARD, destinationPageData: routeData.POLICY_DRIVER, }, + { + scenario: navigationScenarios.CLICKED_CANCEL_VERIFICATION, + destinationPageData: routeData.INSURANCE_COMPANY, + }, ], }, { @@ -820,7 +833,7 @@ const routingTable = function () { maps: [ { scenario: navigationScenarios.CLICKED_BACK_TO_HOMEPAGE, - destinationPageData: routeData.RESTART, + destinationPageData: FUNNEL_START_PAGE, }, ], }, diff --git a/src/router/methods/before-each.js b/src/router/methods/before-each.js index 237014ee6..568cf312c 100644 --- a/src/router/methods/before-each.js +++ b/src/router/methods/before-each.js @@ -76,14 +76,27 @@ export async function beforeEach(to, from) { } // Block navigation if an order has been submitted. - if (window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE) !== null) { - const exceptionPages = [FUNNEL_START_PAGE.name, routeData.CONFIRMATION.name]; + const submittedState = window.sessionStorage.getItem( + sessionStorageKeyConstants.SUBMITTED_STATE + ); + if (submittedState !== null) { + const isBailout = getIsBailout(submittedState); + const exceptionPages = isBailout + ? [FUNNEL_START_PAGE.name, routeData.BAILOUT_SUCCESS.name] + : [FUNNEL_START_PAGE.name, routeData.CONFIRMATION.name]; if (!exceptionPages.some((name) => to.name === name) && !isVirtualRoute(to.name)) { - router.push({ - name: routeData.CONFIRMATION.name, - }); - return false; + if (isBailout) { + router.push({ + name: routeData.BAILOUT_SUCCESS.name, + }); + return false; + } else { + router.push({ + name: routeData.CONFIRMATION.name, + }); + return false; + } } } @@ -142,3 +155,8 @@ export async function beforeEach(to, from) { return; } } + +function getIsBailout(submittedState) { + const submittedStateObj = JSON.parse(submittedState); + return !!submittedStateObj?.applicationUser?.bailoutCode; +} diff --git a/src/router/methods/navigate.js b/src/router/methods/navigate.js index 1cdd87aac..63e20d96c 100644 --- a/src/router/methods/navigate.js +++ b/src/router/methods/navigate.js @@ -1,7 +1,8 @@ -import { saveSession } from "@/helpers/heritage-integration/order-helper"; +import { saveSession, submitBailout } from "@/helpers/heritage-integration/order-helper"; import { buildManualUrl } from "@/router/methods/helpers/build-manual-url"; import { getDestination } from "@/router/methods/helpers/get-destination"; import { savePageData } from "@/router/methods/helpers/save-page-data"; +import { navigationScenarios } from "@/router/constants/navigation-scenarios"; import router from "@/router"; import store from "@/store"; @@ -39,7 +40,14 @@ async function navigate(scenario, currentPageName, withSaving = false, forceTopL store.getters?.applicationUser?.savedSessionId || store.getters?.order?.customer?.emailAddress ) { - await saveSession({ pageNameToLog: nextPage.name }); + if ( + scenario.toUpperCase() === navigationScenarios.CLICKED_FORWARD && + currentPageName.toUpperCase() === navigationScenarios.BAILOUT + ) { + await submitBailout({ pageNameToLog: nextPage.name }); + } else { + await saveSession({ pageNameToLog: nextPage.name }); + } } }