diff --git a/environment-variables.js b/environment-variables.js index 17c797cfd..55ffdf54e 100644 --- a/environment-variables.js +++ b/environment-variables.js @@ -15,6 +15,7 @@ const environmentVariables = { ['__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__']: "", ['__VUE_APP_ADYEN_ENVIRONMENT__']: "test", ['__VUE_APP_ADYEN_CLIENT_KEY__']: "test_WYGT4F5ZT5BRRL5MPWHK6QLYOIXZXROD", + ['__VUE_APP_SESSION_EXPIRATION_INTERVAL_CHECK_MILLISECONDS__']: 60000, }; const keysOnly = Object.keys(environmentVariables); diff --git a/jest.config.js b/jest.config.js index a8063f324..7da5d3cd2 100644 --- a/jest.config.js +++ b/jest.config.js @@ -33,19 +33,20 @@ module.exports = { "!src/layouts/payment-pia-return/*.vue", // Temp test exclusion while in development "!src/layouts/insurance/*.vue", // Temp test exclusion while in development "!src/layouts/insurance-company/*.vue", // Temp test exclusion while in development - "!src/digital-components/date-picker/**/*.vue", // Temp test exclusion while in development + "!src/layouts/policy-info/*.vue", + "!src/layouts/policy-vehicle/*.vue", + "!src/layouts/policy-driver/*.vue", + "!src/layouts/duplicate-check/*.vue", + "!src/layouts/endorsements/*.vue", + "!src/layouts/policy-info-submitted/*.vue", + "!src/layouts/recalibration-info/*.vue", + "!src/layouts/coverage-statement/*.vue", + "!src/layouts/insurance-details/*.vue", + "!src/layouts/verify-details/*.vue", "!src/layouts/insurance-company/insurance-company-question/*.vue", // Temp test exclusion while in development "!src/experiment-components/*.vue", - // END ], // ! means exclude from coverage. testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], - coverageThreshold: { - global: { - statements: 68, - }, - }, - // Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit - //silent: true, }; process.env = Object.assign(process.env, environmentVariablesWithDefaults); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2e45411d6..d920027d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@adyen/adyen-web": "^6.27.0", "@iframe-resizer/child": "^5.3.3", + "@vuepic/vue-datepicker": "^12.1.0", "axios": "^0.30.2", "bootstrap": "^5.3.3", "core-js": "^3.38.1", @@ -1910,6 +1911,11 @@ "dev": true, "license": "MIT" }, + "node_modules/@date-fns/tz": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz", + "integrity": "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==" + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -2045,6 +2051,63 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==" + }, + "node_modules/@floating-ui/vue": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@floating-ui/vue/-/vue-1.1.11.tgz", + "integrity": "sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw==", + "dependencies": { + "@floating-ui/dom": "^1.7.6", + "@floating-ui/utils": "^0.2.11", + "vue-demi": ">=0.13.0" + } + }, + "node_modules/@floating-ui/vue/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -3572,6 +3635,11 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==" + }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", @@ -4536,6 +4604,58 @@ "dev": true, "license": "MIT" }, + "node_modules/@vuepic/vue-datepicker": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-12.1.0.tgz", + "integrity": "sha512-QuWcO+CqIGYFoRNCagp9xUY9sMK/OHUlVIDxBYjw7HjCTWXfuE/r3l3loB00faEtb0Teo3DeBn26hT3tYA5pgg==", + "dependencies": { + "@date-fns/tz": "^1.4.1", + "@floating-ui/vue": "^1.1.9", + "@vueuse/core": "^14.1.0", + "date-fns": "^4.1.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "vue": ">=3.5.0" + } + }, + "node_modules/@vueuse/core": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.2.1.tgz", + "integrity": "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "14.2.1", + "@vueuse/shared": "14.2.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/metadata": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.2.1.tgz", + "integrity": "sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.2.1.tgz", + "integrity": "sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -6693,6 +6813,15 @@ "node": ">=10" } }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", diff --git a/package.json b/package.json index c55259920..2db948652 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dependencies": { "@adyen/adyen-web": "^6.27.0", "@iframe-resizer/child": "^5.3.3", + "@vuepic/vue-datepicker": "^12.1.0", "axios": "^0.30.2", "bootstrap": "^5.3.3", "core-js": "^3.38.1", diff --git a/src/App.vue b/src/App.vue index 2b9bc5a33..36c4b58a3 100644 --- a/src/App.vue +++ b/src/App.vue @@ -18,6 +18,8 @@ import { showFmgLoadingModal } from "@/helpers/loading-modal-helper"; import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer.vue"; import salesforceWebchat from "./digital-components/salesforce-webchat/salesforce-webchat.vue"; import sierraWebchat from "./digital-components/sierra-webchat/sierra-webchat.vue"; +import analyticsMixin from "@/mixins/analytics-mixin"; +import { applicationConfig } from "@/constants/application-config"; export default { name: "app", @@ -25,8 +27,18 @@ export default { const { globalNonpersistedState } = showFmgLoadingModal(); return { globalNonpersistedState }; }, + data() { + return { + sessionCheckInterval: null, + }; + }, methods: { handleAnyComponentFocus: handleAnyComponentFocus, + checkSessionAndRedirect() { + if (analyticsMixin.methods.sessionExpired()) { + this.$router.sendToReturnUser(); + } + }, }, computed: { shouldShowLoader() { @@ -44,6 +56,16 @@ export default { }, mounted() { showFmgLoadingModal(true); + // Check session expiration and redirect if expired + this.sessionCheckInterval = setInterval( + this.checkSessionAndRedirect, + applicationConfig.SESSION_EXPIRATION_INTERVAL_CHECK_MILLISECONDS + ); + }, + beforeUnmount() { + if (this.sessionCheckInterval) { + clearInterval(this.sessionCheckInterval); + } }, }; diff --git a/src/constants/application-config.js b/src/constants/application-config.js index 91873d455..c64ae0db6 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -31,6 +31,8 @@ const applicationConfig = { AFFILIATE_COOKIE_CONTAINING_NAME: "_Track", COOKIE_NAME_LENGTH_MAX_LIMIT: 44, SESSION_TIMEOUT_MINUTES: process.env.__VUE_APP_SESSION_TIMEOUT_MINUTES__, + SESSION_EXPIRATION_INTERVAL_CHECK_MILLISECONDS: + process.env.__VUE_APP_SESSION_EXPIRATION_INTERVAL_CHECK_MILLISECONDS__, RETURN_USER_PAGE: "/fmg/return-user", ADYEN_CLIENT_KEY: process.env.__VUE_APP_ADYEN_CLIENT_KEY__, ADYEN_ENVIRONMENT: process.env.__VUE_APP_ADYEN_ENVIRONMENT__, diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index ec8ab4c86..9adfc0613 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -61,7 +61,7 @@ const endpoints = { method: "POST", }, GetWipers: { - url: "/parts/api/v1/parts/wipers", + url: "/parts/api/v2/parts/wipers", method: "GET", }, GetRainRepel: { @@ -69,7 +69,7 @@ const endpoints = { method: "GET", }, GetMobileFeePart: { - url: "/parts/api/v1/parts/mobile-fee", + url: "/parts/api/v2/parts/mobile-fee", method: "GET", }, GetPricingByDayPart: { diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index 8b8c98881..6899c2aec 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -38,6 +38,12 @@ const errorMessages = { STYLE_REQUIRED: "Please select your vehicle style", PROMO_REQUIRED: "Please enter a promo code", INSURANCE_COMPANY_REQUIRED: "Please select an insurance company", + INSURANCE_COMPANY_NAME_REQUIRED: "Please enter your insurance company name", + POLICY_NUMBER_REQUIRED: "Please enter your policy number", + DATE_OF_LOSS_REQUIRED: "Please enter your date of damage", + DAMAGE_TYPES_REQUIRED: "How damage occurred is required", + ZIP_CODE_REQUIRED: "Please enter your ZIP code", + ZIP_CODE_FORMAT: "Zip must be 5 digits", }; export { errorMessages }; diff --git a/src/constants/experiments.js b/src/constants/experiments.js index 97e049df0..26c7b07ad 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -47,6 +47,10 @@ const experimentSettings = { USE_ADYEN_PAYMENT: "UseAdyenPayment", SHOW_UNVERIFIED_DEDUCT_ENTRY: "ShowUnverifiedDeducEntry", SERVICE_PACKAGE_ORDER: "ServicePackageOrder", + + // Claim and Coverage for 2.0 + ENABLE_NON_CLAIM_AND_COVERAGE_FLOW: "EnableNonC&CFlow", + NON_CLAIM_AND_COVERAGE_TEST_PARENT_ACCOUNT: "NonC&CTestParentAccount", }; const experimentTriggers = { diff --git a/src/constants/progress-bar-mapper.js b/src/constants/progress-bar-mapper.js index b21c6c9c7..3293c067c 100644 --- a/src/constants/progress-bar-mapper.js +++ b/src/constants/progress-bar-mapper.js @@ -52,6 +52,42 @@ export const pageProgressMapper = { percent: 55, step: 2, }, + "insurance-details": { + percent: 55, + step: 2, + }, + "duplicate-check": { + percent: 55, + step: 2, + }, + "policy-vehicle": { + percent: 55, + step: 2, + }, + "policy-driver": { + percent: 55, + step: 2, + }, + endorsements: { + percent: 55, + step: 2, + }, + "policy-info-submitted": { + percent: 55, + step: 2, + }, + "recalibration-info": { + percent: 55, + step: 2, + }, + "coverage-statement": { + percent: 55, + step: 2, + }, + "verify-details": { + percent: 55, + step: 2, + }, quote: { percent: 60, step: 2, diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index fff009619..702f7c737 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -99,6 +99,9 @@ const storeActions = { SAVE_PAYMENT_TYPE: "savePaymentType", SAVE_PAYMENT_METHOD_CHOICE: "savePaymentMethodChoice", SAVE_PARENT_ACCOUNT_NUMBER: "saveParentAccountNumber", + SAVE_ACCOUNT_NAME: "saveAccountName", + SAVE_IS_CLAIM_AND_COVERAGE: "saveIsClaimAndCoverage", + SAVE_CAN_SCHEDULE_ONLINE: "saveCanScheduleOnline", SAVE_BILL_TO_ACCOUNT_NUMBER: "saveBillToAccountNumber", SAVE_SUPPORTING_ITEMS: "saveSupportingItems", SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING: @@ -106,6 +109,8 @@ const storeActions = { SAVE_VAPS: "saveVaps", SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS: "saveActiveAndOrInactivePromos", SAVE_CUSTOMER_DETAILS: "saveCustomerDetails", + SAVE_INSURANCE_DETAILS: "saveInsuranceDetails", + SAVE_DAMAGE_DETAILS: "saveDamageDetails", SAVE_SERVICE_LOCATION_TECH_NOTES: "saveServiceLocationTechNotes", SAVE_CCTOKEN: "saveCCToken", SAVE_PAYPAL_TOKEN: "savePaypalToken", diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index b5a471a79..c43e737d3 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -51,12 +51,19 @@ const storeMutations = { UPDATE_CUSTOMER_DETAILS: "updateCustomerDetails", UPDATE_CUSTOMER_WAITLIST_REQUESTED: "updateCustomerWaitListRequested", + // INSURANCE / DAMAGE MUTATIONS + UPDATE_INSURANCE_DETAILS: "updateInsuranceDetails", + UPDATE_DAMAGE_DETAILS: "updateDamageDetails", + // ORDER MUTATIONS UPDATE_REFERRAL_NUMBER: "updateReferralNumber", UPDATE_REFERRAL_SEQUENCE_NUMBER: "updateReferralSequenceNumber", UPDATE_REFERRAL_DATE: "updateReferralDate", UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId", UPDATE_PARENT_ACCT_NUMBER: "updateParentAcctNumber", + UPDATE_ACCOUNT_NAME: "updateAccountName", + UPDATE_IS_CLAIM_AND_COVERAGE: "updateIsClaimAndCoverage", + UPDATE_CAN_SCHEDULE_ONLINE: "updateCanScheduleOnline", UPDATE_BILL_TO_ACCT_NUMBER: "updateBillToAcctNumber", UPDATE_EON: "updateEON", UPDATE_IS_INSURANCE: "updateIsInsurance", diff --git a/src/digital-components/date-picker-popup/date-picker-popup.vue b/src/digital-components/date-picker-popup/date-picker-popup.vue new file mode 100644 index 000000000..3c666e775 --- /dev/null +++ b/src/digital-components/date-picker-popup/date-picker-popup.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/src/layouts/confirmation/confirmation.vue b/src/layouts/confirmation/confirmation.vue index e26c5f9b1..70ef3b25d 100644 --- a/src/layouts/confirmation/confirmation.vue +++ b/src/layouts/confirmation/confirmation.vue @@ -169,8 +169,8 @@ export default { const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_WIPERS, { - serviceZipCode: submittedOrder.serviceLocation.zipCode, carId: submittedOrder.vehicle.carId, + accountNumber: submittedOrder.payment?.parentAccountNumber, }, "confirmation" ); diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js new file mode 100644 index 000000000..2d4fd3f8d --- /dev/null +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -0,0 +1,70 @@ +import coverageStatement from "@/layouts/coverage-statement/coverage-statement.vue"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { settleAllPromises } from "@/helpers/layout-helper"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +describe("coverage-statement.vue", () => { + describe("component rendering", () => { + test("renders funnelHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelHeader" }).exists()).toBe(true); + }); + + test("renders funnelSubHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelSubHeader" }).exists()).toBe(true); + }); + + test("renders navbar component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "navbar" }).exists()).toBe(true); + }); + + test("renders Form component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "Form" }).exists()).toBe(true); + }); + }); + + describe("methods", () => { + test("arePagePrerequisitesValid returns true", () => { + const { wrapper } = setupMocks(); + expect(wrapper.vm.arePagePrerequisitesValid()).toBe(true); + }); + }); +}); + +function setupMocks() { + const mockCmsContent = { + FunnelHeaderWidget: { Text: "Header" }, + FunnelSubHeaderWidget: { Text: "Subheader" }, + FunnelFooterWidget: { Text: "Footer" }, + }; + + fetchCmsContentForPage.mockResolvedValue(mockCmsContent); + settleAllPromises.mockResolvedValue({ cmsContent: mockCmsContent }); + + const mountOptions = getMountOptions({ + route: { name: "duplicate-check", query: {}, params: {} }, + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + }); + + const wrapper = shallowMount(coverageStatement, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue new file mode 100644 index 000000000..4e4dd4cc0 --- /dev/null +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -0,0 +1,103 @@ + + + diff --git a/src/layouts/duplicate-check/duplicate-check.spec.js b/src/layouts/duplicate-check/duplicate-check.spec.js new file mode 100644 index 000000000..e28a749e6 --- /dev/null +++ b/src/layouts/duplicate-check/duplicate-check.spec.js @@ -0,0 +1,70 @@ +import duplicateCheck from "@/layouts/duplicate-check/duplicate-check.vue"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { settleAllPromises } from "@/helpers/layout-helper"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +describe("duplicate-check.vue", () => { + describe("component rendering", () => { + test("renders funnelHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelHeader" }).exists()).toBe(true); + }); + + test("renders funnelSubHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelSubHeader" }).exists()).toBe(true); + }); + + test("renders navbar component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "navbar" }).exists()).toBe(true); + }); + + test("renders Form component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "Form" }).exists()).toBe(true); + }); + }); + + describe("methods", () => { + test("arePagePrerequisitesValid returns true", () => { + const { wrapper } = setupMocks(); + expect(wrapper.vm.arePagePrerequisitesValid()).toBe(true); + }); + }); +}); + +function setupMocks() { + const mockCmsContent = { + FunnelHeaderWidget: { Text: "Header" }, + FunnelSubHeaderWidget: { Text: "Subheader" }, + FunnelFooterWidget: { Text: "Footer" }, + }; + + fetchCmsContentForPage.mockResolvedValue(mockCmsContent); + settleAllPromises.mockResolvedValue({ cmsContent: mockCmsContent }); + + const mountOptions = getMountOptions({ + route: { name: "duplicate-check", query: {}, params: {} }, + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + }); + + const wrapper = shallowMount(duplicateCheck, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/duplicate-check/duplicate-check.vue b/src/layouts/duplicate-check/duplicate-check.vue new file mode 100644 index 000000000..aa1f80bb9 --- /dev/null +++ b/src/layouts/duplicate-check/duplicate-check.vue @@ -0,0 +1,78 @@ + + + diff --git a/src/layouts/endorsements/endorsements.spec.js b/src/layouts/endorsements/endorsements.spec.js new file mode 100644 index 000000000..a44302072 --- /dev/null +++ b/src/layouts/endorsements/endorsements.spec.js @@ -0,0 +1,70 @@ +import endorsements from "@/layouts/endorsements/endorsements.vue"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { settleAllPromises } from "@/helpers/layout-helper"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +describe("endorsements.vue", () => { + describe("component rendering", () => { + test("renders funnelHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelHeader" }).exists()).toBe(true); + }); + + test("renders funnelSubHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelSubHeader" }).exists()).toBe(true); + }); + + test("renders navbar component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "navbar" }).exists()).toBe(true); + }); + + test("renders Form component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "Form" }).exists()).toBe(true); + }); + }); + + describe("methods", () => { + test("arePagePrerequisitesValid returns true", () => { + const { wrapper } = setupMocks(); + expect(wrapper.vm.arePagePrerequisitesValid()).toBe(true); + }); + }); +}); + +function setupMocks() { + const mockCmsContent = { + FunnelHeaderWidget: { Text: "Header" }, + FunnelSubHeaderWidget: { Text: "Subheader" }, + FunnelFooterWidget: { Text: "Footer" }, + }; + + fetchCmsContentForPage.mockResolvedValue(mockCmsContent); + settleAllPromises.mockResolvedValue({ cmsContent: mockCmsContent }); + + const mountOptions = getMountOptions({ + route: { name: "duplicate-check", query: {}, params: {} }, + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + }); + + const wrapper = shallowMount(endorsements, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/endorsements/endorsements.vue b/src/layouts/endorsements/endorsements.vue new file mode 100644 index 000000000..d43251901 --- /dev/null +++ b/src/layouts/endorsements/endorsements.vue @@ -0,0 +1,78 @@ + + + diff --git a/src/layouts/insurance-company/insurance-company-question.vue b/src/layouts/insurance-company/insurance-company-question.vue index 4d33661c8..c0ce6a2cc 100644 --- a/src/layouts/insurance-company/insurance-company-question.vue +++ b/src/layouts/insurance-company/insurance-company-question.vue @@ -35,7 +35,7 @@ export default { name: "insurance-company-question", props: { originalList: Array, - modelValue: String, + modelValue: Object, validationRules: String, }, data() { @@ -44,12 +44,13 @@ export default { }; }, computed: { - selectedAccountNumber: { + selectedAccount: { get: function () { - return this.modelValue?.toString(); + return this.modelValue; }, set: function (newValue) { - this.$emit("update:modelValue", newValue); // send data up to v-model on parent, s/b account number + this.selectedAccountName = newValue?.accountName; + this.$emit("update:modelValue", newValue); }, }, searchableInsuranceCompanyList() { @@ -71,15 +72,15 @@ export default { }, }, methods: { - getParentAccountNumber(name) { + getAccount(name) { const matchedItems = this.searchableInsuranceCompanyList?.filter((item) => { return item.accountName?.toString() === name.toString(); }); if (matchedItems.length > 0) { - return matchedItems[0].parentAccountNumber; + return matchedItems[0]; } else { - console.error("Error locating accountNumber"); + console.error("Error locating accountNumber" + name); return; } }, @@ -91,7 +92,7 @@ export default { if (matchedItems.length > 0) { return matchedItems[0].accountName; } else { - console.error("Error locating accountName"); + console.error("Error locating accountName" + number); return; } }, @@ -128,19 +129,18 @@ export default { console.error("No insurance companies found"); return; } + if (parentAccountName) { - const parentAccountNumber = this.getParentAccountNumber(parentAccountName); - this.selectedAccountNumber = parentAccountNumber; - this.selectedAccountName = this.getParentAccountName(parentAccountNumber); + this.selectedAccount = this.getAccount(parentAccountName); } else { - this.selectedAccountNumber = ""; this.selectedAccountName = ""; } }, }, mounted() { - if (this.modelValue.length > 0) { - this.selectedAccountName = this.getParentAccountName(this.modelValue?.toString()); + const parentAccountNumber = this.modelValue?.parentAccountNumber; + if (parentAccountNumber && parentAccountNumber.length > 0) { + this.selectedAccountName = this.getParentAccountName(parentAccountNumber.toString()); } const select = this.selectInsuranceCompany; diff --git a/src/layouts/insurance-company/insurance-company.vue b/src/layouts/insurance-company/insurance-company.vue index 1455847bd..c97a8589a 100644 --- a/src/layouts/insurance-company/insurance-company.vue +++ b/src/layouts/insurance-company/insurance-company.vue @@ -6,11 +6,10 @@
-
@@ -59,6 +58,7 @@ import store from "@/store"; import { flushSaveSessionQueue } from "@/helpers/heritage-integration/order-helper"; import { errorMessages } from "@/constants/error-messages"; import { required, regex } from "@/helpers/validation-rules"; +import { debugLog } from "@/helpers/debug-log-helper"; defineRule("insurance-company-required", required(errorMessages.INSURANCE_COMPANY_REQUIRED)); @@ -117,13 +117,18 @@ export default { data() { return { - parentAccountNumber: this.parentAccountNumberFromStore(), + selectedAccount: { + parentAccountNumber: this.parentAccountNumberFromStore(), + accountName: this.accountNameFromStore(), + isClaimAndCoverage: this.isClaimAndCoverageFromStore(), + canScheduleOnline: this.canScheduleOnlineFromStore(), + }, originalList: [], }; }, computed: { isParentAccountNumber() { - return !!this.parentAccountNumber; + return !!this.selectedAccount.parentAccountNumber; }, payWithCashButtonCopy() { return this.getCmsContent("PayWithCashWidget", "Text"); @@ -142,6 +147,15 @@ export default { : ""; return accountNumber; }, + accountNameFromStore() { + return store.getters.order?.payment?.accountName; + }, + isClaimAndCoverageFromStore() { + return store.getters.order?.payment?.isClaimAndCoverage; + }, + canScheduleOnlineFromStore() { + return store.getters.order?.payment?.canScheduleOnline; + }, arePagePrerequisitesValid() { return store.getters.order.payment.isInsurance === true; }, @@ -168,7 +182,25 @@ export default { await this.dispatchStoreAction( this.storeActions.SAVE_PARENT_ACCOUNT_NUMBER, - this.parentAccountNumber.toString(), + this.selectedAccount.parentAccountNumber.toString(), + false + ); + + await this.dispatchStoreAction( + this.storeActions.SAVE_ACCOUNT_NAME, + this.selectedAccount.accountName, + false + ); + + await this.dispatchStoreAction( + this.storeActions.SAVE_IS_CLAIM_AND_COVERAGE, + this.selectedAccount.isClaimAndCoverage, + false + ); + + await this.dispatchStoreAction( + this.storeActions.SAVE_CAN_SCHEDULE_ONLINE, + this.selectedAccount.canScheduleOnline, false ); @@ -187,6 +219,75 @@ export default { //Reload page when navigate with browser back button window.addEventListener("pageshow", this.handlePageShow); + //TODO: Where to send if can schedule online is false? + if (!this.selectedAccount.canScheduleOnline) { + debugLog( + `--- ${this.selectedAccount.parentAccountNumber} Can schedule online is false, sending to vue app Insurance Details page ---` + ); + } + + // hasClaimAndCoverage in experiment-mixin.js checks if the parent account number is in the experiment settings. + const isClaimAndCoverageExperimentActive = this.hasClaimAndCoverage( + this.selectedAccount.parentAccountNumber + ); + + // C&C experiment active for this parent account number, send to vue app Policy Info page + if (isClaimAndCoverageExperimentActive) { + debugLog( + `--- ${this.selectedAccount.parentAccountNumber} C&C experiment active for this parent account number, sending to vue app Policy Info page ---` + ); + this.$router.navigateWithSaving( + this.navigationScenarios.CLICKED_FORWARD_POLICY_INFO, + this.pageName + ); + return; + } + + // C&C experiment setting is false, but is a C&C client, send to heritage + if (this.selectedAccount.isClaimAndCoverage) { + debugLog( + `--- ${this.selectedAccount.parentAccountNumber} C&C experiment setting is false, but is a C&C client, sending to heritage ---` + ); + navigateToHeritageFunnel({ + shouldSaveSession: true, + pageNameToLog: this.pageName, + }); + return; + } + + // Non integrated experiment setting is true, send to new insurance details page + if ( + this.hasSettingEqualTo( + experimentSettings.ENABLE_NON_CLAIM_AND_COVERAGE_FLOW, + "true" + ) + ) { + debugLog( + `--- ${this.selectedAccount.parentAccountNumber} Non integrated experiment setting is true, sending to vue app Insurance Details page ---` + ); + this.$router.navigateWithSaving( + this.navigationScenarios.CLICKED_FORWARD_NON_CLAIM_AND_COVERAGE, + this.pageName + ); + return; + } + + // Non integrated experiment setting is false, but a parent account is NON_CLAIM_AND_COVERAGE_TEST_PARENT_ACCOUNT experiment + // contains a specific parent account number you wish to send to the veu app insurance details page + var nonIntegratedTestParentAccount = this.getSettingValue( + experimentSettings.NON_CLAIM_AND_COVERAGE_TEST_PARENT_ACCOUNT + ); + if (nonIntegratedTestParentAccount === this.selectedAccount.parentAccountNumber) { + debugLog( + `--- ${this.selectedAccount.parentAccountNumber} Non integrated experiment setting is false, but a parent account is NON_CLAIM_AND_COVERAGE_TEST_PARENT_ACCOUNT experiment contains a specific parent account number, sending to vue app Insurance Details page ---` + ); + this.$router.navigateWithSaving( + this.navigationScenarios.CLICKED_FORWARD_NON_CLAIM_AND_COVERAGE, + this.pageName + ); + return; + } + navigateToHeritageFunnel({ shouldSaveSession: true, pageNameToLog: "insurance-company", diff --git a/src/layouts/insurance-details/insurance-details.vue b/src/layouts/insurance-details/insurance-details.vue new file mode 100644 index 000000000..67670b9cc --- /dev/null +++ b/src/layouts/insurance-details/insurance-details.vue @@ -0,0 +1,297 @@ + + + + + diff --git a/src/layouts/payment-adyen/payment-adyen.spec.js b/src/layouts/payment-adyen/payment-adyen.spec.js index 1a506b860..26d3a6aec 100644 --- a/src/layouts/payment-adyen/payment-adyen.spec.js +++ b/src/layouts/payment-adyen/payment-adyen.spec.js @@ -187,118 +187,6 @@ describe("payment-adyen.vue", () => { expect(result).toBe(true); }); }); - - describe("splitStreetAddress", () => { - const setInShopStreet = (streetAddress) => { - store.getters.order.serviceLocation.appointmentType = AppointmentTypeStrings.IN_SHOP; - store.getters.order.serviceLocation.provider.address.streetAddress = streetAddress; - }; - - test("splits typical address into first token as number and remainder as street", () => { - setInShopStreet("123 West Elm St"); - const wrapper = setupMocks({}); - - expect(wrapper.vm.splitStreetAddress).toEqual({ - number: "123", - street: "West Elm St", - }); - }); - - test("two tokens: number and single-word street", () => { - setInShopStreet("456 Oak"); - const wrapper = setupMocks({}); - - expect(wrapper.vm.splitStreetAddress).toEqual({ - number: "456", - street: "Oak", - }); - }); - - test("single token with no spaces: full string in number, empty street", () => { - setInShopStreet("123OakStreet"); - const wrapper = setupMocks({}); - - expect(wrapper.vm.splitStreetAddress).toEqual({ - number: "123OakStreet", - street: "", - }); - }); - - test("collapses multiple spaces between words", () => { - setInShopStreet("123 West Elm St"); - const wrapper = setupMocks({}); - - expect(wrapper.vm.splitStreetAddress).toEqual({ - number: "123", - street: "West Elm St", - }); - }); - - test("trims leading and trailing whitespace on full address", () => { - setInShopStreet(" 99 Maple Ave "); - const wrapper = setupMocks({}); - - expect(wrapper.vm.splitStreetAddress).toEqual({ - number: "99", - street: "Maple Ave", - }); - }); - - test("empty string yields empty number and street", () => { - setInShopStreet(""); - const wrapper = setupMocks({}); - - expect(wrapper.vm.splitStreetAddress).toEqual({ - number: "", - street: "", - }); - }); - - test("whitespace-only address yields empty number and street", () => { - setInShopStreet(" \t "); - const wrapper = setupMocks({}); - - expect(wrapper.vm.splitStreetAddress).toEqual({ - number: "", - street: "", - }); - }); - - test("null address yields empty number and street", () => { - setInShopStreet(null); - const wrapper = setupMocks({}); - - expect(wrapper.vm.splitStreetAddress).toEqual({ - number: "", - street: "", - }); - }); - - test("uses mobile service address when appointment is mobile", () => { - store.getters.order.serviceLocation.appointmentType = AppointmentTypeStrings.MOBILE; - store.getters.order.serviceLocation.address = "700 Broadway Blvd"; - store.getters.order.serviceLocation.city = "Columbus"; - store.getters.order.serviceLocation.state = "OH"; - store.getters.order.serviceLocation.zipCode = "43235"; - - const wrapper = setupMocks({}); - - expect(wrapper.vm.splitStreetAddress).toEqual({ - number: "700", - street: "Broadway Blvd", - }); - }); - - test("splits on tabs and other whitespace runs", () => { - setInShopStreet("10\tPine\tLane"); - const wrapper = setupMocks({}); - - expect(wrapper.vm.splitStreetAddress).toEqual({ - number: "10", - street: "Pine Lane", - }); - }); - }); }); function setupMocks({ customMountOptions } = {}) { diff --git a/src/layouts/payment-adyen/payment-adyen.vue b/src/layouts/payment-adyen/payment-adyen.vue index aa75487da..5b3a663ea 100644 --- a/src/layouts/payment-adyen/payment-adyen.vue +++ b/src/layouts/payment-adyen/payment-adyen.vue @@ -455,8 +455,8 @@ export default { zipCodeCtu: this.locationInfo.zipCodeCtu, amount: this.adyenPriceTotal, city: this.locationInfo.city, - houseNumberOrName: this.splitStreetAddress.number, - street: this.splitStreetAddress.street, + street: this.locationInfo.address ?? "", + houseNumberOrName: this.locationInfo.address2 ?? "", zipCode: this.locationInfo.zipCode, stateOrProvince: this.locationInfo.state, returnUrl: applicationConfig.PIA_ADYEN_RETURN_URL, @@ -515,18 +515,6 @@ export default { } }, - splitStreetAddress() { - const address = (this.locationInfo?.address ?? "").trim(); - const tokens = address.length ? address.split(/\s+/) : [""]; - const number = tokens[0] ?? ""; - const street = tokens.length > 1 ? tokens.slice(1).join(" ") : ""; - - return { - number, - street, - }; - }, - sourceSystem() { return "FMG-2.0"; }, diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index e5b08bdbc..da49aa039 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -226,8 +226,8 @@ export default { const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_WIPERS, { - serviceZipCode: store.getters.order.serviceLocation.zipCode, carId: store.getters.vehicle.carId, + accountNumber: store.getters.order.payment?.parentAccountNumber, }, "payment-method" ); diff --git a/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue index 4cf6dae0b..51827a30d 100644 --- a/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue +++ b/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue @@ -35,8 +35,8 @@ export default { const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_WIPERS, { - serviceZipCode: store.getters.order.serviceLocation.zipCode, carId: store.getters.vehicle.carId, + accountNumber: store.getters.order.payment?.parentAccountNumber, }, "review" ); diff --git a/src/layouts/policy-driver/policy-driver.spec.js b/src/layouts/policy-driver/policy-driver.spec.js new file mode 100644 index 000000000..5680f6f2f --- /dev/null +++ b/src/layouts/policy-driver/policy-driver.spec.js @@ -0,0 +1,70 @@ +import policyDriver from "@/layouts/policy-driver/policy-driver.vue"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { settleAllPromises } from "@/helpers/layout-helper"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +describe("policy-driver.vue", () => { + describe("component rendering", () => { + test("renders funnelHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelHeader" }).exists()).toBe(true); + }); + + test("renders funnelSubHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelSubHeader" }).exists()).toBe(true); + }); + + test("renders navbar component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "navbar" }).exists()).toBe(true); + }); + + test("renders Form component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "Form" }).exists()).toBe(true); + }); + }); + + describe("methods", () => { + test("arePagePrerequisitesValid returns true", () => { + const { wrapper } = setupMocks(); + expect(wrapper.vm.arePagePrerequisitesValid()).toBe(true); + }); + }); +}); + +function setupMocks() { + const mockCmsContent = { + FunnelHeaderWidget: { Text: "Header" }, + FunnelSubHeaderWidget: { Text: "Subheader" }, + FunnelFooterWidget: { Text: "Footer" }, + }; + + fetchCmsContentForPage.mockResolvedValue(mockCmsContent); + settleAllPromises.mockResolvedValue({ cmsContent: mockCmsContent }); + + const mountOptions = getMountOptions({ + route: { name: "policy-driver", query: {}, params: {} }, + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + }); + + const wrapper = shallowMount(policyDriver, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/policy-driver/policy-driver.vue b/src/layouts/policy-driver/policy-driver.vue new file mode 100644 index 000000000..4b3b5f171 --- /dev/null +++ b/src/layouts/policy-driver/policy-driver.vue @@ -0,0 +1,78 @@ + + + diff --git a/src/layouts/policy-info-submitted/policy-info-submitted.spec.js b/src/layouts/policy-info-submitted/policy-info-submitted.spec.js new file mode 100644 index 000000000..a647c2681 --- /dev/null +++ b/src/layouts/policy-info-submitted/policy-info-submitted.spec.js @@ -0,0 +1,70 @@ +import policyInfoSubmitted from "@/layouts/policy-info-submitted/policy-info-submitted.vue"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { settleAllPromises } from "@/helpers/layout-helper"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +describe("policy-info-submitted.vue", () => { + describe("component rendering", () => { + test("renders funnelHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelHeader" }).exists()).toBe(true); + }); + + test("renders funnelSubHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelSubHeader" }).exists()).toBe(true); + }); + + test("renders navbar component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "navbar" }).exists()).toBe(true); + }); + + test("renders Form component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "Form" }).exists()).toBe(true); + }); + }); + + describe("methods", () => { + test("arePagePrerequisitesValid returns true", () => { + const { wrapper } = setupMocks(); + expect(wrapper.vm.arePagePrerequisitesValid()).toBe(true); + }); + }); +}); + +function setupMocks() { + const mockCmsContent = { + FunnelHeaderWidget: { Text: "Header" }, + FunnelSubHeaderWidget: { Text: "Subheader" }, + FunnelFooterWidget: { Text: "Footer" }, + }; + + fetchCmsContentForPage.mockResolvedValue(mockCmsContent); + settleAllPromises.mockResolvedValue({ cmsContent: mockCmsContent }); + + const mountOptions = getMountOptions({ + route: { name: "policy-vehicle", query: {}, params: {} }, + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + }); + + const wrapper = shallowMount(policyInfoSubmitted, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/policy-info-submitted/policy-info-submitted.vue b/src/layouts/policy-info-submitted/policy-info-submitted.vue new file mode 100644 index 000000000..fa7a623c0 --- /dev/null +++ b/src/layouts/policy-info-submitted/policy-info-submitted.vue @@ -0,0 +1,78 @@ + + + diff --git a/src/layouts/policy-info/policy-info.vue b/src/layouts/policy-info/policy-info.vue index d1a9b80d2..ceef462a0 100644 --- a/src/layouts/policy-info/policy-info.vue +++ b/src/layouts/policy-info/policy-info.vue @@ -58,11 +58,17 @@ export default { }, methods: { - async backButtonAction() { - // Stub, for navigating back via nav-bar. + backButtonAction() { + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, async forwardButtonAction() { - // Stub, for navigating forward via nav-bar + this.$router.navigateWithSaving( + this.navigationScenarios.CLICKED_FORWARD, + this.pageName + ); }, arePagePrerequisitesValid() { return true; diff --git a/src/layouts/policy-vehicle/policy-vehicle.spec.js b/src/layouts/policy-vehicle/policy-vehicle.spec.js new file mode 100644 index 000000000..1fe1a5559 --- /dev/null +++ b/src/layouts/policy-vehicle/policy-vehicle.spec.js @@ -0,0 +1,70 @@ +import policyVehicle from "@/layouts/policy-vehicle/policy-vehicle.vue"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { settleAllPromises } from "@/helpers/layout-helper"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +describe("policy-vehicle.vue", () => { + describe("component rendering", () => { + test("renders funnelHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelHeader" }).exists()).toBe(true); + }); + + test("renders funnelSubHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelSubHeader" }).exists()).toBe(true); + }); + + test("renders navbar component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "navbar" }).exists()).toBe(true); + }); + + test("renders Form component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "Form" }).exists()).toBe(true); + }); + }); + + describe("methods", () => { + test("arePagePrerequisitesValid returns true", () => { + const { wrapper } = setupMocks(); + expect(wrapper.vm.arePagePrerequisitesValid()).toBe(true); + }); + }); +}); + +function setupMocks() { + const mockCmsContent = { + FunnelHeaderWidget: { Text: "Header" }, + FunnelSubHeaderWidget: { Text: "Subheader" }, + FunnelFooterWidget: { Text: "Footer" }, + }; + + fetchCmsContentForPage.mockResolvedValue(mockCmsContent); + settleAllPromises.mockResolvedValue({ cmsContent: mockCmsContent }); + + const mountOptions = getMountOptions({ + route: { name: "policy-vehicle", query: {}, params: {} }, + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + }); + + const wrapper = shallowMount(policyVehicle, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/policy-vehicle/policy-vehicle.vue b/src/layouts/policy-vehicle/policy-vehicle.vue new file mode 100644 index 000000000..954b04bc3 --- /dev/null +++ b/src/layouts/policy-vehicle/policy-vehicle.vue @@ -0,0 +1,78 @@ + + + diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 106c04bfa..d9f238733 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -217,8 +217,10 @@ export default { const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_WIPERS, { - serviceZipCode: store.getters.order.serviceLocation.zipCode, carId: store.getters.vehicle.carId, + accountNumber: + store.getters.order.payment?.parentAccountNumber ?? + applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, }, "quote" ); @@ -792,6 +794,13 @@ export default { applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER, false ); + this.dispatchStoreAction( + this.storeActions.SAVE_IS_CLAIM_AND_COVERAGE, + false, + false + ); + this.dispatchStoreAction(this.storeActions.SAVE_CAN_SCHEDULE_ONLINE, false, false); + this.dispatchStoreAction(this.storeActions.SAVE_ACCOUNT_NAME, null, false); } else { baseMixin.methods.dispatchStoreAction( storeActions.SAVE_PARENT_ACCOUNT_NUMBER, diff --git a/src/layouts/recalibration-info/recalibration-info.spec.js b/src/layouts/recalibration-info/recalibration-info.spec.js new file mode 100644 index 000000000..50667e1fa --- /dev/null +++ b/src/layouts/recalibration-info/recalibration-info.spec.js @@ -0,0 +1,70 @@ +import recalibrationInfo from "@/layouts/recalibration-info/recalibration-info.vue"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { settleAllPromises } from "@/helpers/layout-helper"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +describe("recalibration-info.vue", () => { + describe("component rendering", () => { + test("renders funnelHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelHeader" }).exists()).toBe(true); + }); + + test("renders funnelSubHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelSubHeader" }).exists()).toBe(true); + }); + + test("renders navbar component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "navbar" }).exists()).toBe(true); + }); + + test("renders Form component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "Form" }).exists()).toBe(true); + }); + }); + + describe("methods", () => { + test("arePagePrerequisitesValid returns true", () => { + const { wrapper } = setupMocks(); + expect(wrapper.vm.arePagePrerequisitesValid()).toBe(true); + }); + }); +}); + +function setupMocks() { + const mockCmsContent = { + FunnelHeaderWidget: { Text: "Header" }, + FunnelSubHeaderWidget: { Text: "Subheader" }, + FunnelFooterWidget: { Text: "Footer" }, + }; + + fetchCmsContentForPage.mockResolvedValue(mockCmsContent); + settleAllPromises.mockResolvedValue({ cmsContent: mockCmsContent }); + + const mountOptions = getMountOptions({ + route: { name: "policy-vehicle", query: {}, params: {} }, + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + }); + + const wrapper = shallowMount(recalibrationInfo, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/recalibration-info/recalibration-info.vue b/src/layouts/recalibration-info/recalibration-info.vue new file mode 100644 index 000000000..828ba080a --- /dev/null +++ b/src/layouts/recalibration-info/recalibration-info.vue @@ -0,0 +1,78 @@ + + + diff --git a/src/layouts/verify-details/verify-details.spec.js b/src/layouts/verify-details/verify-details.spec.js new file mode 100644 index 000000000..ec541ecf9 --- /dev/null +++ b/src/layouts/verify-details/verify-details.spec.js @@ -0,0 +1,70 @@ +import verifyDetails from "@/layouts/verify-details/verify-details.vue"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { settleAllPromises } from "@/helpers/layout-helper"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +describe("verify-details.vue", () => { + describe("component rendering", () => { + test("renders funnelHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelHeader" }).exists()).toBe(true); + }); + + test("renders funnelSubHeader component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "funnelSubHeader" }).exists()).toBe(true); + }); + + test("renders navbar component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "navbar" }).exists()).toBe(true); + }); + + test("renders Form component", () => { + const { wrapper } = setupMocks(); + expect(wrapper.findComponent({ name: "Form" }).exists()).toBe(true); + }); + }); + + describe("methods", () => { + test("arePagePrerequisitesValid returns true", () => { + const { wrapper } = setupMocks(); + expect(wrapper.vm.arePagePrerequisitesValid()).toBe(true); + }); + }); +}); + +function setupMocks() { + const mockCmsContent = { + FunnelHeaderWidget: { Text: "Header" }, + FunnelSubHeaderWidget: { Text: "Subheader" }, + FunnelFooterWidget: { Text: "Footer" }, + }; + + fetchCmsContentForPage.mockResolvedValue(mockCmsContent); + settleAllPromises.mockResolvedValue({ cmsContent: mockCmsContent }); + + const mountOptions = getMountOptions({ + route: { name: "policy-vehicle", query: {}, params: {} }, + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + }); + + const wrapper = shallowMount(verifyDetails, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/verify-details/verify-details.vue b/src/layouts/verify-details/verify-details.vue new file mode 100644 index 000000000..e0b889cb2 --- /dev/null +++ b/src/layouts/verify-details/verify-details.vue @@ -0,0 +1,78 @@ + + + diff --git a/src/mixins/experiment-mixin.js b/src/mixins/experiment-mixin.js index 474945a54..9439f0506 100644 --- a/src/mixins/experiment-mixin.js +++ b/src/mixins/experiment-mixin.js @@ -1,5 +1,6 @@ import store from "@/store"; import * as experimentHelper from "../helpers/experiment-helper"; +import { experimentSettings } from "@/constants/experiments"; /* This is a wrapper around experiment-helper.js methods that allows an override @@ -32,5 +33,24 @@ export default { experimentHelper.getExperimentSettingsFromExperimentList(experimentList); return experimentHelper.getSettingValue(settingName, experimentSettings); }, + + // Looks for an experiment setting that has a value that matches the passed in parent account number. + // Settings named NON_CLAIM_AND_COVERAGE_TEST_PARENT_ACCOUNT are excluded from the match. + hasClaimAndCoverage( + parentAccountNumber, + experimentList = store.getters.applicationUser.experiments + ) { + const parentNum = String(parentAccountNumber); + return experimentList.some( + (experiment) => + experiment.settings && + Object.entries(experiment.settings).some( + ([name, value]) => + name !== + experimentSettings.NON_CLAIM_AND_COVERAGE_TEST_PARENT_ACCOUNT && + value === parentNum + ) + ); + }, }, }; diff --git a/src/router/constants/auto-route-table.js b/src/router/constants/auto-route-table.js index 0bf3503b9..ea1dd69e0 100644 --- a/src/router/constants/auto-route-table.js +++ b/src/router/constants/auto-route-table.js @@ -6,7 +6,6 @@ export const autoRouteTable = [ routeData.MOLDING_QUESTIONS, routeData.VEHICLE_PARTS, routeData.PART_QUESTIONS, - routeData.VIN_LOOKUP, routeData.ESTIMATE, routeData.VEHICLE_DAMAGE, routeData.VEHICLE, diff --git a/src/router/constants/navigation-scenarios.js b/src/router/constants/navigation-scenarios.js index 21bcc46f3..fef66ddbb 100644 --- a/src/router/constants/navigation-scenarios.js +++ b/src/router/constants/navigation-scenarios.js @@ -39,6 +39,8 @@ const navigationScenarios = { CLICKED_FORWARD_WITH_MOLDING_QUESTIONS: "CLICKED_FORWARD_WITH_MOLDING_QUESTIONS", CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS: "CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS", CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS: "CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS", + CLICKED_BACK_NON_CLAIM_AND_COVERAGE: "CLICKED_BACK_NON_CLAIM_AND_COVERAGE", + CLICKED_BACK_RECALIBRATION_INFO: "CLICKED_BACK_RECALIBRATION_INFO", CLICKED_BACK_WITH_PART_QUESTIONS: "CLICKED_BACK_WITH_PART_QUESTIONS", CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE: "CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE", CLICKED_BACK_WITH_MOLDING_QUESTIONS: "CLICKED_BACK_WITH_MOLDING_QUESTIONS", @@ -48,6 +50,8 @@ const navigationScenarios = { // Insurance-Company CLICKED_PAY_ON_MY_OWN: "CLICKED_PAY_ON_MY_OWN", + CLICKED_FORWARD_POLICY_INFO: "CLICKED_FORWARD_POLICY_INFO", + CLICKED_FORWARD_NON_CLAIM_AND_COVERAGE: "CLICKED_FORWARD_NON_CLAIM_AND_COVERAGE", //Service-Location CLICKED_FORWARD_WITH_MOBILE_SERVICE: "CLICKED_FORWARD_WITH_MOBILE_SERVICE", diff --git a/src/router/constants/routes.js b/src/router/constants/routes.js index 47c37bb55..fc54025ef 100644 --- a/src/router/constants/routes.js +++ b/src/router/constants/routes.js @@ -55,6 +55,42 @@ export const routeData = { name: "policy-info", path: "/policy-info", }, + INSURANCE_DETAILS: { + name: "insurance-details", + path: "/insurance-details", + }, + DUPLICATE_CHECK: { + name: "duplicate-check", + path: "/duplicate-check", + }, + POLICY_VEHICLE: { + name: "policy-vehicle", + path: "/policy-vehicle", + }, + POLICY_DRIVER: { + name: "policy-driver", + path: "/policy-driver", + }, + ENDORSEMENTS: { + name: "endorsements", + path: "/endorsements", + }, + POLICY_INFO_SUBMITTED: { + name: "policy-info-submitted", + path: "/policy-info-submitted", + }, + RECALIBRATION_INFO: { + name: "recalibration-info", + path: "/recalibration-info", + }, + COVERAGE_STATEMENT: { + name: "coverage-statement", + path: "/coverage-statement", + }, + VERIFY_DETAILS: { + name: "verify-details", + path: "/verify-details", + }, INSURANCE_COMPANY: { name: "insurance-company", path: "/insurance-company", diff --git a/src/router/constants/routing-table.js b/src/router/constants/routing-table.js index a7be5f387..77876a096 100644 --- a/src/router/constants/routing-table.js +++ b/src/router/constants/routing-table.js @@ -431,7 +431,141 @@ const routingTable = function () { }, { pageName: routeData.POLICY_INFO.name, - maps: [], + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.INSURANCE_COMPANY, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.DUPLICATE_CHECK, + }, + ], + }, + { + pageName: routeData.INSURANCE_DETAILS.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.INSURANCE_COMPANY, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.COVERAGE_STATEMENT, + }, + ], + }, + { + pageName: routeData.DUPLICATE_CHECK.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.POLICY_INFO, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.POLICY_VEHICLE, + }, + ], + }, + { + pageName: routeData.POLICY_VEHICLE.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.DUPLICATE_CHECK, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.POLICY_DRIVER, + }, + ], + }, + { + pageName: routeData.POLICY_DRIVER.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.POLICY_VEHICLE, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.ENDORSEMENTS, + }, + ], + }, + { + pageName: routeData.ENDORSEMENTS.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.POLICY_DRIVER, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.POLICY_INFO_SUBMITTED, + }, + ], + }, + { + pageName: routeData.POLICY_INFO_SUBMITTED.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.ENDORSEMENTS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.RECALIBRATION_INFO, + }, + ], + }, + { + pageName: routeData.RECALIBRATION_INFO.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.POLICY_INFO_SUBMITTED, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.COVERAGE_STATEMENT, + }, + ], + }, + { + pageName: routeData.COVERAGE_STATEMENT.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.POLICY_INFO_SUBMITTED, + }, + { + scenario: navigationScenarios.CLICKED_BACK_RECALIBRATION_INFO, + destinationPageData: routeData.RECALIBRATION_INFO, + }, + { + scenario: navigationScenarios.CLICKED_BACK_NON_CLAIM_AND_COVERAGE, + destinationPageData: routeData.INSURANCE_DETAILS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.SCHEDULE, + }, + ], + }, + { + pageName: routeData.VERIFY_DETAILS.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.DUPLICATE_CHECK, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.POLICY_INFO_SUBMITTED, + }, + ], }, { pageName: routeData.INSURANCE_COMPANY.name, @@ -451,6 +585,14 @@ const routingTable = function () { scenario: navigationScenarios.CLICKED_FORWARD, destinationPageData: routeData.INSURANCE_DETAILS, }, + { + scenario: navigationScenarios.CLICKED_FORWARD_POLICY_INFO, + destinationPageData: routeData.POLICY_INFO, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_NON_CLAIM_AND_COVERAGE, + destinationPageData: routeData.INSURANCE_DETAILS, + }, ], }, // TODO: REMOVE THIS COMMENT AND BELOW, ONCE CASH-803 (SERVICE-LOCATION AND SCHEDULE PAGE COMBINATION) HAS BEEN VETTED diff --git a/src/router/methods/routes.js b/src/router/methods/routes.js index 521ba43a1..88cc17f94 100644 --- a/src/router/methods/routes.js +++ b/src/router/methods/routes.js @@ -42,7 +42,15 @@ export const routes = [ createRoute(routeData.RETURN_USER), createRoute(routeData.MOBILE_DETAILS), createRoute(routeData.POLICY_INFO), - + createRoute(routeData.INSURANCE_DETAILS), + createRoute(routeData.DUPLICATE_CHECK), + createRoute(routeData.POLICY_VEHICLE), + createRoute(routeData.POLICY_DRIVER), + createRoute(routeData.ENDORSEMENTS), + createRoute(routeData.POLICY_INFO_SUBMITTED), + createRoute(routeData.RECALIBRATION_INFO), + createRoute(routeData.COVERAGE_STATEMENT), + createRoute(routeData.VERIFY_DETAILS), // Virtual pages (resolve to a non-virtual page.) createVirtualRoute(routeData.LANDING, landingBeforeEnter), createVirtualRoute(routeData.HERITAGE, heritageBeforeEnter), diff --git a/src/store/index.js b/src/store/index.js index da45f3a61..a58200a96 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -142,6 +142,9 @@ const getDefaultState = () => { coverageVerificationType: null, }, parentAccountNumber: 0, + accountName: null, + isClaimAndCoverage: false, + canScheduleOnline: false, billToAccountNumber: null, isPia: null, piaType: null, @@ -171,6 +174,11 @@ const getDefaultState = () => { additionalAuthFlag: null, isNoComp: false, insuranceCompanyName: null, + streetAddress: null, + apartment: null, + city: null, + state: null, + zipCode: null, }, schedule: { date: null, @@ -328,6 +336,31 @@ export const mutations = { updateParentAcctNumber(state, parentAcctNumber) { state.order.payment.parentAccountNumber = parentAcctNumber; }, + updateAccountName(state, accountName) { + state.order.payment.accountName = accountName; + state.order.policy.insuranceCompanyName = accountName; + }, + updateStreetAddress(state, streetAddress) { + state.order.policy.streetAddress = streetAddress; + }, + updateApartment(state, apartment) { + state.order.policy.apartment = apartment; + }, + updateCity(state, city) { + state.order.policy.city = city; + }, + updateState(state, stateValue) { + state.order.policy.state = stateValue; + }, + updateZipCode(state, zipCode) { + state.order.policy.zipCode = zipCode; + }, + updateIsClaimAndCoverage(state, isClaimAndCoverage) { + state.order.payment.isClaimAndCoverage = isClaimAndCoverage; + }, + updateCanScheduleOnline(state, canScheduleOnline) { + state.order.payment.canScheduleOnline = canScheduleOnline; + }, updateBillToAcctNumber(state, billToAcctNumber) { state.order.payment.billToAccountNumber = billToAcctNumber; }, @@ -482,6 +515,22 @@ export const mutations = { state.order.customer.isSmsOptIn = customerDetails.isSmsOptIn; } }, + updateInsuranceDetails(state, insuranceDetails) { + if (insuranceDetails) { + state.order.policy.policyNumber = insuranceDetails.policyNumber; + state.order.policy.streetAddress = insuranceDetails.streetAddress; + state.order.policy.apartment = insuranceDetails.apartment; + state.order.policy.city = insuranceDetails.city; + state.order.policy.state = insuranceDetails.state; + state.order.policy.zipCode = insuranceDetails.zipCode; + } + }, + updateDamageDetails(state, damageDetails) { + if (damageDetails) { + state.order.damage.dateOfLoss = damageDetails.dateOfLoss; + state.order.damage.damageCause = damageDetails.damageCause; + } + }, // applicationUser MUTATIONS updateSaveSessionPromise(state, saveSessionPromise) { @@ -766,7 +815,10 @@ export const mutations = { state.order.payment.billToAccountNumber = sessionInformation.order.payment.billToAccountNumber; state.order.payment.inactivePromos = sessionInformation.order.payment.inactivePromos; - + state.order.payment.isClaimAndCoverage = + sessionInformation.order.payment.isClaimAndCoverage; + state.order.payment.canScheduleOnline = sessionInformation.order.payment.canScheduleOnline; + state.order.payment.accountName = sessionInformation.order.policy.insuranceCompanyName; //Do not assign default service type once user make service type selection if (state.order.serviceLocation.appointmentType == null) { state.order.serviceLocation.address = @@ -863,6 +915,11 @@ export const mutations = { state.order.policy.policyNumber = sessionInformation.order.policy?.policyNumber; state.order.policy.insuranceCompanyName = sessionInformation.order.policy?.insuranceCompanyName; + //state.order.policy.streetAddress = sessionInformation.order.policy?.streetAddress; + //state.order.policy.apartment = sessionInformation.order.policy?.apartment; + //state.order.policy.city = sessionInformation.order.policy?.city; + //state.order.policy.state = sessionInformation.order.policy?.state; + //state.order.policy.zipCode = sessionInformation.order.policy?.zipCode; state.order.policy.isNoComp = coverageTypeValue(sessionInformation?.order.insuranceCoverage.coverageType) === coverageType.NOCOMP @@ -1961,12 +2018,12 @@ export const actions = { async getWipers(context, { payload, pageNameToLog }) { const carId = payload.carId; - const serviceZipCode = payload.serviceZipCode; + const accountNumber = payload.accountNumber; const response = await globalMethods .callHttpClient({ method: endpoints.GetWipers.method, - endpoint: `${endpoints.GetWipers.url}/${carId}/${serviceZipCode}`, + endpoint: `${endpoints.GetWipers.url}/${carId}/${accountNumber}`, logApiCall: true, pageNameToLog: pageNameToLog, }) @@ -2524,6 +2581,8 @@ export const actions = { isInsurance: order.payment.isInsurance, parentAccountNumber: order.payment.parentAccountNumber, billToAccountNumber: order.payment.billToAccountNumber, + isClaimAndCoverage: order.payment.isClaimAndCoverage, + canScheduleOnline: order.payment.canScheduleOnline, inactivePromos: order.payment.inactivePromos, isCreditCard: order.payment.piaType == paymentMethods.CREDIT_CARD ? true : false, @@ -3040,6 +3099,15 @@ export const actions = { saveParentAccountNumber(context, parentAccountNumber) { context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber); }, + saveAccountName(context, accountName) { + context.commit(storeMutations.UPDATE_ACCOUNT_NAME, accountName); + }, + saveIsClaimAndCoverage(context, isClaimAndCoverage) { + context.commit(storeMutations.UPDATE_IS_CLAIM_AND_COVERAGE, isClaimAndCoverage); + }, + saveCanScheduleOnline(context, canScheduleOnline) { + context.commit(storeMutations.UPDATE_CAN_SCHEDULE_ONLINE, canScheduleOnline); + }, saveBillToAccountNumber(context, billToAccountNumber) { context.commit(storeMutations.UPDATE_BILL_TO_ACCT_NUMBER, billToAccountNumber); }, @@ -3439,6 +3507,14 @@ export const actions = { context.commit(storeMutations.UPDATE_CUSTOMER_DETAILS, customerDetails); }, + saveInsuranceDetails(context, insuranceDetails) { + context.commit(storeMutations.UPDATE_INSURANCE_DETAILS, insuranceDetails); + }, + + saveDamageDetails(context, damageDetails) { + context.commit(storeMutations.UPDATE_DAMAGE_DETAILS, damageDetails); + }, + saveServiceZipCodeInfo(context, serviceZipCodeInfo) { if ( context.state.order.serviceLocation && diff --git a/src/store/store.spec.js b/src/store/store.spec.js index ea896116d..f8c41cbe4 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -225,6 +225,9 @@ describe("Mutations", () => { category: "CAR", registration: {}, }, + policy: { + insuranceCompanyName: "LibertyBibity", + }, damage: { glassToReplace: ["Windshield"], isRepair: false,