From 541536b3afcd706cc9265229fdea40c06e3f8120 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 13 May 2025 16:36:01 -0400 Subject: [PATCH 01/13] Reapply "Omnibus" This reverts commit ac3df43577426804f64ed0ea7d1cdd43d7be1041. --- src/App.vue | 3 + src/constants/application-config.js | 19 +- src/constants/store-actions.js | 1 + src/constants/store-mutations.js | 1 + .../text-block/text-block.vue | 2 +- .../progress-bar/progress-bar.vue | 2 +- src/global-methods.js | 4 +- .../heritage-integration/order-helper.js | 26 +- src/layouts/address-lookup/address-lookup.vue | 17 +- .../address-vehicles/address-vehicles.vue | 11 +- src/layouts/bailout/bailout.vue | 2 +- .../capability-questions.vue | 2 +- src/layouts/confirmation/confirmation.vue | 15 +- .../customer-details/customer-details.vue | 15 +- src/layouts/estimate/estimate.vue | 22 +- .../insurance-company/insurance-company.vue | 15 +- .../license-plate-lookup.vue | 16 +- .../molding-questions/molding-questions.vue | 2 +- src/layouts/part-questions/part-questions.vue | 2 +- src/layouts/payment-method/payment-method.vue | 29 +- .../payment-pia-return/payment-pia-return.vue | 47 +- src/layouts/payment/payment.vue | 32 +- src/layouts/quote/quote.vue | 27 +- src/layouts/return-user/return-user.vue | 10 +- src/layouts/schedule/schedule.vue | 12 +- .../service-location/service-location.vue | 9 +- src/layouts/service-zip/service-zip.vue | 11 +- src/layouts/vehicle-damage/vehicle-damage.vue | 37 +- .../glass-part-question.vue | 2 +- src/layouts/vehicle-parts/vehicle-parts.vue | 2 +- src/layouts/vehicle/vehicle.vue | 15 +- src/layouts/vin-lookup/vin-lookup.vue | 14 +- src/main.js | 2 +- src/mixins/base-mixin.js | 9 +- src/mixins/vehicle-questions-mixin.js | 36 +- .../a-rewrite/constants/auto-route-table.js | 13 + .../constants/navigation-scenarios.js | 69 ++ .../a-rewrite/constants/route-prefix.js | 3 + src/router/a-rewrite/constants/routes.js | 123 ++++ .../a-rewrite/constants/routing-table.js | 596 ++++++++++++++++++ src/router/a-rewrite/index.js | 421 +++++++++++++ .../a-rewrite/logic/build-manual-url.js | 27 + .../a-rewrite/logic/consume-referral-info.js | 18 + src/router/a-rewrite/logic/create-route.js | 39 ++ src/router/a-rewrite/logic/get-destination.js | 18 + .../logic/initialize-from-querystrings.js | 121 ++++ .../a-rewrite/logic/lazy-load-component.js | 3 + .../a-rewrite/logic/querystring-stash.js | 58 ++ .../logic/requires-verified-redirect.js | 8 + src/router/a-rewrite/logic/run-experiments.js | 30 + src/router/a-rewrite/logic/save-page-data.js | 11 + src/store/index.js | 8 + 52 files changed, 1816 insertions(+), 221 deletions(-) create mode 100644 src/router/a-rewrite/constants/auto-route-table.js create mode 100644 src/router/a-rewrite/constants/navigation-scenarios.js create mode 100644 src/router/a-rewrite/constants/route-prefix.js create mode 100644 src/router/a-rewrite/constants/routes.js create mode 100644 src/router/a-rewrite/constants/routing-table.js create mode 100644 src/router/a-rewrite/index.js create mode 100644 src/router/a-rewrite/logic/build-manual-url.js create mode 100644 src/router/a-rewrite/logic/consume-referral-info.js create mode 100644 src/router/a-rewrite/logic/create-route.js create mode 100644 src/router/a-rewrite/logic/get-destination.js create mode 100644 src/router/a-rewrite/logic/initialize-from-querystrings.js create mode 100644 src/router/a-rewrite/logic/lazy-load-component.js create mode 100644 src/router/a-rewrite/logic/querystring-stash.js create mode 100644 src/router/a-rewrite/logic/requires-verified-redirect.js create mode 100644 src/router/a-rewrite/logic/run-experiments.js create mode 100644 src/router/a-rewrite/logic/save-page-data.js diff --git a/src/App.vue b/src/App.vue index 422ae2893..f4c5754aa 100644 --- a/src/App.vue +++ b/src/App.vue @@ -36,6 +36,9 @@ export default { loadingModal, funnelFooter, }, + mounted() { + showFmgLoadingModal(true); + }, }; // Add a global Javascript exception handler for logging exceptions, this handler will log when there is an uncaught exception diff --git a/src/constants/application-config.js b/src/constants/application-config.js index 14f195cfc..a03e5f010 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -15,21 +15,12 @@ const applicationConfig = { CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER: "87291", MY_ACCOUNT: process.env.VUE_APP_MY_ACCOUNT, PIA_RESPONSE_URL: - location.protocol + - "//" + - location.host + - "/fmg/?fmgPage=payment-pia-return&src=concept-funnel", + location.protocol + "//" + location.host + "/fmg/payment-pia-return?src=concept-funnel", PIA_CANCEL_URL: - location.protocol + - "//" + - location.host + - "/fmg/?fmgPage=payment-method&src=concept-funnel", + location.protocol + "//" + location.host + "/fmg/payment-method?src=concept-funnel", PIA_ERROR_URL: - location.protocol + - "//" + - location.host + - "/fmg/?fmgPage=payment-pia-return&src=concept-funnel", - CONFIRMATION_URL: location.protocol + "//" + location.host + "/fmg/?fmgPage=confirmation", + location.protocol + "//" + location.host + "/fmg/payment-pia-return?src=concept-funnel", + CONFIRMATION_URL: location.protocol + "//" + location.host + "/fmg/confirmation", GOOGLE_CALENDAR: "https://www.google.com/calendar/render?action=TEMPLATE", YAHOO_CALENDAR: "https://calendar.yahoo.com/?v=60", OUTLOOK_CALENDAR: @@ -38,7 +29,7 @@ const applicationConfig = { AFFILIATE_COOKIE_CONTAINING_NAME: "_Track", COOKIE_NAME_LENGTH_MAX_LIMIT: 44, SESSION_TIMEOUT_MINUTES: process.env.VUE_APP_SESSION_TIMEOUT_MINUTES, - RETURN_USER_PAGE: "/fmg/?fmgPage=return-user", + RETURN_USER_PAGE: "/fmg/return-user", }; export { applicationConfig }; diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 7b76d4064..9f0965480 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -117,6 +117,7 @@ const storeActions = { UPDATE_EXTERNAL_PARAMETER_MMS: "updateExternalParameterMMS", SAVE_LOGGING_OPTION: "saveLoggingOption", + UPDATE_HAS_TRIGGERED_ERROR: "updateHasTriggeredError", }; export { storeActions }; diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index 5064864d0..f7e8d9f4b 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -94,6 +94,7 @@ const storeMutations = { UPDATE_SAVE_SESSION_PROMISE: "updateSaveSessionPromise", UPDATE_LAST_PAGE_VISITED: "updateLastPageVisited", UPDATE_LOGGING_OPTION: "updateLoggingOption", + UPDATE_HAS_TRIGGERED_ERROR: "updateHasTriggeredError", // EXPERIMENT MUTATIONS UPDATE_EXPERIMENTS: "updateExperiments", diff --git a/src/digital-components/text-block/text-block.vue b/src/digital-components/text-block/text-block.vue index b84f12283..c7bb61215 100644 --- a/src/digital-components/text-block/text-block.vue +++ b/src/digital-components/text-block/text-block.vue @@ -58,7 +58,7 @@ export default { getRouterLinkDisplayTextFromCopy, getExternalLink, navigateWithScenario(scenarioName) { - this.$router.navigateWithoutSaving(scenarioName, this.$route); + this.$router.navigateWithoutSaving(scenarioName, this.pageName); }, }, computed: { diff --git a/src/fmg-components/funnel-header/progress-bar/progress-bar.vue b/src/fmg-components/funnel-header/progress-bar/progress-bar.vue index ab6a00b3a..da370e415 100644 --- a/src/fmg-components/funnel-header/progress-bar/progress-bar.vue +++ b/src/fmg-components/funnel-header/progress-bar/progress-bar.vue @@ -17,7 +17,7 @@ export default { }, methods: { getProgress() { - var pageName = store.getters.applicationUser.lastPageVisited; + var pageName = this.pageName; return getProgressBarPercentage(pageName); }, }, diff --git a/src/global-methods.js b/src/global-methods.js index ba6cec1ec..784ba6782 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -1,7 +1,7 @@ import axios from "axios"; import analyticsMixIn from "@/mixins/analytics-mixin.js"; import baseMixin from "@/mixins/base-mixin.js"; -import router from "@/router"; +import router from "@/router/a-rewrite"; import store from "@/store"; import { applicationConfig } from "@/constants/application-config.js"; @@ -117,7 +117,7 @@ export default { endpoint: endpoint, }; - router.navigateError(errorPayload); + router.bailout(errorPayload); // do not log 404 errors from services because we return NotFound // when a service doesn't return an object diff --git a/src/helpers/heritage-integration/order-helper.js b/src/helpers/heritage-integration/order-helper.js index 76729e49f..1c0922ba0 100644 --- a/src/helpers/heritage-integration/order-helper.js +++ b/src/helpers/heritage-integration/order-helper.js @@ -59,25 +59,15 @@ export async function saveSession({ submitAfterSave = false, createUnscheduledStatusWorkOrderForPIA = false, }) { - var saveSessionPromise; - if (store.getters.applicationUser.saveSessionPromise) { - // queue newest request after current saveSessionPromise resolves - saveSessionPromise = store.getters.applicationUser.saveSessionPromise.then(() => { - // get a new saveSessionPromise - return saveSessionHelper( - pageNameToLog, - submitAfterSave, - createUnscheduledStatusWorkOrderForPIA - ); - }); - } else { - // create an initial saveSessionPromise - saveSessionPromise = saveSessionHelper( + // Add next save session to end of queue + const saveSessionPromise = flushSaveSessionQueue().then(() => { + return saveSessionHelper( pageNameToLog, submitAfterSave, createUnscheduledStatusWorkOrderForPIA ); - } + }); + store.commit(storeMutations.UPDATE_SAVE_SESSION_PROMISE, saveSessionPromise); // await here to allow for a caller to await and make the function synchronous if (!store.getters.applicationUser.savedSessionId || shouldAwaitSaveSessionQueue) { @@ -133,7 +123,7 @@ async function loadSession( pageNameToLog ) { // await the saveSessionPromise in the store to make sure we're loading up to date information - await store.getters.applicationUser.saveSessionPromise; + await flushSaveSessionQueue(); const response = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.LOAD_SESSION, @@ -193,3 +183,7 @@ async function saveSessionHelper( // Update the cookie with the referral information when saved. updateOrCreateFunnelCookie(); } + +export async function flushSaveSessionQueue() { + return Promise.resolve(store.getters.applicationUser.saveSessionPromise); +} diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue index 54020b7b0..6a82ea26c 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -137,7 +137,7 @@ export default { mixins: [vinPagesMixin], async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ @@ -193,7 +193,10 @@ export default { }, backButtonAction() { // route to move backwards - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, attachCustomEvents() { this.prependActionToMethod(this, this.forwardButtonAction, () => { @@ -442,18 +445,14 @@ export default { ) { this.$router.navigateWithSaving( this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true } + this.pageName ); } else if (matchingCars.length === 1) { await this.navigateForwardWithSingleCarMatch(); } else { - this.$router.navigateWithSaving( + this.$router.navigateWithPageData( this.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES, - this.$route, - {}, - {}, + this.pageName, carsFound ); } diff --git a/src/layouts/address-vehicles/address-vehicles.vue b/src/layouts/address-vehicles/address-vehicles.vue index f44cdc65a..e094f6147 100644 --- a/src/layouts/address-vehicles/address-vehicles.vue +++ b/src/layouts/address-vehicles/address-vehicles.vue @@ -82,7 +82,7 @@ export default { mixins: [vinPagesMixin], async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ @@ -166,7 +166,10 @@ export default { return false; }, backButtonAction() { - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, async forwardButtonAction() { const vinLookup = await this.dispatchStoreActionWithLogging( @@ -205,9 +208,7 @@ export default { if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true } + this.pageName ); } else { await this.navigateForwardWithSingleCarMatch(); diff --git a/src/layouts/bailout/bailout.vue b/src/layouts/bailout/bailout.vue index b1f159fbe..a64f7a416 100644 --- a/src/layouts/bailout/bailout.vue +++ b/src/layouts/bailout/bailout.vue @@ -37,7 +37,7 @@ export default { name: "bailout", async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index 1896513a1..e04f0f18e 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -47,7 +47,7 @@ export default { mixins: [vehicleQuestionsMixin], async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ diff --git a/src/layouts/confirmation/confirmation.vue b/src/layouts/confirmation/confirmation.vue index 40736b2c2..e65eacc3c 100644 --- a/src/layouts/confirmation/confirmation.vue +++ b/src/layouts/confirmation/confirmation.vue @@ -123,6 +123,7 @@ import experimentMixin from "@/mixins/experiment-mixin.js"; import { containsRecalParts } from "@/helpers/recal-helper.js"; import donationBlock from "@/experiment-components/donation-block.vue"; import { partNumberStrings } from "@/constants/part-number-strings"; +import analyticsMixin from "@/mixins/analytics-mixin"; export default { name: "confirmation", @@ -179,7 +180,7 @@ export default { // Call APIs const submittedOrder = baseMixin.methods.getSubmittedOrder(); - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_WIPERS, @@ -244,6 +245,8 @@ export default { vm.showDonationSuccess = lineItemsFromSubmittedOrder.supportingItems?.some( (item) => item.partType === partNumberStrings.DONATION ); + + vm.pushAnalytics(); }); }, data() { @@ -556,6 +559,16 @@ export default { this.$refs.donationBlock.removeLoader(); } }, + pushAnalytics() { + //Push Ecommerce Cart to Data Layer + analyticsMixin.methods.pushECommerceCartToDataLayer(); + + //Push Product Array to Data Layer + analyticsMixin.methods.pushProductArrayToDataLayer(); + + //Push Commission Junction Gtm Data To Data Layer + analyticsMixin.methods.pushCommissionJunctionGtmDataToDataLayer(); + }, }, components: { funnelHeader, diff --git a/src/layouts/customer-details/customer-details.vue b/src/layouts/customer-details/customer-details.vue index baa8636be..8cb17673b 100644 --- a/src/layouts/customer-details/customer-details.vue +++ b/src/layouts/customer-details/customer-details.vue @@ -84,6 +84,7 @@ import { required, regex } from "@/helpers/validation-rules"; import { Form, defineRule } from "vee-validate"; import store from "@/store"; import { paymentMethods } from "@/constants/payment-method-constants"; +import { flushSaveSessionQueue } from "@/helpers/heritage-integration/order-helper"; // DEFINE VALIDATION RULES defineRule("first-name-required", required(errorMessages.FIRST_NAME_REQUIRED)); @@ -102,7 +103,7 @@ export default { name: "customer-details", async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ @@ -157,7 +158,10 @@ export default { return store.getters.order.serviceLocation.techNotes; }, backButtonAction() { - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, async forwardButtonAction() { this.dispatchStoreAction( @@ -186,10 +190,13 @@ export default { paymentMethods.NONE, false ); - await store.getters.applicationUser.saveSessionPromise; + await flushSaveSessionQueue(); } - this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route); + this.$router.navigateWithSaving( + this.navigationScenarios.CLICKED_FORWARD, + this.pageName + ); }, }, components: { diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index b9fdf1958..0a5db7d74 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -62,6 +62,7 @@ import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; import baseMixin from "@/mixins/base-mixin.js"; import { queryStrings } from "@/constants/query-strings"; import { nextTick } from "vue"; +import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; // Define Validation Rules defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); @@ -89,7 +90,7 @@ export default { async beforeRouteEnter(to, from, next) { //Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); @@ -98,9 +99,9 @@ export default { lowerCaseParams.append(name.toLowerCase(), value); } - const zip = lowerCaseParams.get(queryStrings.ZIP_CODE) - ? lowerCaseParams.get(queryStrings.ZIP_CODE) - : store.getters.order.serviceLocation.zipCode; + const zip = + consumeQueryFromStash(queryStrings.ZIP_CODE) ?? + store.getters.order.serviceLocation.zipCode; var vinByAddressPromise; if (zip) { @@ -184,32 +185,35 @@ export default { }, backButtonAction() { // route to move backwards - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, async forwardButtonAction() { if (this.selectedVinLookupMethod === vinLookupMethodSelections.MANUALVIN) { await this.dispatchStoreAction(storeActions.CLEAR_VIN); return this.$router.navigateWithSaving( this.navigationScenarios.SELECTED_MANUAL_VIN, - this.$route + this.pageName ); } if (this.selectedVinLookupMethod === vinLookupMethodSelections.LICENSEPLATE) { return this.$router.navigateWithSaving( this.navigationScenarios.SELECTED_LICENSE_PLATE, - this.$route + this.pageName ); } if (this.selectedVinLookupMethod === vinLookupMethodSelections.HOMEADDRESS) { return this.$router.navigateWithSaving( this.navigationScenarios.SELECTED_HOME_ADDRESS, - this.$route + this.pageName ); } if (this.selectedVinLookupMethod === vinLookupMethodSelections.DECLINE) { return this.$router.navigateWithSaving( this.navigationScenarios.SELECTED_NO_VIN, - this.$route + this.pageName ); } }, diff --git a/src/layouts/insurance-company/insurance-company.vue b/src/layouts/insurance-company/insurance-company.vue index c9409eb71..7efde9a68 100644 --- a/src/layouts/insurance-company/insurance-company.vue +++ b/src/layouts/insurance-company/insurance-company.vue @@ -58,6 +58,7 @@ import { experimentSettings } from "@/constants/experiments"; import { partNumberStrings } from "@/constants/part-number-strings"; import { deepClone } from "@/helpers/object-helper"; import store from "@/store"; +import { flushSaveSessionQueue } from "@/helpers/heritage-integration/order-helper"; export default { name: "insurance-company", @@ -81,7 +82,7 @@ export default { } // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); const insuranceCompanyListPromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_INSURANCE_COMPANY_LIST, {}, @@ -146,18 +147,20 @@ export default { // Go back to Quote page if (forceCashSelectionOnQuote) { this.$router.navigateWithoutSaving( - this.navigationScenarios.CLICKED_BACK, - this.$route, - { isCashSelected: true } + this.navigationScenarios.CLICKED_PAY_ON_MY_OWN, + this.pageName ); return; } - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, async forwardButtonAction() { // await any pending save-sessions. if you don't, we will save the new parent account into vuex and then a pending async save-session response overwrites it - await store.getters.applicationUser.saveSessionPromise; + await flushSaveSessionQueue(); await this.dispatchStoreAction( this.storeActions.SAVE_PARENT_ACCOUNT_NUMBER, diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index 223ca9ee7..a6bb07bab 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -119,6 +119,8 @@ import baseMixin from "@/mixins/base-mixin.js"; import store from "@/store"; import vinPagesMixin from "@/mixins/vin-pages-mixin"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; +import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; +import { queryStrings } from "@/constants/query-strings"; // DEFINE VALIDATION RULES defineRule("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIRED)); @@ -138,7 +140,7 @@ export default { mixins: [vinPagesMixin], async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ @@ -163,7 +165,8 @@ export default { data() { return { licensePlate: this.getLicensePlateFromStore(), - registrationZipCode: this.getRegistrationZipFromStore() ?? this.$route.query.zipcode, + registrationZipCode: + this.getRegistrationZipFromStore() ?? consumeQueryFromStash(queryStrings.ZIP_CODE), emailOrSms: this.getEmailOrSmsFromStore(), serviceZipCode: this.getServiceZipFromStore(), carId: this.getCarIdfromStore(), @@ -187,7 +190,10 @@ export default { }, backButtonAction() { // route to move backwards - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, attachCustomEvents() { this.prependActionToMethod(this, this.forwardButtonAction, () => { @@ -392,9 +398,7 @@ export default { if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true } + this.pageName ); } else { await this.navigateForwardWithSingleCarMatch(); diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index 2c5f5a7c3..82b1e1619 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -47,7 +47,7 @@ export default { mixins: [vehicleQuestionsMixin], async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index 1d7771474..89568fa37 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -47,7 +47,7 @@ export default { mixins: [vehicleQuestionsMixin], async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index d5c7d93c3..d07434c1f 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -168,6 +168,7 @@ import { getSubTotal, getSalesTax, } from "@/helpers/pricing-helper.js"; +import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED)); defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED)); @@ -179,7 +180,7 @@ export default { }, async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); const lineItemsFromStore = deepClone(store.getters.order.lineItems); @@ -281,7 +282,7 @@ export default { const oldActivePromos = store.getters.lineItems.promos?.slice(0); const oldInactivePromos = store.getters.order.payment.inactivePromos?.slice(0); - const promoCodeFromQueryString = getQuerystringParameter(queryStrings.PROMO); + const promoCodeFromQueryString = consumeQueryFromStash(queryStrings.PROMO); const { validatePromoResponse, revalidatePromoResponse } = await revalidatePromosAndValidateQueryStringPromo( promoCodeFromQueryString, @@ -374,7 +375,7 @@ export default { doesCopyContainRouterLink, getRouterLinkRouteFromCopy, navigateWithScenario(scenarioName) { - this.$router.navigateWithoutSaving(scenarioName, this.$route); + this.$router.navigateWithoutSaving(scenarioName, this.pageName); }, arePagePrerequisitesValid() { // Service Location @@ -537,7 +538,10 @@ export default { return this.$store.getters.order.isRecalAckOptIn; }, backButtonAction() { - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, async forwardButtonAction() { this.forwardClicked = true; @@ -575,16 +579,14 @@ export default { await submitWorkOrder({ pageNameToLog: "payment-method", submitAfterSave: true }); this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_FORWARD, - this.$route, - {}, - { [routerParams.DISPLAY_PIA_ALERT]: false } + this.pageName ); } else { if (this.paymentMethod == paymentMethods.INSURANCE) { this.dispatchStoreAction(this.storeActions.SAVE_PAYMENT_TYPE, true, false); return this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_INSURANCE, - this.$route + this.pageName ); } else { this.setupPia(); @@ -603,16 +605,14 @@ export default { } catch (error) { console.log("error: response from pia submit work order:" + error.message); this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); - this.$route.query[queryStrings.DISPLAY_PIA_ALERT] = true; + this.$route.query.piaError = true; return; } this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_PAY_NOW, - this.$route, - {}, - { [routerParams.DISPLAY_PIA_ALERT]: false } + this.pageName ); }, hasSubmittedOrder() { @@ -797,10 +797,7 @@ export default { return this.paymentMethodInternalModel; }, shouldDisplayPiaAlert() { - return ( - this.$route.query[queryStrings.DISPLAY_PIA_ALERT] || - getBoolFromString(window.history.state.displayPiaAlert) - ); + return getBoolFromString(this.$route?.query?.piaError); }, // Necessary to make the watcher of lineItems work // JavaScript does not keep a record of the old value, only a reference to it's location in the memory. diff --git a/src/layouts/payment-pia-return/payment-pia-return.vue b/src/layouts/payment-pia-return/payment-pia-return.vue index f0b4433ea..b39726948 100644 --- a/src/layouts/payment-pia-return/payment-pia-return.vue +++ b/src/layouts/payment-pia-return/payment-pia-return.vue @@ -39,20 +39,22 @@ export default { store.getters.order.payment.piaType === paymentMethods.APPLE_PAY || store.getters.order.payment.piaType === paymentMethods.AFTERPAY; if (paymentPageNavScenario) { - this.$router.navigateWithoutSaving( - this.navigationScenarios.PIA_CC_ERROR, - this.$route, - { - [queryStrings.DISPLAY_PIA_ALERT]: store.getters.order.payment.piaType, - } + const scenarios = { + [paymentMethods.CREDIT_CARD]: this.navigationScenarios.PIA_CC_ERROR, + [paymentMethods.APPLE_PAY]: this.navigationScenarios.PIA_APPLE_ERROR, + [paymentMethods.AFTERPAY]: this.navigationScenarios.PIA_AFTERPAY_ERROR, + }; + + const relevantScenario = scenarios[store.getters.order.payment.piaType]; + + await this.$router.navigateAndForceTopLevelNavigation( + relevantScenario, + this.pageName ); } else { - this.$router.navigateWithoutSaving( + await this.$router.navigateAndForceTopLevelNavigation( this.navigationScenarios.PIA_ERROR, - this.$route, - { - [queryStrings.DISPLAY_PIA_ALERT]: true, - } + this.pageName ); } } else { @@ -84,11 +86,9 @@ export default { } else { var msg = "Unknown Pia type: " + store.getters.order.payment.piaType; console.log(msg); - this.$router.navigateWithoutSaving( + await this.$router.navigateAndForceTopLevelNavigation( this.navigationScenarios.PIA_ERROR, - this.$route, - {}, - { [routerParams.DISPLAY_PIA_ALERT]: true } + this.pageName ); } } @@ -123,11 +123,9 @@ export default { " " + store.getters.order.referralSequenceNumber ); - this.$router.navigateWithoutSaving( + this.$router.navigateAndForceTopLevelNavigation( this.navigationScenarios.PIA_ERROR, - this.$route, - {}, - { [routerParams.DISPLAY_PIA_ALERT]: true } + this.pageName ); } else { const expMonth = getQuerystringParameter(queryStrings.CARD_EXPIRATION_MONTH); @@ -181,11 +179,9 @@ export default { }); } catch (error) { console.log("error: response from submit work order:" + error.message); - this.$router.navigateWithoutSaving( + this.$router.navigateAndForceTopLevelNavigation( this.navigationScenarios.PIA_ERROR, - this.$route, - {}, - { [routerParams.DISPLAY_PIA_ALERT]: true } + this.pageName ); this.$refs.loadingModal.isModalVisible = false; return; @@ -193,7 +189,10 @@ export default { this.$refs.loadingModal.isModalVisible = false; await baseMixin.methods.dispatchStoreAction(storeActions.CREATE_SUBMITTED_STATE); - this.$router.navigateWithoutSaving(this.navigationScenarios.PIA_SUCCESS, this.$route); + this.$router.navigateAndForceTopLevelNavigation( + this.navigationScenarios.PIA_SUCCESS, + this.pageName + ); }, }, components: { diff --git a/src/layouts/payment/payment.vue b/src/layouts/payment/payment.vue index 3c87f85f2..f2bdb6733 100644 --- a/src/layouts/payment/payment.vue +++ b/src/layouts/payment/payment.vue @@ -289,7 +289,7 @@ export default { }, async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); const signaturePromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_SIGNATURE, @@ -684,12 +684,16 @@ export default { }); await baseMixin.methods.dispatchStoreAction(storeActions.CREATE_SUBMITTED_STATE); - window.location = applicationConfig.CONFIRMATION_URL; + this.$router.navigateAndForceTopLevelNavigation( + this.navigationScenarios.CLICKED_PAY_LATER, + this.pageName + ); + //window.location = applicationConfig.CONFIRMATION_URL; } catch (error) { console.log("error: response from submit work order(payment pg):" + error.message); this.$router.navigateWithoutSaving( this.navigationScenarios.PIA_ERROR, - this.$route, + this.pageName, {}, { [routerParams.DISPLAY_PIA_ALERT]: true } ); @@ -698,16 +702,13 @@ export default { } }, backButtonAction() { - // The only way I could figure out how to get navigation to work on a page with the iframe. - // This is also how a cancel from Paypal would work. Just a redirect to the payment-method page. - // The normal navigation sort of works but the page does not render. The "next" callback function does not get - // invoked in payment-method's beforeroute enter. I also spotted an error in vue-router.esm-bundler.js when this - // happens but was unable to ignore it with a try catch. The navigation guard error is: - // Error: Redirected from "/?fmgPage=payment-method" to "{ params: {isSavingNation: "false"}, query: "fmgPage: "payment-method"}" - // I don't know if the navigation guard thinks the to and from are the same page. - // Also tried overriding with a $router.push - window.location = applicationConfig.PIA_CANCEL_URL; - //this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + // Used to set the url directly here. + // Now hooks into a shared set of logic for doing this, also used with `payment-pia-return`. + // And uses nav scenarios properly. + this.$router.navigateAndForceTopLevelNavigation( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, submitHopForm() { this.$nextTick(() => { @@ -804,10 +805,7 @@ export default { } }, shouldDisplayPiaAlert(payMethod) { - return ( - this.$route.query[queryStrings.DISPLAY_PIA_ALERT] === payMethod || - getBoolFromString(window.history.state.displayPiaAlert) - ); + return this.$route?.query?.piaErrorType === payMethod; }, }, components: { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 663f778c1..f100a9f32 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -169,17 +169,23 @@ import { } from "@/helpers/heritage-integration/cookie-helper"; import { showFmgLoadingModal } from "@/helpers/loading-modal-helper"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; +import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; import { storeMutations } from "@/constants/store-mutations"; defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); const INSURANCE_TAB_TO_DISPLAY_THRESHOLD_DEFAULT = 300; +const ACCEPTED_QUOTE_TYPES = { + CASH: "cash", + INSURANCE: "insurance", +}; + export default { name: "quote", async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_WIPERS, { @@ -216,7 +222,7 @@ export default { userId: getUserIdValue(), deviceId: getDeviceIdValue(), sessionKey: getSessionKeyValue(), - pageName: to.query.fmgPage, + pageName: to.name, experiment: skipQuoteExperiment, }, "quote", @@ -246,7 +252,7 @@ export default { userId: getUserIdValue(), deviceId: getDeviceIdValue(), sessionKey: getSessionKeyValue(), - pageName: to.query.fmgPage, + pageName: to.name, experiment: afterpayBreakoutDisplayExperiment, }, "quote", @@ -353,7 +359,7 @@ export default { const oldActivePromos = store.getters.lineItems.promos?.slice(0); const oldInactivePromos = store.getters.order.payment.inactivePromos?.slice(0); - const promoCodeFromQueryString = getQuerystringParameter(queryStrings.PROMO); + const promoCodeFromQueryString = consumeQueryFromStash(queryStrings.PROMO); const { validatePromoResponse, revalidatePromoResponse } = await revalidatePromosAndValidateQueryStringPromo( promoCodeFromQueryString, @@ -403,10 +409,15 @@ export default { } const getIsInsuranceSelectedValue = (availableLineItems, insuranceThreshold) => { - // query param checked here is set on insurance-selection "Pay on my own" link click - if (to.query?.isCashSelected || to.query?.iscashselected) { + // Override auto-select if specified + const quoteTypeParam = to.query?.offer?.toLowerCase(); + + if (quoteTypeParam === ACCEPTED_QUOTE_TYPES.CASH) { return false; + } else if (quoteTypeParam === ACCEPTED_QUOTE_TYPES.INSURANCE) { + return true; } + const serviceLocationState = store.getters.order.serviceLocation.state; // usually true when returning from heritage but can be false when returning from heritage on a save quote @@ -760,12 +771,12 @@ export default { if (payment.isInsurance) { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITH_INSURANCE, - this.$route + this.pageName ); } else { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITH_CASH, - this.$route + this.pageName ); } diff --git a/src/layouts/return-user/return-user.vue b/src/layouts/return-user/return-user.vue index d655a0c14..6b2a36f7e 100644 --- a/src/layouts/return-user/return-user.vue +++ b/src/layouts/return-user/return-user.vue @@ -55,7 +55,7 @@ export default { name: "return-user", async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ { @@ -85,7 +85,7 @@ export default { async forwardButtonAction() { this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_FORWARD, - this.$route + this.pageName ); }, @@ -96,11 +96,9 @@ export default { "Start over", true ); - deleteFunnelCookie(); - await this.dispatchStoreAction(storeActions.RESET_STATE); this.$router.navigateWithoutSaving( - this.navigationScenarios.CLICKED_FORWARD, - this.$route + this.navigationScenarios.CLICKED_RESTART, + this.pageName ); }, }, diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index ae05b9358..b47de1fa8 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -267,7 +267,7 @@ export default { } // Set up promises - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); const alertReasonsPromise = locationAlerts.methods.loadInitialData( store.getters.order.serviceLocation.zipCodeCtu, @@ -536,7 +536,10 @@ export default { } }, backButtonAction() { - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, forwardButtonAction() { this.updateSupportingItems(); @@ -585,7 +588,10 @@ export default { ); } - this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route); + this.$router.navigateWithSaving( + this.navigationScenarios.CLICKED_FORWARD, + this.pageName + ); }, setDisplayWaitList() { if ( diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 3b37c8406..752d0c4c9 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -219,7 +219,7 @@ export default { }, async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); const serviceZipCode = store.getters.order.serviceLocation.zipCode; const zipCodeDataPromise = getZipCodeData(serviceZipCode); @@ -611,7 +611,7 @@ export default { } else { this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_BACK, - this.$route + this.pageName ); } }, @@ -746,7 +746,10 @@ export default { this.updateAndSaveSupportingItems(); this.updateAndSaveIsMSRFeeApplicable(); - this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route); + this.$router.navigateWithSaving( + this.navigationScenarios.CLICKED_FORWARD, + this.pageName + ); }, setMobileLocationInValid(isMobileLocationInValid) { this.isMobileAddressValid = !isMobileLocationInValid; diff --git a/src/layouts/service-zip/service-zip.vue b/src/layouts/service-zip/service-zip.vue index ae6ff4ecf..16c6f7f72 100644 --- a/src/layouts/service-zip/service-zip.vue +++ b/src/layouts/service-zip/service-zip.vue @@ -96,6 +96,7 @@ import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; import baseMixin from "@/mixins/base-mixin.js"; import { queryStrings } from "@/constants/query-strings"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; +import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; // Define Validation Rules defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); @@ -115,7 +116,7 @@ export default { mixins: [vinPagesMixin], data() { return { - serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode, + serviceZipCode: this.getZipFromStore() ?? consumeQueryFromStash(queryStrings.ZIP_CODE), emailOrSms: this.getEmailOrSmsFromStore(), carId: this.getCarIdfromStore(), isHeavyTruck: this.getIsVehicleHeavyTruckServiceableFromStore(), @@ -127,7 +128,7 @@ export default { async beforeRouteEnter(to, from, next) { //Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); //Settle promises and get results const promiseResultMap = [ @@ -214,12 +215,12 @@ export default { if (skipVin) { this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_BACK_WITH_SKIP_VIN, - this.$route + this.pageName ); } else { this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_BACK, - this.$route + this.pageName ); } }, @@ -317,7 +318,7 @@ export default { await saveSession({ pageNameToLog: "service-zip" }); return this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITH_NO_QUESTIONS, - this.$route + this.pageName ); } else { // if we're skipping the vin-lookup but it's not a repair, we still need to get the parts diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index 46efb4728..488ad1eb4 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -110,7 +110,7 @@ export default { name: "vehicle-damage", async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); const damageOptionsPromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_DAMAGE_OPTIONS, @@ -249,7 +249,10 @@ export default { backButtonAction() { // route to move backwards - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.pageName + ); }, getDamageLocationsFromStore() { @@ -455,34 +458,26 @@ export default { if (skipVin) { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITH_SKIP_VIN, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false } + this.pageName ); } else { if (store.getters.damage.isRepair) { this.$router.navigateWithSaving( this.navigationScenarios .CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false } + this.pageName ); } else { if (store.getters.vehicle.vin) { this.$router.navigateWithSaving( this.navigationScenarios .CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false } + this.pageName ); } else { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false } + this.pageName ); } } @@ -492,23 +487,17 @@ export default { else if (store.getters.vehicle.vin) { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITH_VIN, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false } + this.pageName ); } else if (skipVin) { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITH_SKIP_VIN, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false } + this.pageName ); } else { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false } + this.pageName ); } }, @@ -637,7 +626,7 @@ export default { ); }, shouldDisplayVehicleChangeAlert() { - return getBoolFromString(window.history.state.displayVehicleChangeAlert); + return getBoolFromString(this.$route?.query?.displayVehicleChangeAlert); }, shouldHideBackButton() { return this.$store.getters.requiresVerifiedRedirecting; diff --git a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue index 280edfc6c..5f06391c1 100644 --- a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue +++ b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue @@ -154,7 +154,7 @@ export default { }, PartDataFromApi() { - return this.$store.getters.pageData(this.$route.query.fmgPage) ?? {}; + return this.$store.getters.pageData(this.pageName) ?? {}; }, }, methods: { diff --git a/src/layouts/vehicle-parts/vehicle-parts.vue b/src/layouts/vehicle-parts/vehicle-parts.vue index 4b68007f9..4298b74cb 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.vue +++ b/src/layouts/vehicle-parts/vehicle-parts.vue @@ -81,7 +81,7 @@ export default { mixins: [vehicleQuestionsMixin], async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ { diff --git a/src/layouts/vehicle/vehicle.vue b/src/layouts/vehicle/vehicle.vue index bad52fb02..1d2e7d2bb 100644 --- a/src/layouts/vehicle/vehicle.vue +++ b/src/layouts/vehicle/vehicle.vue @@ -110,6 +110,10 @@ import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; import { applicationConfig } from "../../constants/application-config"; import { queryStrings } from "@/constants/query-strings"; import { getQuerystringParameter } from "@/helpers/querystring-helper"; +import { + consumeQueryFromStash, + peekQueryFromStash, +} from "@/router/a-rewrite/logic/querystring-stash"; //define validation rules defineRule("year-required", required(errorMessages.YEAR_REQUIRED)); @@ -133,7 +137,7 @@ export default { imageUrl: this.getImagefromStore(), imageVifNumber: this.getImageVifNumberfromStore(), imageVifColor: this.getImageVifColorfromStore(), - serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode, + serviceZipCode: this.getZipFromStore() ?? peekQueryFromStash(queryStrings.ZIP_CODE), yearOptions: [], makeOptions: [], modelOptions: [], @@ -154,7 +158,7 @@ export default { ); } // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); const experimentForLogging = store.getters.applicationUser.experiments.find( (e) => e.universeName === experimentUniverses.CONCEPT_FUNNEL ); @@ -213,7 +217,7 @@ export default { userId: getUserIdValue(), deviceId: getDeviceIdValue(), sessionKey: getSessionKeyValue(), - pageName: to.query.fmgPage, + pageName: to.name, experiment: experimentForLogging, }, "vehicle", @@ -536,7 +540,10 @@ export default { } } - this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route); + this.$router.navigateWithSaving( + this.navigationScenarios.CLICKED_FORWARD, + this.pageName + ); }, initializeYearComponent(initialData) { this.yearOptions = initialData; diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index 23875e3e9..5db93d76d 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -160,6 +160,8 @@ import baseMixin from "@/mixins/base-mixin.js"; import store from "@/store"; import vinPagesMixin from "@/mixins/vin-pages-mixin"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; +import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; +import { queryStrings } from "@/constants/query-strings"; // DEFINE VALIDATION RULES defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); @@ -180,7 +182,7 @@ export default { mixins: [vinPagesMixin], async beforeRouteEnter(to, from, next) { // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + const cmsContentPromise = fetchCmsContentForPage(to.name); // Settle promises and get results const promiseResultMap = [ @@ -203,7 +205,7 @@ export default { data() { return { vin: this.getVinFromStore(), - serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode, + serviceZipCode: this.getZipFromStore() ?? consumeQueryFromStash(queryStrings.ZIP_CODE), emailOrSms: this.getEmailOrSmsFromStore(), carId: this.getCarIdfromStore(), isHeavyTruck: this.getIsVehicleHeavyTruckServiceableFromStore(), @@ -247,12 +249,12 @@ export default { if (this.$store.getters.vehicle.vin) { this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_BACK_WITH_VIN, - this.$route + this.pageName ); } else { this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_BACK, - this.$route + this.pageName ); } }, @@ -474,9 +476,7 @@ export default { if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) { this.$router.navigateWithSaving( this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS, - this.$route, - {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true } + this.pageName ); } else { await this.navigateForwardWithSingleCarMatch(); diff --git a/src/main.js b/src/main.js index 1017651f8..5b823125b 100644 --- a/src/main.js +++ b/src/main.js @@ -2,7 +2,7 @@ import { createApp } from "vue"; import LoadScript from "vue-plugin-load-script"; import Maska from "maska"; import App from "./App.vue"; -import router from "./router"; +import router from "./router/a-rewrite"; import store from "@/store"; import baseMixin from "@/mixins/base-mixin.js"; import analyticsMixin from "@/mixins/analytics-mixin.js"; diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js index b29eae8c1..e39908a8f 100644 --- a/src/mixins/base-mixin.js +++ b/src/mixins/base-mixin.js @@ -2,7 +2,7 @@ import store from "@/store"; import { storeActions } from "@/constants/store-actions.js"; import { storeMutations } from "@/constants/store-mutations.js"; import { sessionStorageKeyConstants } from "@/constants/session-storage.js"; -import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; +import { navigationScenarios } from "@/router/a-rewrite/constants/navigation-scenarios"; import { vehicleCategories } from "@/constants/vehicle-categories.js"; import { routerParams } from "@/router/router-constants/router-params"; import { queryStrings } from "@/constants/query-strings"; @@ -15,6 +15,7 @@ export default { data() { return { cmsContentByWidget: {}, + _componentPageName: null, }; }, methods: { @@ -246,9 +247,15 @@ export default { cssClassNameForCmsWidget() { return "widget-name-" + this.cmsWidgetName; }, + pageName() { + return this._componentPageName ?? this.$route.name; + }, }, mounted() { + // Store route immutably so that components know their originating page even during page transition. + this._componentPageName = this.$route.name; + if (!store.getters.externalParameterState?.isExternalParameter) { showFmgLoadingModal(false); } diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 517fc7c90..ab39462ce 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -65,10 +65,10 @@ export default { orderedVehicleQuestionPages.indexOf(fmgPage) ); }, - currentPageComesBeforePage(currentPage = this.$route.query.fmgPage, fmgPage) { + currentPageComesBeforePage(currentPage = this.pageName, fmgPage) { return this.comparePageIndices(currentPage, fmgPage) < 0; }, - currentPageComesAfterPage(currentPage = this.$route.query.fmgPage, fmgPage) { + currentPageComesAfterPage(currentPage = this.pageName, fmgPage) { return this.comparePageIndices(currentPage, fmgPage) > 0; }, setupInitialData(glass, index, alreadyAnsweredQuestions, vm) { @@ -359,7 +359,7 @@ export default { // Can't use `this` because navigateForward is also called from vin-pages-mixin async navigateForward(partsOrQuestions, vm) { const self = vm ?? this; - const currentPage = self.$route.query.fmgPage; + const currentPage = self.pageName; const hasPartQuestions = this.hasPartQuestions(partsOrQuestions); const hasGlassLocationWithMultipleParts = @@ -371,11 +371,9 @@ export default { hasPartQuestions && this.currentPageComesBeforePage(currentPage, fmgPageValues.PART_QUESTIONS) ) { - self.$router.navigateWithSaving( + self.$router.navigateWithPageData( self.navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, - self.$route, - {}, - {}, + self.pageName, { partsOrQuestions: partsOrQuestions } ); } else if ( @@ -384,11 +382,9 @@ export default { ) { // if multiple parts on any glass // go to vehicle-parts page and pass the partsData - self.$router.navigateWithSaving( + self.$router.navigateWithPageData( self.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, - self.$route, - {}, - {}, + self.pageName, { partsOrQuestions: partsOrQuestions } ); } else if ( @@ -397,11 +393,9 @@ export default { ) { // if any childpart questions // go to molding-questions page and pass the partsData - self.$router.navigateWithSaving( + self.$router.navigateWithPageData( self.navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, - self.$route, - {}, - {}, + self.pageName, { partsOrQuestions: partsOrQuestions } ); } else if ( @@ -438,11 +432,9 @@ export default { } } - self.$router.navigateWithSaving( + self.$router.navigateWithPageData( self.navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, - self.$route, - {}, - {}, + self.pageName, { partsOrQuestions } ); } else { @@ -477,7 +469,7 @@ export default { } else { self.$router.navigateWithSaving( self.navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, - self.$route + self.pageName ); } } @@ -485,7 +477,7 @@ export default { // Can't use `this` because navigateForward is also called from quote async navigateBack(vm) { const self = vm ?? this; - const currentPage = self.$route.query.fmgPage; + const currentPage = self.pageName; const pageDataCapabilityQuestions = self.$store.getters.pageData( fmgPageValues.CAPABILITY_QUESTIONS ); @@ -539,7 +531,7 @@ export default { backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS; } - self.$router.navigateWithoutSaving(backNavigationScenario, self.$route); + self.$router.navigateWithoutSaving(backNavigationScenario, self.pageName); }, }, }; diff --git a/src/router/a-rewrite/constants/auto-route-table.js b/src/router/a-rewrite/constants/auto-route-table.js new file mode 100644 index 000000000..0bf3503b9 --- /dev/null +++ b/src/router/a-rewrite/constants/auto-route-table.js @@ -0,0 +1,13 @@ +import { routeData } from "./routes"; + +export const autoRouteTable = [ + routeData.QUOTE, + routeData.CAPABILITY_QUESTIONS, + routeData.MOLDING_QUESTIONS, + routeData.VEHICLE_PARTS, + routeData.PART_QUESTIONS, + routeData.VIN_LOOKUP, + routeData.ESTIMATE, + routeData.VEHICLE_DAMAGE, + routeData.VEHICLE, +]; diff --git a/src/router/a-rewrite/constants/navigation-scenarios.js b/src/router/a-rewrite/constants/navigation-scenarios.js new file mode 100644 index 000000000..a6e117948 --- /dev/null +++ b/src/router/a-rewrite/constants/navigation-scenarios.js @@ -0,0 +1,69 @@ +/** + * We want to name these to describe the scenario rather than what page(s) they're used on. + * + * Naming convention: [PAST_TENSE_VERB]_[DESCRIPTOR_OF_STATE] + * ex: Rather than "HAS_PART_QUESTIONS", we might name the + * scenario "CLICKED_FORWARD_WITH_PART_QUESTIONS" + */ + +const navigationScenarios = { + // General + CLICKED_BACK: "CLICKED_BACK", + CLICKED_FORWARD: "CLICKED_FORWARD", + CLICKED_FORWARD_WITH_CASH: "CLICKED_FORWARD_WITH_CASH", + CLICKED_FORWARD_WITH_INSURANCE: "CLICKED_FORWARD_WITH_INSURANCE", + + // TODO: use virtual page? + // Vin selection + CLICKED_BACK_WITH_VIN: "CLICKED_BACK_WITH_VIN", + CLICKED_BACK_WITH_SKIP_VIN: "CLICKED_BACK_WITH_SKIP_VIN", + CLICKED_FORWARD_WITH_VIN: "CLICKED_FORWARD_WITH_VIN", + CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE: + "CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE", + CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE: + "CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE", + CLICKED_FORWARD_WITHOUT_VIN: "CLICKED_FORWARD_WITHOUT_VIN", + CLICKED_FORWARD_WITH_SKIP_VIN: "CLICKED_FORWARD_WITH_SKIP_VIN", + CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES: "CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES", + SELECTED_VIN_WITH_MISMATCHED_GLASS: "SELECTED_VIN_WITH_MISMATCHED_GLASS", + SELECTED_MANUAL_VIN: "SELECTED_MANUAL_VIN", + SELECTED_LICENSE_PLATE: "SELECTED_LICENSE_PLATE", + SELECTED_HOME_ADDRESS: "SELECTED_HOME_ADDRESS", + SELECTED_NO_VIN: "SELECTED_NO_VIN", + CLICKED_FORWARD_WITH_NO_QUESTIONS: "CLICKED_FORWARD_WITH_NO_QUESTIONS", + CLICKED_VIN_RETRY: "CLICKED_VIN_RETRY", + + // Part selection + CLICKED_FORWARD_WITH_PART_QUESTIONS: "CLICKED_FORWARD_WITH_PART_QUESTIONS", + CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE: "CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE", + 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_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", + CLICKED_BACK_WITH_CAPABILITY_QUESTIONS: "CLICKED_BACK_WITH_CAPABILITY_QUESTIONS", + CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS: "CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS", + CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS: "CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS", + + // Insurance-Company + CLICKED_PAY_ON_MY_OWN: "CLICKED_PAY_ON_MY_OWN", + + // Schedule + CLICKED_CHANGE_LOCATION: "CLICKED_CHANGE_LOCATION", + + // Payment + CLICKED_INSURANCE: "CLICKED_INSURANCE", + CLICKED_PAY_NOW: "CLICKED_PAY_NOW", + CLICKED_PAY_LATER: "CLICKED_PAY_LATER", + PIA_ERROR: "PIA_ERROR", + PIA_CC_ERROR: "PIA_CC_ERROR", + PIA_APPLE_ERROR: "PIA_APPLE_ERROR", + PIA_AFTERPAY_ERROR: "PIA_AFTERPAY_ERROR", + PIA_SUCCESS: "PIA_SUCCESS", + + // Return User + CLICKED_RESTART: "CLICKED_RESTART", +}; + +export { navigationScenarios }; diff --git a/src/router/a-rewrite/constants/route-prefix.js b/src/router/a-rewrite/constants/route-prefix.js new file mode 100644 index 000000000..7e5c6f1b9 --- /dev/null +++ b/src/router/a-rewrite/constants/route-prefix.js @@ -0,0 +1,3 @@ +export const ROUTE_PREFIX_TRIMMED = "fmg"; + +export const ROUTE_PREFIX_FULL = `/${ROUTE_PREFIX_TRIMMED}/`; diff --git a/src/router/a-rewrite/constants/routes.js b/src/router/a-rewrite/constants/routes.js new file mode 100644 index 000000000..d03954867 --- /dev/null +++ b/src/router/a-rewrite/constants/routes.js @@ -0,0 +1,123 @@ +export const routeData = { + VEHICLE: { + name: "vehicle", + path: "/vehicle", + }, + VEHICLE_DAMAGE: { + name: "vehicle-damage", + path: "/vehicle-damage", + }, + ESTIMATE: { + name: "estimate", + path: "/estimate", + }, + ADDRESS_LOOKUP: { + name: "address-lookup", + path: "/address-lookup", + }, + VIN_LOOKUP: { + name: "vin-lookup", + path: "/vin-lookup", + }, + LICENSE_PLATE_LOOKUP: { + name: "license-plate-lookup", + path: "/license-plate-lookup", + }, + SERVICE_ZIP: { + name: "service-zip", + path: "/service-zip", + }, + ADDRESS_VEHICLES: { + name: "address-vehicles", + path: "/address-vehicles", + }, + VEHICLE_PARTS: { + name: "vehicle-parts", + path: "/vehicle-parts", + }, + PART_QUESTIONS: { + name: "part-questions", + path: "/part-questions", + }, + MOLDING_QUESTIONS: { + name: "molding-questions", + path: "/molding-questions", + }, + CAPABILITY_QUESTIONS: { + name: "capability-questions", + path: "/capability-questions", + }, + QUOTE: { + name: "quote", + path: "/quote", + }, + INSURANCE_COMPANY: { + name: "insurance-company", + path: "/insurance-company", + }, + SERVICE_LOCATION: { + name: "service-location", + path: "/service-location", + }, + HERITAGE: { + name: "heritage", + path: "/virtual/heritage", + virtual: true, + }, + SCHEDULE: { + name: "schedule", + path: "/schedule", + }, + CUSTOMER_DETAILS: { + name: "customer-details", + path: "/customer-details", + }, + PAYMENT_METHOD: { + name: "payment-method", + path: "/payment-method", + }, + PAYMENT: { + name: "payment", + path: "/payment", + }, + PAYMENT_PIA_RETURN: { + name: "payment-pia-return", + path: "/payment-pia-return", + }, + CONFIRMATION: { + name: "confirmation", + path: "/confirmation", + }, + RETURN_USER: { + name: "return-user", + path: "/return-user", + }, + LOAD_SESSION: { + name: "load-session", + path: "/virtual/load-session", + virtual: true, + }, + LANDING: { + name: "landing", + path: "/", + virtual: true, + }, + AUTO_ROUTE: { + name: "auto-route", + path: "/virtual/auto-route", + virtual: true, + }, + // TODO: RENAME FROM BAILOUT + ERROR: { + name: "error", + path: "/virtual/error", + virtual: true, + }, + RESTART: { + name: "restart", + path: "/virtual/restart", + virtual: true, + }, +}; + +export const FUNNEL_START_PAGE = routeData.VEHICLE; diff --git a/src/router/a-rewrite/constants/routing-table.js b/src/router/a-rewrite/constants/routing-table.js new file mode 100644 index 000000000..10ee7ae90 --- /dev/null +++ b/src/router/a-rewrite/constants/routing-table.js @@ -0,0 +1,596 @@ +import { routeData } from "@/router/a-rewrite/constants/routes"; +import { navigationScenarios } from "@/router/a-rewrite/constants/navigation-scenarios"; +import store from "@/store"; +import { paymentMethods } from "../../../constants/payment-method-constants"; + +// Get as function to live-evaluate filters +const routingTable = function () { + return [ + { + pageName: routeData.VEHICLE.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.VEHICLE_DAMAGE, + }, + ], + }, + { + pageName: routeData.VEHICLE_DAMAGE.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.VEHICLE, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_VIN, + destinationPageData: routeData.VIN_LOOKUP, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN, + destinationPageData: routeData.ESTIMATE, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_SKIP_VIN, + destinationPageData: routeData.SERVICE_ZIP, + }, + { + scenario: + navigationScenarios.CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE, + destinationPageData: routeData.SERVICE_ZIP, + }, + { + scenario: + navigationScenarios.CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE, + destinationPageData: routeData.VIN_LOOKUP, + }, + ], + }, + { + pageName: routeData.VIN_LOOKUP.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.ESTIMATE, + }, + { + scenario: navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS, + destinationPageData: routeData.VEHICLE_DAMAGE, + params: { + displayVehicleChangeAlert: true, + }, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_VIN, + destinationPageData: routeData.VEHICLE_DAMAGE, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + destinationPageData: routeData.PART_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + destinationPageData: routeData.VEHICLE_PARTS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, + destinationPageData: routeData.MOLDING_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + destinationPageData: routeData.CAPABILITY_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + destinationPageData: routeData.QUOTE, + }, + { + scenario: navigationScenarios.CLICKED_VIN_RETRY, + destinationPageData: routeData.ESTIMATE, + }, + ], + }, + { + pageName: routeData.LICENSE_PLATE_LOOKUP.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.ESTIMATE, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.VEHICLE_DAMAGE, + params: { + displayVehicleChangeAlert: true, + }, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + destinationPageData: routeData.PART_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + destinationPageData: routeData.VEHICLE_PARTS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, + destinationPageData: routeData.MOLDING_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + destinationPageData: routeData.CAPABILITY_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + destinationPageData: routeData.QUOTE, + }, + { + scenario: navigationScenarios.CLICKED_VIN_RETRY, + destinationPageData: routeData.ESTIMATE, + }, + ], + }, + { + pageName: routeData.ADDRESS_LOOKUP.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.ESTIMATE, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES, + destinationPageData: routeData.ADDRESS_VEHICLES, + }, + { + scenario: navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS, + destinationPageData: routeData.VEHICLE_DAMAGE, + params: { + displayVehicleChangeAlert: true, + }, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + destinationPageData: routeData.PART_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + destinationPageData: routeData.VEHICLE_PARTS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, + destinationPageData: routeData.MOLDING_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + destinationPageData: routeData.CAPABILITY_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + destinationPageData: routeData.QUOTE, + }, + { + scenario: navigationScenarios.CLICKED_VIN_RETRY, + destinationPageData: routeData.ESTIMATE, + }, + ], + }, + { + pageName: routeData.ADDRESS_VEHICLES.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.ADDRESS_LOOKUP, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.VEHICLE_DAMAGE, + params: { + displayVehicleChangeAlert: true, + }, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + destinationPageData: routeData.PART_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + destinationPageData: routeData.VEHICLE_PARTS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, + destinationPageData: routeData.MOLDING_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + destinationPageData: routeData.CAPABILITY_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + destinationPageData: routeData.QUOTE, + }, + { + scenario: navigationScenarios.CLICKED_VIN_RETRY, + destinationPageData: routeData.ESTIMATE, + }, + ], + }, + { + pageName: routeData.ESTIMATE.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.VEHICLE_DAMAGE, + }, + { + scenario: navigationScenarios.SELECTED_MANUAL_VIN, + destinationPageData: routeData.VIN_LOOKUP, + }, + { + scenario: navigationScenarios.SELECTED_LICENSE_PLATE, + destinationPageData: routeData.LICENSE_PLATE_LOOKUP, + }, + { + scenario: navigationScenarios.SELECTED_HOME_ADDRESS, + destinationPageData: routeData.ADDRESS_LOOKUP, + }, + { + scenario: navigationScenarios.SELECTED_NO_VIN, + destinationPageData: routeData.SERVICE_ZIP, + }, + ], + }, + { + pageName: routeData.SERVICE_ZIP.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.ESTIMATE, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_SKIP_VIN, + destinationPageData: routeData.VEHICLE_DAMAGE, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_QUESTIONS, + destinationPageData: routeData.QUOTE, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + destinationPageData: routeData.PART_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + destinationPageData: routeData.VEHICLE_PARTS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, + destinationPageData: routeData.MOLDING_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + destinationPageData: routeData.CAPABILITY_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + destinationPageData: routeData.QUOTE, + }, + ], + }, + { + pageName: routeData.PART_QUESTIONS.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS, + destinationPageData: routeData.VIN_LOOKUP, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS, + destinationPageData: routeData.SERVICE_ZIP, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + destinationPageData: routeData.VEHICLE_PARTS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, + destinationPageData: routeData.MOLDING_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + destinationPageData: routeData.CAPABILITY_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + destinationPageData: routeData.QUOTE, + }, + ], + }, + { + pageName: routeData.VEHICLE_PARTS.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, + destinationPageData: routeData.PART_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS, + destinationPageData: routeData.VIN_LOOKUP, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS, + destinationPageData: routeData.SERVICE_ZIP, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, + destinationPageData: routeData.MOLDING_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + destinationPageData: routeData.CAPABILITY_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + destinationPageData: routeData.QUOTE, + }, + ], + }, + { + pageName: routeData.MOLDING_QUESTIONS.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS, + destinationPageData: routeData.VIN_LOOKUP, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS, + destinationPageData: routeData.SERVICE_ZIP, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, + destinationPageData: routeData.PART_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, + destinationPageData: routeData.VEHICLE_PARTS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + destinationPageData: routeData.CAPABILITY_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + destinationPageData: routeData.QUOTE, + }, + ], + }, + { + pageName: routeData.CAPABILITY_QUESTIONS.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS, + destinationPageData: routeData.VIN_LOOKUP, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS, + destinationPageData: routeData.SERVICE_ZIP, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, + destinationPageData: routeData.PART_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, + destinationPageData: routeData.VEHICLE_PARTS, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS, + destinationPageData: routeData.MOLDING_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + destinationPageData: routeData.QUOTE, + }, + ], + }, + { + pageName: routeData.QUOTE.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS, + destinationPageData: routeData.VIN_LOOKUP, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS, + destinationPageData: routeData.SERVICE_ZIP, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, + destinationPageData: routeData.PART_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, + destinationPageData: routeData.VEHICLE_PARTS, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS, + destinationPageData: routeData.MOLDING_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS, + destinationPageData: routeData.CAPABILITY_QUESTIONS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_CASH, + destinationPageData: routeData.SERVICE_LOCATION, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_INSURANCE, + destinationPageData: routeData.INSURANCE_COMPANY, + }, + ], + }, + { + pageName: routeData.INSURANCE_COMPANY.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.QUOTE, + }, + { + scenario: navigationScenarios.CLICKED_PAY_ON_MY_OWN, + destinationPageData: routeData.QUOTE, + params: { + offer: "cash", + }, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.INSURANCE_DETAILS, + }, + ], + }, + { + pageName: routeData.SERVICE_LOCATION.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.QUOTE, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.SCHEDULE, + }, + ], + }, + { + pageName: routeData.SCHEDULE.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.SERVICE_LOCATION, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.CUSTOMER_DETAILS, + }, + { + scenario: navigationScenarios.CLICKED_CHANGE_LOCATION, + destinationPageData: routeData.SERVICE_LOCATION, + }, + ], + }, + { + pageName: routeData.CUSTOMER_DETAILS.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.SCHEDULE, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.PAYMENT_METHOD, + }, + { + scenario: navigationScenarios.CLICKED_PAY_NOW, + destinationPageData: routeData.PAYMENT_METHOD, + }, + ], + }, + { + pageName: routeData.PAYMENT_METHOD.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.CUSTOMER_DETAILS, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.CONFIRMATION, + }, + { + scenario: navigationScenarios.CLICKED_PAY_NOW, + destinationPageData: routeData.PAYMENT, + }, + { + scenario: navigationScenarios.CLICKED_INSURANCE, + destinationPageData: routeData.INSURANCE_COMPANY, + }, + ], + }, + { + pageName: routeData.PAYMENT.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationPageData: routeData.PAYMENT_METHOD, + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.CONFIRMATION, + }, + { + scenario: navigationScenarios.PIA_ERROR, + destinationPageData: routeData.PAYMENT_METHOD, + params: { + piaError: "true", + }, + }, + ], + }, + { + pageName: routeData.PAYMENT_PIA_RETURN.name, + maps: [ + { + scenario: navigationScenarios.PIA_ERROR, + destinationPageData: routeData.PAYMENT_METHOD, + params: { + piaError: "true", + }, + }, + { + scenario: navigationScenarios.PIA_CC_ERROR, + destinationPageData: routeData.PAYMENT, + params: { + piaErrorType: paymentMethods.CREDIT_CARD, + }, + }, + { + scenario: navigationScenarios.PIA_APPLE_ERROR, + destinationPageData: routeData.PAYMENT, + params: { + piaErrorType: paymentMethods.APPLE_PAY, + }, + }, + { + scenario: navigationScenarios.PIA_AFTERPAY_ERROR, + destinationPageData: routeData.PAYMENT, + params: { + piaErrorType: paymentMethods.AFTERPAY, + }, + }, + { + scenario: navigationScenarios.PIA_SUCCESS, + destinationPageData: routeData.CONFIRMATION, + }, + ], + }, + { + pageName: routeData.CONFIRMATION.name, + }, + { + pageName: routeData.RETURN_USER.name, + maps: [ + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationPageData: routeData.LOAD_SESSION, + }, + { + scenario: navigationScenarios.CLICKED_RESTART, + destinationPageData: routeData.RESTART, + }, + ], + }, + ]; +}; + +export { routingTable }; diff --git a/src/router/a-rewrite/index.js b/src/router/a-rewrite/index.js new file mode 100644 index 000000000..3a84a1730 --- /dev/null +++ b/src/router/a-rewrite/index.js @@ -0,0 +1,421 @@ +import { routeData, FUNNEL_START_PAGE } from "@/router/a-rewrite/constants/routes"; +import { createRoute, createVirtualRoute } from "@/router/a-rewrite/logic/create-route"; +import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; +import { createWebHistory, createRouter } from "vue-router"; +import { getDestination } from "@/router/a-rewrite/logic/get-destination"; +import analyticsMixin from "@/mixins/analytics-mixin"; +import { + getFunnelCookie, + deleteFunnelCookie, + updateOrCreateFunnelCookie, +} from "@/helpers/heritage-integration/cookie-helper"; +import { isSavedSessionStillActive } from "@/helpers/heritage-integration/session-helper"; +import { loadSessionIfPresent, saveSession } from "@/helpers/heritage-integration/order-helper"; +import store from "@/store"; +import { storeActions } from "@/constants/store-actions"; +import { storeMutations } from "@/constants/store-mutations"; +import { sessionStorageKeyConstants } from "@/constants/session-storage"; +import { savePageData } from "@/router/a-rewrite/logic/save-page-data"; +import eventBus from "@/helpers/event-bus/event-bus"; +import { globalEvents, globalEventTypes } from "@/constants/events"; +import { autoRouteTable } from "@/router/a-rewrite/constants/auto-route-table"; +import { queryStrings } from "@/constants/query-strings"; +import { consumeReferralQuerystrings } from "@/router/a-rewrite/logic/consume-referral-info"; +import { initializeFromQueryStrings } from "@/router/a-rewrite/logic/initialize-from-querystrings"; +import { getBoolFromString } from "@/helpers/boolean-helper"; +import { isVerifiedInsurance } from "@/router/a-rewrite/logic/requires-verified-redirect"; +import baseMixin from "@/mixins/base-mixin"; +import { runExperiments } from "@/router/a-rewrite/logic/run-experiments"; +import { ROUTE_PREFIX_FULL } from "@/router/a-rewrite/constants/route-prefix"; +import { buildManualUrl } from "@/router/a-rewrite/logic/build-manual-url"; +import { consumeQueryFromStash, stashAllQueries } from "@/router/a-rewrite/logic/querystring-stash"; + +const routes = [ + // Non-virtual pages. + createRoute(routeData.VEHICLE, async (to, from) => { + // If cookie indicates that vehicle has changed during insurance flow, reset parts info. + const hasVehicleChanged = getBoolFromString(getFunnelCookie()?.HasDelayedClaimRegistration); + if (hasVehicleChanged) { + store.commit(storeMutations.RESET_GLASS_PARTS_STATE); + } + + if (isVerifiedInsurance()) { + return { + name: routeData.VEHICLE_DAMAGE.name, + replace: true, + }; + } + }), + createRoute(routeData.VEHICLE_DAMAGE), + createRoute(routeData.ESTIMATE), + createRoute(routeData.ADDRESS_LOOKUP), + createRoute(routeData.VIN_LOOKUP), + createRoute(routeData.LICENSE_PLATE_LOOKUP), + createRoute(routeData.SERVICE_ZIP), + createRoute(routeData.ADDRESS_VEHICLES), + createRoute(routeData.VEHICLE_PARTS), + createRoute(routeData.PART_QUESTIONS), + createRoute(routeData.MOLDING_QUESTIONS), + createRoute(routeData.CAPABILITY_QUESTIONS), + createRoute(routeData.QUOTE, async (to, from) => { + if (isVerifiedInsurance()) { + return { + name: routeData.HERITAGE.name, + replace: true, + }; + } + + const offerQuote = to.query?.[queryStrings.OFFER_QUOTE]; + + if (offerQuote === "true") { + store.commit(storeMutations.UPDATE_IS_INSURANCE, false); + } + }), + createRoute(routeData.INSURANCE_COMPANY, async (to, from) => { + if (isVerifiedInsurance()) { + return { + name: routeData.HERITAGE.name, + replace: true, + }; + } + }), + createRoute(routeData.SERVICE_LOCATION), + createRoute(routeData.SCHEDULE), + createRoute(routeData.CUSTOMER_DETAILS), + createRoute(routeData.PAYMENT_METHOD), + createRoute(routeData.PAYMENT), + createRoute(routeData.PAYMENT_PIA_RETURN), + createRoute(routeData.CONFIRMATION), + createRoute(routeData.RETURN_USER), + + // Virtual pages (resolve to a non-virtual page.) + createVirtualRoute(routeData.LANDING, async (to, from) => { + await initializeFromQueryStrings(); + // Save querystrings to temporary stash so they can be referred to later. + stashAllQueries(to); + // Change referral info. For use in local testing for insurance crossover. + await consumeReferralQuerystrings(); + + // Check for fmgpage parameter + const fmgPage = to?.query?.fmgPage; + if (fmgPage && router.hasRoute(fmgPage)) { + return { + name: fmgPage, + replace: true, + }; + } + + // If a session is still in memory, go to return-user. + if (store.getters.vehicle?.year > 0) { + console.log(`trying to redirect!`); + return { + name: routeData.RETURN_USER.name, + replace: true, + }; + } + + // Otherwise, load session and auto-route + return { + name: routeData.LOAD_SESSION.name, + replace: true, + }; + }), + createVirtualRoute(routeData.HERITAGE, async (to, from) => { + await navigateToHeritageFunnel({ shouldSaveSession: false, pageNameToLog: to.name }); + }), + createVirtualRoute(routeData.LOAD_SESSION, async (to, from) => { + const loadSessionResponse = await loadSessionIfPresent(false, to.name); + + return { + name: routeData.AUTO_ROUTE.name, + replace: true, + }; + }), + createVirtualRoute(routeData.AUTO_ROUTE, async (to, from) => { + for (let i = 0; i < autoRouteTable.length; i++) { + const testRouteData = autoRouteTable[i]; + + const isReady = await router.checkPagePrerequisites(testRouteData.name); + + if (isReady) { + return { + name: testRouteData.name, + replace: true, + }; + } + } + + return { + name: FUNNEL_START_PAGE, + replace: true, + }; + }), + createVirtualRoute(routeData.ERROR, async (to, from) => { + // If we've already encountered one error, clear session to avoid more. + // Otherwise mark that we encoutnered an error here. + if (store.getters.applicationUser.hasAlreadyTriggeredError) { + return { + name: routeData.RESTART.name, + replace: true, + }; + } else { + await store.dispatch(storeActions.UPDATE_HAS_TRIGGERED_ERROR, true); + } + + // Add error event to bus + eventBus.addEventToBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.UNKNOWN_ERROR, + { + isDismissable: true, + messageCopy: "", + messageHeadline: "We're sorry, something went wrong.", + type: globalEventTypes.Danger, + } + ); + + let nextPage = FUNNEL_START_PAGE.name; + + baseMixin.methods?.ResetExternalParamsAndHideModal(); + + if (store.getters.payment?.insuranceCoverage?.isVerified) { + nextPage = routeData.VEHICLE_DAMAGE.name; + } + + if (from.name === nextPage) { + // Router won't load the page if we redirect to the already existing page + // Force refresh in this scenario. + router.go(0); + return false; + } + + return { + name: nextPage, + replace: false, + }; + }), + createVirtualRoute(routeData.RESTART, async (to, from) => { + await store.dispatch(storeActions.RESET_STATE); + deleteFunnelCookie(); + + if (from.name === FUNNEL_START_PAGE.name) { + // Router won't load the page if we redirect to the already existing page + // Force refresh in this scenario. + router.go(0); + return false; + } + + return { + name: FUNNEL_START_PAGE.name, + replace: true, + }; + }), +]; + +const router = createRouter({ + history: createWebHistory(ROUTE_PREFIX_FULL), + routes, + // Scroll to top on navigation. + scrollBehavior(to, from, savedPosition) { + return { top: 0 }; + }, +}); + +////-- Global Guards + +router.beforeEach(async (to, from) => { + console.log(to); + try { + await analyticsMixin.methods.validateSession(); + + if (getFunnelCookie()?.SuppressConceptFunnel) { + // Redirect to heritage. + return { + name: routeData.HERITAGE.name, + }; + } + + // Ensure session has not expired + if (getFunnelCookie() !== null && !isSavedSessionStillActive()) { + const errorPayload = { + cause: "expired session", + currentPage: from?.name, + nextPage: to?.name, + }; + + router.bailout(errorPayload, true); + return false; + } + + // Block navigation if an order has been submitted. + if (window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE) !== null) { + if (to.name !== FUNNEL_START_PAGE.name && to.name !== routeData.CONFIRMATION.name) { + return false; + } + } + + // Process funnel cookie. + updateOrCreateFunnelCookie(); + + // If sent from heritage, need to load session. + const fromHeritageFlag = consumeQueryFromStash(queryStrings.FROM_HERITAGE); + if (fromHeritageFlag) { + await loadSessionIfPresent(true, routeData.SERVICE_LOCATION.name); + } + + // Ensure page-prerequisites are fulfilled + const arePagePrerequisitesValid = await router.checkPagePrerequisites(to.name); + + if (!arePagePrerequisitesValid) { + const errorPayload = { + cause: "invalid page prerequisites for page", + currentPage: from?.name, + nextPage: to?.name, + }; + + router.bailout(errorPayload); + return; + } + + await runExperiments(to.name); + } catch (error) { + const errorPayload = { + cause: "Uncaught exception in `beforeEach`.", + currentPage: from?.name, + nextPage: to?.name, + }; + + console.log(error); + + router.bailout(errorPayload); + return; + } +}); + +router.afterEach(async (to, from) => { + // Push page view to GA + analyticsMixin.methods.pushPageViewToGA(); + + // Push experiments to Data Layer + analyticsMixin.methods.pushExperimentsToDataLayer(); + + // Push current order status to Data Layer + analyticsMixin.methods.pushOrderToDataLayer(); +}); + +////-- End Global Guards + +////-- Bound Functions + +router.getRoute = (pageName) => { + return router.getRoutes().find((r) => r.name === pageName); +}; + +router.checkPagePrerequisites = async (pageName) => { + const route = router.getRoute(pageName); + + if (!route) { + return false; + } + + let component = route.components; + + // Virtual routes have no component, so skip check. + if (!component) { + return true; + } + + if (component?.default?.methods === undefined) { + component = await component?.default(); + } + + return component?.default?.methods?.arePagePrerequisitesValid(); +}; + +router.navigateWithoutSaving = async (scenario, currentPageName) => { + return await router.navigate(currentPageName, scenario, false); +}; + +router.navigateWithSaving = async (scenario, currentPageName) => { + return await router.navigate(currentPageName, scenario, true); +}; + +router.navigateWithPageData = async (scenario, currentPageName, pageData = {}) => { + const nextPage = getDestination(currentPageName, scenario); + await savePageData(nextPage.name, pageData); + + return await router.navigate(currentPageName, scenario, true); +}; + +router.navigateAndForceTopLevelNavigation = async (scenario, currentPageName, saving = false) => { + return await router.navigate(currentPageName, scenario, saving, true); +}; + +router.bailout = (errorPayload, forceRestart = false) => { + analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload); + + if (forceRestart) { + router.push({ + name: routeData.RESTART.name, + }); + } else { + router.push({ + name: routeData.ERROR.name, + }); + } +}; + +router.navigate = async ( + currentPageName, + scenario, + withSaving = false, + forceTopLevelNav = false +) => { + // Check to see if calling page is same as current page. + // If not, cancel navigation before it begins. + const callingRoute = currentPageName; + const actualRoute = router.currentRoute.value.name; + + if (callingRoute !== actualRoute) { + return false; + } + + const nextPage = getDestination(currentPageName, scenario); + + if (!nextPage) { + console.error( + `Could not navigate from ${currentPageName} via scenario ${scenario}. Ensure routing table is configured correctly.` + ); + + const errorPayload = { + cause: "invalid page name", + currentPage: currentPageName, + nextPage: nextPage?.name, + }; + + router.bailout(errorPayload); + return; + } + + if (withSaving) { + await saveSession({ pageNameToLog: nextPage.name }); + } + + // Some pages require manually setting the next url + // to work with iframes. + if (forceTopLevelNav) { + const newUrl = buildManualUrl(nextPage); + window.top.location.href = newUrl; + return; + } + + // All other pages use router.push + router.push({ + name: nextPage.name, + query: nextPage.params ?? {}, + }); +}; + +////-- End Router Functions + +export default router; diff --git a/src/router/a-rewrite/logic/build-manual-url.js b/src/router/a-rewrite/logic/build-manual-url.js new file mode 100644 index 000000000..017816d6b --- /dev/null +++ b/src/router/a-rewrite/logic/build-manual-url.js @@ -0,0 +1,27 @@ +import { ROUTE_PREFIX_TRIMMED } from "@/router/a-rewrite/constants/route-prefix"; + +export function buildManualUrl(nextPage) { + const queries = nextPage.params; + const querystring = buildSearchParams(queries); + + const url = `${window.top.location.origin}/${ROUTE_PREFIX_TRIMMED}${nextPage.path}${querystring}`; + + return url; +} + +function buildSearchParams(paramList) { + if (!paramList) { + return ""; + } + + const keys = Object.keys(paramList); + if (keys?.length > 0) { + const queryFormattedParams = keys.map((k) => `${k}=${paramList[k]}`); + + const querystring = queryFormattedParams.reduce((a, b) => `${a}&${b}`); + + return `?${querystring}`; + } + + return ""; +} diff --git a/src/router/a-rewrite/logic/consume-referral-info.js b/src/router/a-rewrite/logic/consume-referral-info.js new file mode 100644 index 000000000..5c1dceafc --- /dev/null +++ b/src/router/a-rewrite/logic/consume-referral-info.js @@ -0,0 +1,18 @@ +import { getQuerystringParameter } from "@/helpers/querystring-helper"; +import { queryStrings } from "@/constants/query-strings"; +import store from "@/store"; +import { storeMutations } from "@/constants/store-mutations"; +import { updateOrCreateFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; + +export async function consumeReferralQuerystrings() { + const referralNumber = getQuerystringParameter(queryStrings.REFERRAL_NUMBER); + const parentAccount = getQuerystringParameter(queryStrings.PARENT_ACCOUNT); + const correlationId = getQuerystringParameter(queryStrings.CORRELATION_ID); + if (referralNumber) { + store.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber); + store.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccount); + store.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, correlationId); + // log(" --update cookie"); + updateOrCreateFunnelCookie(); + } +} diff --git a/src/router/a-rewrite/logic/create-route.js b/src/router/a-rewrite/logic/create-route.js new file mode 100644 index 000000000..44e27b568 --- /dev/null +++ b/src/router/a-rewrite/logic/create-route.js @@ -0,0 +1,39 @@ +import { lazyLoadComponent } from "@/router/a-rewrite/logic/lazy-load-component"; +import { routeData } from "@/router/a-rewrite/constants/routes"; + +export function createRoute(routeDatum, beforeEnter = async (to, from) => undefined) { + return { + name: routeDatum.name, + path: routeDatum.path, + component: lazyLoadComponent(routeDatum.name), + beforeEnter: async (to, from) => { + try { + return await beforeEnter(to, from); + } catch { + return { + name: routeData.BAILOUT.name, + replace: true, + }; + } + }, + }; +} + +export function createVirtualRoute(routeDatum, beforeEnter = async (to, from) => undefined) { + return { + name: routeDatum.name, + path: routeDatum.path, + beforeEnter: async (to, from) => { + try { + return await beforeEnter(to, from); + } catch (error) { + console.log(error); + return { + name: routeData.BAILOUT.name, + replace: true, + }; + } + }, + virtual: true, + }; +} diff --git a/src/router/a-rewrite/logic/get-destination.js b/src/router/a-rewrite/logic/get-destination.js new file mode 100644 index 000000000..cd04ddaad --- /dev/null +++ b/src/router/a-rewrite/logic/get-destination.js @@ -0,0 +1,18 @@ +import { routingTable } from "@/router/a-rewrite/constants/routing-table"; + +export function getDestination(sourcePageName, navigationScenario) { + const table = routingTable(); + + const pageEntry = table.find((entry) => entry.pageName === sourcePageName); + + const map = pageEntry?.maps?.find((map) => map.scenario === navigationScenario); + + if (!map || map?.filter === false) { + return null; + } + + return { + ...map.destinationPageData, + params: map.params, + }; +} diff --git a/src/router/a-rewrite/logic/initialize-from-querystrings.js b/src/router/a-rewrite/logic/initialize-from-querystrings.js new file mode 100644 index 000000000..2e12f88eb --- /dev/null +++ b/src/router/a-rewrite/logic/initialize-from-querystrings.js @@ -0,0 +1,121 @@ +import { + setupAdvertiserTracking, + getAffiliateCookies, +} from "@/helpers/heritage-integration/cookie-helper"; +import store from "@/store"; +import { storeMutations } from "@/constants/store-mutations"; +import { storeActions } from "@/constants/store-actions"; +import { getQuerystringParameter } from "@/helpers/querystring-helper"; +import { queryStrings } from "@/constants/query-strings"; +import { externalParameterStatus } from "@/constants/external-parameters"; + +export async function initializeFromQueryStrings() { + // Get advertiser info + setupAdvertisersAndAffiliates(); + + // Read all external paramter queries and write to store. + updateExternalParameterState(); +} + +function setupAdvertisersAndAffiliates() { + const affiliateCookies = getAffiliateCookies(); + if (affiliateCookies != null && affiliateCookies.length > 0) { + store.commit(storeMutations.UPDATE_AFFILIATE_COOKIES, affiliateCookies); + } + setupAdvertiserTracking(); +} + +function updateExternalParameterState() { + const externalParameterYear = getQuerystringParameter(queryStrings.VEHICLE_YEAR); + const externalParameterMake = getQuerystringParameter(queryStrings.VEHICLE_MAKE); + const externalParameterModel = getQuerystringParameter(queryStrings.VEHICLE_MODEL); + const externalParameterStyle = getQuerystringParameter(queryStrings.VEHICLE_STYLE); + const externalParameterDamage = getQuerystringParameter(queryStrings.VEHICLE_DAMAGE); + const externalParameterZipCode = getQuerystringParameter(queryStrings.SERVICE_ZIP); + const externalParameterEmail = getQuerystringParameter(queryStrings.EMAIL); + const externalParameterIsInsurance = getQuerystringParameter(queryStrings.IS_INSURANCE); + const externalParameterVinSelection = getQuerystringParameter(queryStrings.VIN_SELECTION); + const externalParameterServicePackage = getQuerystringParameter(queryStrings.SERVICE_PACKAGE); + const externalParameterNumberOfChips = getQuerystringParameter(queryStrings.NUMBER_OF_CHIPS); + const externalParameterSource = getQuerystringParameter(queryStrings.EXPERIMENTS); + const externalParameterPhoneNumber = getQuerystringParameter(queryStrings.PHONE_NUMBER); + if ( + externalParameterYear && + externalParameterMake && + externalParameterModel && + externalParameterStyle + ) { + resetStoreForExternalParameter(); + store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.ACTIVE); + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_YEAR, externalParameterYear); + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MAKE, externalParameterMake); + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MODEL, externalParameterModel); + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_STYLE, externalParameterStyle); + } + if ( + externalParameterDamage && + (externalParameterDamage.toUpperCase() != "WINDSHIELDREPAIR" || + externalParameterNumberOfChips?.length > 0) + ) { + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_DAMAGE_TYPE, externalParameterDamage); + if (externalParameterDamage.toUpperCase() == "WINDSHIELDREPLACE") { + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_IS_REPAIR, false); + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_NUMBER_OF_CHIPS, null); + } else if (externalParameterDamage.toUpperCase() == "WINDSHIELDREPAIR") { + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_IS_REPAIR, true); + store.commit( + storeMutations.UPDATE_EXTERNAL_PARAMETER_NUMBER_OF_CHIPS, + externalParameterNumberOfChips + ); + } + } + if (externalParameterZipCode) { + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_ZIP_CODE, externalParameterZipCode); + } + if (externalParameterEmail) { + store.commit( + storeMutations.UPDATE_EXTERNAL_PARAMETER_EMAIL_ADDRESS, + externalParameterEmail + ); + } + if (externalParameterIsInsurance?.toUpperCase() == "TRUE") { + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_IS_INSURANCE, true); + store.commit( + storeMutations.UPDATE_EXTERNAL_PARAMETER_SERVICE_PACKAGE, + externalParameterServicePackage?.toLowerCase() + ); + } + if (externalParameterDamage?.toUpperCase() != "WINDSHIELDREPAIR") { + store.commit( + storeMutations.UPDATE_EXTERNAL_PARAMETER_VIN_SELECTION, + externalParameterVinSelection + ); + } + if (externalParameterSource) { + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_SOURCE, externalParameterSource); + } + if (externalParameterPhoneNumber) { + store.commit( + storeMutations.UPDATE_EXTERNAL_PARAMETER_PHONE_NUMBER, + externalParameterPhoneNumber + ); + } +} + +// if there is an existing external parameter state then they have already been through from an external source(LeadGen) and +// are returning. clear out prior related things that need to be selected again like parts and damage type. +function resetStoreForExternalParameter() { + if ( + store.getters.externalParameterState?.isExternalParameter == + externalParameterStatus.INACTIVE + ) { + store.dispatch(storeActions.RESET_VEHICLE_STATE_AND_DEPENDENCIES); + store.dispatch(storeActions.SAVE_SERVICE_ZIP_CODE_INFO, { + state: null, + zipCode: null, + zipCodeCtu: null, + }); + store.dispatch(storeActions.SAVE_EMAIL, null); + store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); + } +} diff --git a/src/router/a-rewrite/logic/lazy-load-component.js b/src/router/a-rewrite/logic/lazy-load-component.js new file mode 100644 index 000000000..cb91c06c0 --- /dev/null +++ b/src/router/a-rewrite/logic/lazy-load-component.js @@ -0,0 +1,3 @@ +export function lazyLoadComponent(componentName) { + return () => import(`@/layouts/${componentName}/${componentName}.vue`); +} diff --git a/src/router/a-rewrite/logic/querystring-stash.js b/src/router/a-rewrite/logic/querystring-stash.js new file mode 100644 index 000000000..96b206572 --- /dev/null +++ b/src/router/a-rewrite/logic/querystring-stash.js @@ -0,0 +1,58 @@ +import { reactive } from "vue"; + +const queryStash = reactive({ + queries: [], +}); + +function stash(key, value) { + const existingValue = getStashedQuery(key); + + if (existingValue) { + existingValue.value = value; + existingValue.used = false; + return; + } + + queryStash.queries.push({ + key: key, + value: value, + used: false, + }); +} + +export function stashAllQueries(toRoute) { + const keys = Object.keys(toRoute.query); + + keys.forEach((k) => stash(k, toRoute.query[k])); +} + +function getStashedQuery(key) { + const match = queryStash.queries.find( + (entry) => entry?.key?.toLowerCase() === key?.toLowerCase() + ); + + return match; +} + +export function peekQueryFromStash(key) { + return getStashedQuery(key)?.value; +} + +export function consumeQueryFromStash(key) { + const match = getStashedQuery(key); + + if (match) { + if (!match.used) { + match.used = true; + return match.value; + } + + return null; + } + + return null; +} + +export function clearStash() { + queryStash.queries = []; +} diff --git a/src/router/a-rewrite/logic/requires-verified-redirect.js b/src/router/a-rewrite/logic/requires-verified-redirect.js new file mode 100644 index 000000000..19f088687 --- /dev/null +++ b/src/router/a-rewrite/logic/requires-verified-redirect.js @@ -0,0 +1,8 @@ +import store from "@/store"; + +export function isVerifiedInsurance() { + return ( + store.getters.payment?.insuranceCoverage?.isVerified || + store.getters.order?.referralNumber?.length === 6 + ); +} diff --git a/src/router/a-rewrite/logic/run-experiments.js b/src/router/a-rewrite/logic/run-experiments.js new file mode 100644 index 000000000..97472ad0c --- /dev/null +++ b/src/router/a-rewrite/logic/run-experiments.js @@ -0,0 +1,30 @@ +import store from "@/store"; +import baseMixin from "@/mixins/base-mixin"; +import { storeActions } from "@/constants/store-actions"; +import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper"; +import { experimentTriggers } from "@/constants/experiments"; +import { applicationConfig } from "@/constants/application-config"; + +export async function runExperiments(nextPageName) { + if (!store.getters.applicationUser.triggeredSiteEntry) { + await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.RUN_EXPERIMENTS_FOR_TRIGGER, + { + deviceId: getDeviceIdValue(), + triggerEvent: experimentTriggers.SITE_ENTRY, + triggerValue: applicationConfig.SITE_ENTRY_TRIGGER_VALUE, + }, + nextPageName + ); + } + + await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.RUN_EXPERIMENTS_FOR_TRIGGER, + { + deviceId: getDeviceIdValue(), + triggerEvent: experimentTriggers.PAGE_ENTRY, + triggerValue: nextPageName, + }, + nextPageName + ); +} diff --git a/src/router/a-rewrite/logic/save-page-data.js b/src/router/a-rewrite/logic/save-page-data.js new file mode 100644 index 000000000..1299f8900 --- /dev/null +++ b/src/router/a-rewrite/logic/save-page-data.js @@ -0,0 +1,11 @@ +import store from "@/store"; +import { storeMutations } from "@/constants/store-mutations"; + +export async function savePageData(page, data) { + const existingPageData = store.getters.pageData(page); + + const dataToSave = Object.keys(data).length > 0 ? data : (existingPageData ?? {}); + + // Save data if non-null + store.commit(storeMutations.UPDATE_PAGE_DATA, { page: page, data: dataToSave }); +} diff --git a/src/store/index.js b/src/store/index.js index 753d8509b..468a9e9eb 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -199,6 +199,7 @@ const getDefaultState = () => { triggeredSiteEntry: false, affiliateCookies: [], loggingOption: false, + hasAlreadyTriggeredError: false, }, }; }; @@ -824,6 +825,9 @@ export const mutations = { updateAffiliateCookies(state, affiliateCookies) { state.applicationUser.affiliateCookies = affiliateCookies; }, + updateHasTriggeredError(state, hasTriggeredError) { + state.applicationUser.hasAlreadyTriggeredError = hasTriggeredError; + }, }; // Export Getters @@ -3428,6 +3432,10 @@ export const actions = { } } }, + + updateHasTriggeredError(context, hasAlreadyTriggeredError) { + context.commit(storeMutations.UPDATE_HAS_TRIGGERED_ERROR, hasAlreadyTriggeredError); + }, }; export default createStore({ From d89f61a5b71fbd0e9aeb8580abf2ea6eb0a6d373 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 13 May 2025 16:36:13 -0400 Subject: [PATCH 02/13] Reapply "Big split" This reverts commit 0b80154cd9bf6cafed54079eb3cadaec7d941a1b. --- src/layouts/estimate/estimate.vue | 2 +- .../license-plate-lookup.vue | 2 +- src/layouts/payment-method/payment-method.vue | 2 +- src/layouts/quote/quote.vue | 2 +- src/layouts/service-zip/service-zip.vue | 2 +- src/layouts/vehicle/vehicle.vue | 2 +- src/layouts/vin-lookup/vin-lookup.vue | 2 +- .../a-rewrite/constants/externalUrl-values.js | 6 + src/router/a-rewrite/index.js | 425 +----------------- src/router/a-rewrite/methods/after-each.js | 12 + src/router/a-rewrite/methods/before-each.js | 83 ++++ src/router/a-rewrite/methods/error.js | 17 + src/router/a-rewrite/methods/get-route.js | 5 + .../helpers}/build-manual-url.js | 2 +- .../helpers}/consume-referral-info.js | 0 .../helpers}/create-route.js | 2 +- .../helpers}/get-destination.js | 0 .../helpers}/initialize-from-querystrings.js | 0 .../helpers}/lazy-load-component.js | 0 .../helpers}/querystring-stash.js | 0 .../helpers}/requires-verified-redirect.js | 0 .../helpers}/run-experiments.js | 0 .../helpers}/save-page-data.js | 0 .../a-rewrite/methods/navigate-external.js | 10 + src/router/a-rewrite/methods/navigate.js | 84 ++++ .../a-rewrite/methods/page-prerequisites.js | 22 + .../methods/route-logic/auto-route.js | 23 + .../a-rewrite/methods/route-logic/error.js | 52 +++ .../a-rewrite/methods/route-logic/heritage.js | 5 + .../methods/route-logic/insurance-company.js | 11 + .../a-rewrite/methods/route-logic/landing.js | 38 ++ .../methods/route-logic/load-session.js | 11 + .../a-rewrite/methods/route-logic/quote.js | 20 + .../a-rewrite/methods/route-logic/restart.js | 22 + .../a-rewrite/methods/route-logic/vehicle.js | 21 + src/router/a-rewrite/methods/routes.js | 46 ++ 36 files changed, 518 insertions(+), 413 deletions(-) create mode 100644 src/router/a-rewrite/constants/externalUrl-values.js create mode 100644 src/router/a-rewrite/methods/after-each.js create mode 100644 src/router/a-rewrite/methods/before-each.js create mode 100644 src/router/a-rewrite/methods/error.js create mode 100644 src/router/a-rewrite/methods/get-route.js rename src/router/a-rewrite/{logic => methods/helpers}/build-manual-url.js (93%) rename src/router/a-rewrite/{logic => methods/helpers}/consume-referral-info.js (100%) rename src/router/a-rewrite/{logic => methods/helpers}/create-route.js (92%) rename src/router/a-rewrite/{logic => methods/helpers}/get-destination.js (100%) rename src/router/a-rewrite/{logic => methods/helpers}/initialize-from-querystrings.js (100%) rename src/router/a-rewrite/{logic => methods/helpers}/lazy-load-component.js (100%) rename src/router/a-rewrite/{logic => methods/helpers}/querystring-stash.js (100%) rename src/router/a-rewrite/{logic => methods/helpers}/requires-verified-redirect.js (100%) rename src/router/a-rewrite/{logic => methods/helpers}/run-experiments.js (100%) rename src/router/a-rewrite/{logic => methods/helpers}/save-page-data.js (100%) create mode 100644 src/router/a-rewrite/methods/navigate-external.js create mode 100644 src/router/a-rewrite/methods/navigate.js create mode 100644 src/router/a-rewrite/methods/page-prerequisites.js create mode 100644 src/router/a-rewrite/methods/route-logic/auto-route.js create mode 100644 src/router/a-rewrite/methods/route-logic/error.js create mode 100644 src/router/a-rewrite/methods/route-logic/heritage.js create mode 100644 src/router/a-rewrite/methods/route-logic/insurance-company.js create mode 100644 src/router/a-rewrite/methods/route-logic/landing.js create mode 100644 src/router/a-rewrite/methods/route-logic/load-session.js create mode 100644 src/router/a-rewrite/methods/route-logic/quote.js create mode 100644 src/router/a-rewrite/methods/route-logic/restart.js create mode 100644 src/router/a-rewrite/methods/route-logic/vehicle.js create mode 100644 src/router/a-rewrite/methods/routes.js diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index 0a5db7d74..66d1544d9 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -62,7 +62,7 @@ import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; import baseMixin from "@/mixins/base-mixin.js"; import { queryStrings } from "@/constants/query-strings"; import { nextTick } from "vue"; -import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; +import { consumeQueryFromStash } from "@/router/a-rewrite/methods/helpers/querystring-stash"; // Define Validation Rules defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index a6bb07bab..673116965 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -119,7 +119,7 @@ import baseMixin from "@/mixins/base-mixin.js"; import store from "@/store"; import vinPagesMixin from "@/mixins/vin-pages-mixin"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; -import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; +import { consumeQueryFromStash } from "@/router/a-rewrite/methods/helpers/querystring-stash"; import { queryStrings } from "@/constants/query-strings"; // DEFINE VALIDATION RULES diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index d07434c1f..51a3ffd5d 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -168,7 +168,7 @@ import { getSubTotal, getSalesTax, } from "@/helpers/pricing-helper.js"; -import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; +import { consumeQueryFromStash } from "@/router/a-rewrite/methods/helpers/querystring-stash"; defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED)); defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED)); diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index f100a9f32..c095d00be 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -169,7 +169,7 @@ import { } from "@/helpers/heritage-integration/cookie-helper"; import { showFmgLoadingModal } from "@/helpers/loading-modal-helper"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; -import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; +import { consumeQueryFromStash } from "@/router/a-rewrite/methods/helpers/querystring-stash"; import { storeMutations } from "@/constants/store-mutations"; defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); diff --git a/src/layouts/service-zip/service-zip.vue b/src/layouts/service-zip/service-zip.vue index 16c6f7f72..6e0bccda6 100644 --- a/src/layouts/service-zip/service-zip.vue +++ b/src/layouts/service-zip/service-zip.vue @@ -96,7 +96,7 @@ import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; import baseMixin from "@/mixins/base-mixin.js"; import { queryStrings } from "@/constants/query-strings"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; -import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; +import { consumeQueryFromStash } from "@/router/a-rewrite/methods/helpers/querystring-stash"; // Define Validation Rules defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); diff --git a/src/layouts/vehicle/vehicle.vue b/src/layouts/vehicle/vehicle.vue index 1d2e7d2bb..8686be85b 100644 --- a/src/layouts/vehicle/vehicle.vue +++ b/src/layouts/vehicle/vehicle.vue @@ -113,7 +113,7 @@ import { getQuerystringParameter } from "@/helpers/querystring-helper"; import { consumeQueryFromStash, peekQueryFromStash, -} from "@/router/a-rewrite/logic/querystring-stash"; +} from "@/router/a-rewrite/methods/helpers/querystring-stash"; //define validation rules defineRule("year-required", required(errorMessages.YEAR_REQUIRED)); diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index 5db93d76d..277e176f5 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -160,7 +160,7 @@ import baseMixin from "@/mixins/base-mixin.js"; import store from "@/store"; import vinPagesMixin from "@/mixins/vin-pages-mixin"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; -import { consumeQueryFromStash } from "@/router/a-rewrite/logic/querystring-stash"; +import { consumeQueryFromStash } from "@/router/a-rewrite/methods/helpers/querystring-stash"; import { queryStrings } from "@/constants/query-strings"; // DEFINE VALIDATION RULES diff --git a/src/router/a-rewrite/constants/externalUrl-values.js b/src/router/a-rewrite/constants/externalUrl-values.js new file mode 100644 index 000000000..5516095c4 --- /dev/null +++ b/src/router/a-rewrite/constants/externalUrl-values.js @@ -0,0 +1,6 @@ +const externalUrls = { + HERITAGE_FUNNEL: process.env.VUE_APP_HERITAGE_FUNNEL, + SAFELITE_HOP: process.env.VUE_APP_SAFELITE_HOP, +}; + +export { externalUrls }; diff --git a/src/router/a-rewrite/index.js b/src/router/a-rewrite/index.js index 3a84a1730..37bd5aa0d 100644 --- a/src/router/a-rewrite/index.js +++ b/src/router/a-rewrite/index.js @@ -1,216 +1,16 @@ -import { routeData, FUNNEL_START_PAGE } from "@/router/a-rewrite/constants/routes"; -import { createRoute, createVirtualRoute } from "@/router/a-rewrite/logic/create-route"; -import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; -import { createWebHistory, createRouter } from "vue-router"; -import { getDestination } from "@/router/a-rewrite/logic/get-destination"; -import analyticsMixin from "@/mixins/analytics-mixin"; +import { routes } from "@/router/a-rewrite/methods/routes"; +import { afterEach } from "@/router/a-rewrite/methods/after-each"; +import { beforeEach } from "@/router/a-rewrite/methods/before-each"; +import { bailout } from "@/router/a-rewrite/methods/error"; import { - getFunnelCookie, - deleteFunnelCookie, - updateOrCreateFunnelCookie, -} from "@/helpers/heritage-integration/cookie-helper"; -import { isSavedSessionStillActive } from "@/helpers/heritage-integration/session-helper"; -import { loadSessionIfPresent, saveSession } from "@/helpers/heritage-integration/order-helper"; -import store from "@/store"; -import { storeActions } from "@/constants/store-actions"; -import { storeMutations } from "@/constants/store-mutations"; -import { sessionStorageKeyConstants } from "@/constants/session-storage"; -import { savePageData } from "@/router/a-rewrite/logic/save-page-data"; -import eventBus from "@/helpers/event-bus/event-bus"; -import { globalEvents, globalEventTypes } from "@/constants/events"; -import { autoRouteTable } from "@/router/a-rewrite/constants/auto-route-table"; -import { queryStrings } from "@/constants/query-strings"; -import { consumeReferralQuerystrings } from "@/router/a-rewrite/logic/consume-referral-info"; -import { initializeFromQueryStrings } from "@/router/a-rewrite/logic/initialize-from-querystrings"; -import { getBoolFromString } from "@/helpers/boolean-helper"; -import { isVerifiedInsurance } from "@/router/a-rewrite/logic/requires-verified-redirect"; -import baseMixin from "@/mixins/base-mixin"; -import { runExperiments } from "@/router/a-rewrite/logic/run-experiments"; + navigateWithoutSaving, + navigateWithSaving, + navigateWithPageData, + navigateAndForceTopLevelNavigation, +} from "@/router/a-rewrite/methods/navigate"; +import { navigateToExternalUrl } from "@/router/a-rewrite/methods/navigate-external"; +import { createWebHistory, createRouter } from "vue-router"; import { ROUTE_PREFIX_FULL } from "@/router/a-rewrite/constants/route-prefix"; -import { buildManualUrl } from "@/router/a-rewrite/logic/build-manual-url"; -import { consumeQueryFromStash, stashAllQueries } from "@/router/a-rewrite/logic/querystring-stash"; - -const routes = [ - // Non-virtual pages. - createRoute(routeData.VEHICLE, async (to, from) => { - // If cookie indicates that vehicle has changed during insurance flow, reset parts info. - const hasVehicleChanged = getBoolFromString(getFunnelCookie()?.HasDelayedClaimRegistration); - if (hasVehicleChanged) { - store.commit(storeMutations.RESET_GLASS_PARTS_STATE); - } - - if (isVerifiedInsurance()) { - return { - name: routeData.VEHICLE_DAMAGE.name, - replace: true, - }; - } - }), - createRoute(routeData.VEHICLE_DAMAGE), - createRoute(routeData.ESTIMATE), - createRoute(routeData.ADDRESS_LOOKUP), - createRoute(routeData.VIN_LOOKUP), - createRoute(routeData.LICENSE_PLATE_LOOKUP), - createRoute(routeData.SERVICE_ZIP), - createRoute(routeData.ADDRESS_VEHICLES), - createRoute(routeData.VEHICLE_PARTS), - createRoute(routeData.PART_QUESTIONS), - createRoute(routeData.MOLDING_QUESTIONS), - createRoute(routeData.CAPABILITY_QUESTIONS), - createRoute(routeData.QUOTE, async (to, from) => { - if (isVerifiedInsurance()) { - return { - name: routeData.HERITAGE.name, - replace: true, - }; - } - - const offerQuote = to.query?.[queryStrings.OFFER_QUOTE]; - - if (offerQuote === "true") { - store.commit(storeMutations.UPDATE_IS_INSURANCE, false); - } - }), - createRoute(routeData.INSURANCE_COMPANY, async (to, from) => { - if (isVerifiedInsurance()) { - return { - name: routeData.HERITAGE.name, - replace: true, - }; - } - }), - createRoute(routeData.SERVICE_LOCATION), - createRoute(routeData.SCHEDULE), - createRoute(routeData.CUSTOMER_DETAILS), - createRoute(routeData.PAYMENT_METHOD), - createRoute(routeData.PAYMENT), - createRoute(routeData.PAYMENT_PIA_RETURN), - createRoute(routeData.CONFIRMATION), - createRoute(routeData.RETURN_USER), - - // Virtual pages (resolve to a non-virtual page.) - createVirtualRoute(routeData.LANDING, async (to, from) => { - await initializeFromQueryStrings(); - // Save querystrings to temporary stash so they can be referred to later. - stashAllQueries(to); - // Change referral info. For use in local testing for insurance crossover. - await consumeReferralQuerystrings(); - - // Check for fmgpage parameter - const fmgPage = to?.query?.fmgPage; - if (fmgPage && router.hasRoute(fmgPage)) { - return { - name: fmgPage, - replace: true, - }; - } - - // If a session is still in memory, go to return-user. - if (store.getters.vehicle?.year > 0) { - console.log(`trying to redirect!`); - return { - name: routeData.RETURN_USER.name, - replace: true, - }; - } - - // Otherwise, load session and auto-route - return { - name: routeData.LOAD_SESSION.name, - replace: true, - }; - }), - createVirtualRoute(routeData.HERITAGE, async (to, from) => { - await navigateToHeritageFunnel({ shouldSaveSession: false, pageNameToLog: to.name }); - }), - createVirtualRoute(routeData.LOAD_SESSION, async (to, from) => { - const loadSessionResponse = await loadSessionIfPresent(false, to.name); - - return { - name: routeData.AUTO_ROUTE.name, - replace: true, - }; - }), - createVirtualRoute(routeData.AUTO_ROUTE, async (to, from) => { - for (let i = 0; i < autoRouteTable.length; i++) { - const testRouteData = autoRouteTable[i]; - - const isReady = await router.checkPagePrerequisites(testRouteData.name); - - if (isReady) { - return { - name: testRouteData.name, - replace: true, - }; - } - } - - return { - name: FUNNEL_START_PAGE, - replace: true, - }; - }), - createVirtualRoute(routeData.ERROR, async (to, from) => { - // If we've already encountered one error, clear session to avoid more. - // Otherwise mark that we encoutnered an error here. - if (store.getters.applicationUser.hasAlreadyTriggeredError) { - return { - name: routeData.RESTART.name, - replace: true, - }; - } else { - await store.dispatch(storeActions.UPDATE_HAS_TRIGGERED_ERROR, true); - } - - // Add error event to bus - eventBus.addEventToBus( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.UNKNOWN_ERROR, - { - isDismissable: true, - messageCopy: "", - messageHeadline: "We're sorry, something went wrong.", - type: globalEventTypes.Danger, - } - ); - - let nextPage = FUNNEL_START_PAGE.name; - - baseMixin.methods?.ResetExternalParamsAndHideModal(); - - if (store.getters.payment?.insuranceCoverage?.isVerified) { - nextPage = routeData.VEHICLE_DAMAGE.name; - } - - if (from.name === nextPage) { - // Router won't load the page if we redirect to the already existing page - // Force refresh in this scenario. - router.go(0); - return false; - } - - return { - name: nextPage, - replace: false, - }; - }), - createVirtualRoute(routeData.RESTART, async (to, from) => { - await store.dispatch(storeActions.RESET_STATE); - deleteFunnelCookie(); - - if (from.name === FUNNEL_START_PAGE.name) { - // Router won't load the page if we redirect to the already existing page - // Force refresh in this scenario. - router.go(0); - return false; - } - - return { - name: FUNNEL_START_PAGE.name, - replace: true, - }; - }), -]; const router = createRouter({ history: createWebHistory(ROUTE_PREFIX_FULL), @@ -221,201 +21,18 @@ const router = createRouter({ }, }); -////-- Global Guards +// Set guards +router.afterEach(async (to, from) => afterEach(to, from)); +router.beforeEach(async (to, from) => beforeEach(to, from)); -router.beforeEach(async (to, from) => { - console.log(to); - try { - await analyticsMixin.methods.validateSession(); +// Bind methods for external use +router.navigateWithSaving = navigateWithSaving; +router.navigateWithoutSaving = navigateWithoutSaving; +router.navigateWithPageData = navigateWithPageData; +router.navigateAndForceTopLevelNavigation = navigateAndForceTopLevelNavigation; - if (getFunnelCookie()?.SuppressConceptFunnel) { - // Redirect to heritage. - return { - name: routeData.HERITAGE.name, - }; - } +router.bailout = bailout; - // Ensure session has not expired - if (getFunnelCookie() !== null && !isSavedSessionStillActive()) { - const errorPayload = { - cause: "expired session", - currentPage: from?.name, - nextPage: to?.name, - }; - - router.bailout(errorPayload, true); - return false; - } - - // Block navigation if an order has been submitted. - if (window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE) !== null) { - if (to.name !== FUNNEL_START_PAGE.name && to.name !== routeData.CONFIRMATION.name) { - return false; - } - } - - // Process funnel cookie. - updateOrCreateFunnelCookie(); - - // If sent from heritage, need to load session. - const fromHeritageFlag = consumeQueryFromStash(queryStrings.FROM_HERITAGE); - if (fromHeritageFlag) { - await loadSessionIfPresent(true, routeData.SERVICE_LOCATION.name); - } - - // Ensure page-prerequisites are fulfilled - const arePagePrerequisitesValid = await router.checkPagePrerequisites(to.name); - - if (!arePagePrerequisitesValid) { - const errorPayload = { - cause: "invalid page prerequisites for page", - currentPage: from?.name, - nextPage: to?.name, - }; - - router.bailout(errorPayload); - return; - } - - await runExperiments(to.name); - } catch (error) { - const errorPayload = { - cause: "Uncaught exception in `beforeEach`.", - currentPage: from?.name, - nextPage: to?.name, - }; - - console.log(error); - - router.bailout(errorPayload); - return; - } -}); - -router.afterEach(async (to, from) => { - // Push page view to GA - analyticsMixin.methods.pushPageViewToGA(); - - // Push experiments to Data Layer - analyticsMixin.methods.pushExperimentsToDataLayer(); - - // Push current order status to Data Layer - analyticsMixin.methods.pushOrderToDataLayer(); -}); - -////-- End Global Guards - -////-- Bound Functions - -router.getRoute = (pageName) => { - return router.getRoutes().find((r) => r.name === pageName); -}; - -router.checkPagePrerequisites = async (pageName) => { - const route = router.getRoute(pageName); - - if (!route) { - return false; - } - - let component = route.components; - - // Virtual routes have no component, so skip check. - if (!component) { - return true; - } - - if (component?.default?.methods === undefined) { - component = await component?.default(); - } - - return component?.default?.methods?.arePagePrerequisitesValid(); -}; - -router.navigateWithoutSaving = async (scenario, currentPageName) => { - return await router.navigate(currentPageName, scenario, false); -}; - -router.navigateWithSaving = async (scenario, currentPageName) => { - return await router.navigate(currentPageName, scenario, true); -}; - -router.navigateWithPageData = async (scenario, currentPageName, pageData = {}) => { - const nextPage = getDestination(currentPageName, scenario); - await savePageData(nextPage.name, pageData); - - return await router.navigate(currentPageName, scenario, true); -}; - -router.navigateAndForceTopLevelNavigation = async (scenario, currentPageName, saving = false) => { - return await router.navigate(currentPageName, scenario, saving, true); -}; - -router.bailout = (errorPayload, forceRestart = false) => { - analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload); - - if (forceRestart) { - router.push({ - name: routeData.RESTART.name, - }); - } else { - router.push({ - name: routeData.ERROR.name, - }); - } -}; - -router.navigate = async ( - currentPageName, - scenario, - withSaving = false, - forceTopLevelNav = false -) => { - // Check to see if calling page is same as current page. - // If not, cancel navigation before it begins. - const callingRoute = currentPageName; - const actualRoute = router.currentRoute.value.name; - - if (callingRoute !== actualRoute) { - return false; - } - - const nextPage = getDestination(currentPageName, scenario); - - if (!nextPage) { - console.error( - `Could not navigate from ${currentPageName} via scenario ${scenario}. Ensure routing table is configured correctly.` - ); - - const errorPayload = { - cause: "invalid page name", - currentPage: currentPageName, - nextPage: nextPage?.name, - }; - - router.bailout(errorPayload); - return; - } - - if (withSaving) { - await saveSession({ pageNameToLog: nextPage.name }); - } - - // Some pages require manually setting the next url - // to work with iframes. - if (forceTopLevelNav) { - const newUrl = buildManualUrl(nextPage); - window.top.location.href = newUrl; - return; - } - - // All other pages use router.push - router.push({ - name: nextPage.name, - query: nextPage.params ?? {}, - }); -}; - -////-- End Router Functions +router.navigateToExternalUrl = navigateToExternalUrl; export default router; diff --git a/src/router/a-rewrite/methods/after-each.js b/src/router/a-rewrite/methods/after-each.js new file mode 100644 index 000000000..ef3dc0d93 --- /dev/null +++ b/src/router/a-rewrite/methods/after-each.js @@ -0,0 +1,12 @@ +import analyticsMixin from "@/mixins/analytics-mixin"; + +export async function afterEach(to, from) { + // Push page view to GA + analyticsMixin.methods.pushPageViewToGA(); + + // Push experiments to Data Layer + analyticsMixin.methods.pushExperimentsToDataLayer(); + + // Push current order status to Data Layer + analyticsMixin.methods.pushOrderToDataLayer(); +} diff --git a/src/router/a-rewrite/methods/before-each.js b/src/router/a-rewrite/methods/before-each.js new file mode 100644 index 000000000..05264ed3c --- /dev/null +++ b/src/router/a-rewrite/methods/before-each.js @@ -0,0 +1,83 @@ +import { queryStrings } from "@/constants/query-strings"; +import { sessionStorageKeyConstants } from "@/constants/session-storage"; +import { + getFunnelCookie, + updateOrCreateFunnelCookie, +} from "@/helpers/heritage-integration/cookie-helper"; +import { loadSessionIfPresent } from "@/helpers/heritage-integration/order-helper"; +import { isSavedSessionStillActive } from "@/helpers/heritage-integration/session-helper"; +import analyticsMixin from "@/mixins/analytics-mixin"; +import { routeData, FUNNEL_START_PAGE } from "@/router/a-rewrite/constants/routes"; +import { consumeQueryFromStash } from "@/router/a-rewrite/methods/helpers/querystring-stash"; +import { runExperiments } from "@/router/a-rewrite/methods/helpers/run-experiments"; + +import { bailout } from "@/router/a-rewrite/methods/error"; +import { checkPagePrerequisites } from "@/router/a-rewrite/methods/page-prerequisites"; + +export async function beforeEach(to, from) { + try { + await analyticsMixin.methods.validateSession(); + + if (getFunnelCookie()?.SuppressConceptFunnel) { + // Redirect to heritage. + return { + name: routeData.HERITAGE.name, + }; + } + + // Ensure session has not expired + if (getFunnelCookie() !== null && !isSavedSessionStillActive()) { + const errorPayload = { + cause: "expired session", + currentPage: from?.name, + nextPage: to?.name, + }; + + bailout(errorPayload, true); + return false; + } + + // Block navigation if an order has been submitted. + if (window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE) !== null) { + if (to.name !== FUNNEL_START_PAGE.name && to.name !== routeData.CONFIRMATION.name) { + return false; + } + } + + // Process funnel cookie. + updateOrCreateFunnelCookie(); + + // If sent from heritage, need to load session. + const fromHeritageFlag = consumeQueryFromStash(queryStrings.FROM_HERITAGE); + if (fromHeritageFlag) { + await loadSessionIfPresent(true, routeData.SERVICE_LOCATION.name); + } + + // Ensure page-prerequisites are fulfilled + const arePagePrerequisitesValid = await checkPagePrerequisites(to.name); + + if (!arePagePrerequisitesValid) { + const errorPayload = { + cause: "invalid page prerequisites for page", + currentPage: from?.name, + nextPage: to?.name, + }; + + bailout(errorPayload); + return; + } + + await runExperiments(to.name); + } catch (error) { + const errorPayload = { + cause: "Uncaught exception in `beforeEach`.", + currentPage: from?.name, + nextPage: to?.name, + }; + + console.log(error); + + bailout(errorPayload); + return; + } +} diff --git a/src/router/a-rewrite/methods/error.js b/src/router/a-rewrite/methods/error.js new file mode 100644 index 000000000..3c50c1768 --- /dev/null +++ b/src/router/a-rewrite/methods/error.js @@ -0,0 +1,17 @@ +import analyticsMixin from "@/mixins/analytics-mixin"; +import { routeData } from "@/router/a-rewrite/constants/routes"; +import router from "@/router/a-rewrite"; + +export async function bailout(errorPayload, forceRestart = false) { + analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload); + + if (forceRestart) { + router.push({ + name: routeData.RESTART.name, + }); + } else { + router.push({ + name: routeData.ERROR.name, + }); + } +} diff --git a/src/router/a-rewrite/methods/get-route.js b/src/router/a-rewrite/methods/get-route.js new file mode 100644 index 000000000..ead89eb5b --- /dev/null +++ b/src/router/a-rewrite/methods/get-route.js @@ -0,0 +1,5 @@ +import router from "@/router/a-rewrite"; + +export function getRoute(pageName) { + return router.getRoutes().find((r) => r.name === pageName); +} diff --git a/src/router/a-rewrite/logic/build-manual-url.js b/src/router/a-rewrite/methods/helpers/build-manual-url.js similarity index 93% rename from src/router/a-rewrite/logic/build-manual-url.js rename to src/router/a-rewrite/methods/helpers/build-manual-url.js index 017816d6b..260b41257 100644 --- a/src/router/a-rewrite/logic/build-manual-url.js +++ b/src/router/a-rewrite/methods/helpers/build-manual-url.js @@ -9,7 +9,7 @@ export function buildManualUrl(nextPage) { return url; } -function buildSearchParams(paramList) { +export function buildSearchParams(paramList) { if (!paramList) { return ""; } diff --git a/src/router/a-rewrite/logic/consume-referral-info.js b/src/router/a-rewrite/methods/helpers/consume-referral-info.js similarity index 100% rename from src/router/a-rewrite/logic/consume-referral-info.js rename to src/router/a-rewrite/methods/helpers/consume-referral-info.js diff --git a/src/router/a-rewrite/logic/create-route.js b/src/router/a-rewrite/methods/helpers/create-route.js similarity index 92% rename from src/router/a-rewrite/logic/create-route.js rename to src/router/a-rewrite/methods/helpers/create-route.js index 44e27b568..a1535f3c8 100644 --- a/src/router/a-rewrite/logic/create-route.js +++ b/src/router/a-rewrite/methods/helpers/create-route.js @@ -1,4 +1,4 @@ -import { lazyLoadComponent } from "@/router/a-rewrite/logic/lazy-load-component"; +import { lazyLoadComponent } from "@/router/a-rewrite/methods/helpers/lazy-load-component"; import { routeData } from "@/router/a-rewrite/constants/routes"; export function createRoute(routeDatum, beforeEnter = async (to, from) => undefined) { diff --git a/src/router/a-rewrite/logic/get-destination.js b/src/router/a-rewrite/methods/helpers/get-destination.js similarity index 100% rename from src/router/a-rewrite/logic/get-destination.js rename to src/router/a-rewrite/methods/helpers/get-destination.js diff --git a/src/router/a-rewrite/logic/initialize-from-querystrings.js b/src/router/a-rewrite/methods/helpers/initialize-from-querystrings.js similarity index 100% rename from src/router/a-rewrite/logic/initialize-from-querystrings.js rename to src/router/a-rewrite/methods/helpers/initialize-from-querystrings.js diff --git a/src/router/a-rewrite/logic/lazy-load-component.js b/src/router/a-rewrite/methods/helpers/lazy-load-component.js similarity index 100% rename from src/router/a-rewrite/logic/lazy-load-component.js rename to src/router/a-rewrite/methods/helpers/lazy-load-component.js diff --git a/src/router/a-rewrite/logic/querystring-stash.js b/src/router/a-rewrite/methods/helpers/querystring-stash.js similarity index 100% rename from src/router/a-rewrite/logic/querystring-stash.js rename to src/router/a-rewrite/methods/helpers/querystring-stash.js diff --git a/src/router/a-rewrite/logic/requires-verified-redirect.js b/src/router/a-rewrite/methods/helpers/requires-verified-redirect.js similarity index 100% rename from src/router/a-rewrite/logic/requires-verified-redirect.js rename to src/router/a-rewrite/methods/helpers/requires-verified-redirect.js diff --git a/src/router/a-rewrite/logic/run-experiments.js b/src/router/a-rewrite/methods/helpers/run-experiments.js similarity index 100% rename from src/router/a-rewrite/logic/run-experiments.js rename to src/router/a-rewrite/methods/helpers/run-experiments.js diff --git a/src/router/a-rewrite/logic/save-page-data.js b/src/router/a-rewrite/methods/helpers/save-page-data.js similarity index 100% rename from src/router/a-rewrite/logic/save-page-data.js rename to src/router/a-rewrite/methods/helpers/save-page-data.js diff --git a/src/router/a-rewrite/methods/navigate-external.js b/src/router/a-rewrite/methods/navigate-external.js new file mode 100644 index 000000000..622bf1e99 --- /dev/null +++ b/src/router/a-rewrite/methods/navigate-external.js @@ -0,0 +1,10 @@ +export function navigateToExternalUrl(url, optionalQuery = {}) { + // possibly show some loading screen in the future here. + var externalUrl = new URL(url); + + for (const queryKey in optionalQuery) { + externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]); + } + + window.location.assign(externalUrl); +} diff --git a/src/router/a-rewrite/methods/navigate.js b/src/router/a-rewrite/methods/navigate.js new file mode 100644 index 000000000..ca8de4784 --- /dev/null +++ b/src/router/a-rewrite/methods/navigate.js @@ -0,0 +1,84 @@ +import { saveSession } from "@/helpers/heritage-integration/order-helper"; +import { buildManualUrl } from "@/router/a-rewrite/methods/helpers/build-manual-url"; +import { getDestination } from "@/router/a-rewrite/methods/helpers/get-destination"; +import { savePageData } from "@/router/a-rewrite/methods/helpers/save-page-data"; +import router from "@/router/a-rewrite"; + +import { bailout } from "@/router/a-rewrite/methods/error"; + +async function navigate(scenario, currentPageName, withSaving = false, forceTopLevelNav = false) { + console.log(`Navigate:\n + - scenario: ${scenario}\n + - currentPage: ${currentPageName}\n + - withSaving: ${withSaving}\n + - forceTopLevelNav: ${forceTopLevelNav}`); + + // Check to see if calling page is same as current page. + // If not, cancel navigation before it begins. + const callingRoute = currentPageName; + const actualRoute = router.currentRoute.value.name; + + if (callingRoute !== actualRoute) { + return false; + } + + const nextPage = getDestination(currentPageName, scenario); + + if (!nextPage) { + console.error( + `Could not navigate from ${currentPageName} via scenario ${scenario}. Ensure routing table is configured correctly.` + ); + + const errorPayload = { + cause: "invalid page name", + currentPage: currentPageName, + nextPage: nextPage?.name, + }; + + bailout(errorPayload); + return; + } + + if (withSaving) { + await saveSession({ pageNameToLog: nextPage.name }); + } + + // Some pages require manually setting the next url + // to work with iframes. + if (forceTopLevelNav) { + const newUrl = buildManualUrl(nextPage); + window.top.location.href = newUrl; + return; + } + + // All other pages use router.push + router.push({ + name: nextPage.name, + query: nextPage.params ?? {}, + }); +} + +//// -- Aliases: what's actually called + +export async function navigateWithoutSaving(scenario, currentPageName) { + return await navigate(scenario, currentPageName, false); +} + +export async function navigateWithSaving(scenario, currentPageName) { + return await navigate(scenario, currentPageName, true); +} + +export async function navigateWithPageData(scenario, currentPageName, pageData = {}) { + const nextPage = getDestination(currentPageName, scenario); + await savePageData(nextPage.name, pageData); + + return await navigate(scenario, currentPageName, true); +} + +export async function navigateAndForceTopLevelNavigation( + scenario, + currentPageName, + saving = false +) { + return await navigate(scenario, currentPageName, saving, true); +} diff --git a/src/router/a-rewrite/methods/page-prerequisites.js b/src/router/a-rewrite/methods/page-prerequisites.js new file mode 100644 index 000000000..581ab0354 --- /dev/null +++ b/src/router/a-rewrite/methods/page-prerequisites.js @@ -0,0 +1,22 @@ +import { getRoute } from "@/router/a-rewrite/methods/get-route"; + +export async function checkPagePrerequisites(pageName) { + const route = getRoute(pageName); + + if (!route) { + return false; + } + + let component = route.components; + + // Virtual routes have no component, so skip check. + if (!component) { + return true; + } + + if (component?.default?.methods === undefined) { + component = await component?.default(); + } + + return component?.default?.methods?.arePagePrerequisitesValid(); +} diff --git a/src/router/a-rewrite/methods/route-logic/auto-route.js b/src/router/a-rewrite/methods/route-logic/auto-route.js new file mode 100644 index 000000000..a6d55e4fa --- /dev/null +++ b/src/router/a-rewrite/methods/route-logic/auto-route.js @@ -0,0 +1,23 @@ +import { autoRouteTable } from "@/router/a-rewrite/constants/auto-route-table"; +import { FUNNEL_START_PAGE } from "@/router/a-rewrite/constants/routes"; +import { checkPagePrerequisites } from "@/router/a-rewrite/methods/page-prerequisites"; + +export async function autoRouteBeforeEnter(to, from) { + for (let i = 0; i < autoRouteTable.length; i++) { + const testRouteData = autoRouteTable[i]; + + const isReady = await checkPagePrerequisites(testRouteData.name); + + if (isReady) { + return { + name: testRouteData.name, + replace: true, + }; + } + } + + return { + name: FUNNEL_START_PAGE, + replace: true, + }; +} diff --git a/src/router/a-rewrite/methods/route-logic/error.js b/src/router/a-rewrite/methods/route-logic/error.js new file mode 100644 index 000000000..c4bdeb6d5 --- /dev/null +++ b/src/router/a-rewrite/methods/route-logic/error.js @@ -0,0 +1,52 @@ +import { globalEvents, globalEventTypes } from "@/constants/events"; +import { storeActions } from "@/constants/store-actions"; +import eventBus from "@/helpers/event-bus/event-bus"; +import baseMixin from "@/mixins/base-mixin"; +import router from "@/router/a-rewrite"; +import { routeData, FUNNEL_START_PAGE } from "@/router/a-rewrite/constants/routes"; +import store from "@/store"; + +export async function errorBeforeEnter(to, from) { + // If we've already encountered one error, clear session to avoid more. + // Otherwise mark that we encoutnered an error here. + if (store.getters.applicationUser.hasAlreadyTriggeredError) { + return { + name: routeData.RESTART.name, + replace: true, + }; + } else { + await store.dispatch(storeActions.UPDATE_HAS_TRIGGERED_ERROR, true); + } + + // Add error event to bus + eventBus.addEventToBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.UNKNOWN_ERROR, + { + isDismissable: true, + messageCopy: "", + messageHeadline: "We're sorry, something went wrong.", + type: globalEventTypes.Danger, + } + ); + + let nextPage = FUNNEL_START_PAGE.name; + + baseMixin.methods?.ResetExternalParamsAndHideModal(); + + if (store.getters.payment?.insuranceCoverage?.isVerified) { + nextPage = routeData.VEHICLE_DAMAGE.name; + } + + if (from.name === nextPage) { + // Router won't load the page if we redirect to the already existing page + // Force refresh in this scenario. + router.go(0); + return false; + } + + return { + name: nextPage, + replace: false, + }; +} diff --git a/src/router/a-rewrite/methods/route-logic/heritage.js b/src/router/a-rewrite/methods/route-logic/heritage.js new file mode 100644 index 000000000..d1a4c41c4 --- /dev/null +++ b/src/router/a-rewrite/methods/route-logic/heritage.js @@ -0,0 +1,5 @@ +import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; + +export async function heritageBeforeEnter(to, from) { + await navigateToHeritageFunnel({ shouldSaveSession: false, pageNameToLog: to.name }); +} diff --git a/src/router/a-rewrite/methods/route-logic/insurance-company.js b/src/router/a-rewrite/methods/route-logic/insurance-company.js new file mode 100644 index 000000000..18d961854 --- /dev/null +++ b/src/router/a-rewrite/methods/route-logic/insurance-company.js @@ -0,0 +1,11 @@ +import { routeData } from "@/router/a-rewrite/constants/routes"; +import { isVerifiedInsurance } from "@/router/a-rewrite/methods/helpers/requires-verified-redirect"; + +export async function insuranceCompanyBeforeEnter(to, from) { + if (isVerifiedInsurance()) { + return { + name: routeData.HERITAGE.name, + replace: true, + }; + } +} diff --git a/src/router/a-rewrite/methods/route-logic/landing.js b/src/router/a-rewrite/methods/route-logic/landing.js new file mode 100644 index 000000000..b71d7a9db --- /dev/null +++ b/src/router/a-rewrite/methods/route-logic/landing.js @@ -0,0 +1,38 @@ +import router from "@/router/a-rewrite"; +import { routeData } from "@/router/a-rewrite/constants/routes"; +import { consumeReferralQuerystrings } from "@/router/a-rewrite/methods/helpers/consume-referral-info"; +import { initializeFromQueryStrings } from "@/router/a-rewrite/methods/helpers/initialize-from-querystrings"; +import { stashAllQueries } from "@/router/a-rewrite/methods/helpers/querystring-stash"; +import store from "@/store"; + +export async function landingBeforeEnter(to, from) { + await initializeFromQueryStrings(); + // Save querystrings to temporary stash so they can be referred to later. + stashAllQueries(to); + // Change referral info. For use in local testing for insurance crossover. + await consumeReferralQuerystrings(); + + // Check for fmgpage parameter + const fmgPage = to?.query?.fmgPage; + if (fmgPage && router.hasRoute(fmgPage)) { + return { + name: fmgPage, + replace: true, + }; + } + + // If a session is still in memory, go to return-user. + if (store.getters.vehicle?.year > 0) { + console.log(`trying to redirect!`); + return { + name: routeData.RETURN_USER.name, + replace: true, + }; + } + + // Otherwise, load session and auto-route + return { + name: routeData.LOAD_SESSION.name, + replace: true, + }; +} diff --git a/src/router/a-rewrite/methods/route-logic/load-session.js b/src/router/a-rewrite/methods/route-logic/load-session.js new file mode 100644 index 000000000..c70eb28d6 --- /dev/null +++ b/src/router/a-rewrite/methods/route-logic/load-session.js @@ -0,0 +1,11 @@ +import { loadSessionIfPresent } from "@/helpers/heritage-integration/order-helper"; +import { routeData } from "@/router/a-rewrite/constants/routes"; + +export async function loadSessionBeforeEnter(to, from) { + const loadSessionResponse = await loadSessionIfPresent(false, to.name); + + return { + name: routeData.AUTO_ROUTE.name, + replace: true, + }; +} diff --git a/src/router/a-rewrite/methods/route-logic/quote.js b/src/router/a-rewrite/methods/route-logic/quote.js new file mode 100644 index 000000000..9771b9bbb --- /dev/null +++ b/src/router/a-rewrite/methods/route-logic/quote.js @@ -0,0 +1,20 @@ +import { queryStrings } from "@/constants/query-strings"; +import { storeMutations } from "@/constants/store-mutations"; +import { routeData } from "@/router/a-rewrite/constants/routes"; +import { isVerifiedInsurance } from "@/router/a-rewrite/methods/helpers/requires-verified-redirect"; +import store from "@/store"; + +export async function quoteBeforeEnter(to, from) { + if (isVerifiedInsurance()) { + return { + name: routeData.HERITAGE.name, + replace: true, + }; + } + + const offerQuote = to.query?.[queryStrings.OFFER_QUOTE]; + + if (offerQuote === "true") { + store.commit(storeMutations.UPDATE_IS_INSURANCE, false); + } +} diff --git a/src/router/a-rewrite/methods/route-logic/restart.js b/src/router/a-rewrite/methods/route-logic/restart.js new file mode 100644 index 000000000..4589999e0 --- /dev/null +++ b/src/router/a-rewrite/methods/route-logic/restart.js @@ -0,0 +1,22 @@ +import { storeActions } from "@/constants/store-actions"; +import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; +import router from "@/router/a-rewrite"; +import { FUNNEL_START_PAGE } from "@/router/a-rewrite/constants/routes"; +import store from "@/store"; + +export async function restartBeforeEnter(to, from) { + await store.dispatch(storeActions.RESET_STATE); + deleteFunnelCookie(); + + if (from.name === FUNNEL_START_PAGE.name) { + // Router won't load the page if we redirect to the already existing page + // Force refresh in this scenario. + router.go(0); + return false; + } + + return { + name: FUNNEL_START_PAGE.name, + replace: true, + }; +} diff --git a/src/router/a-rewrite/methods/route-logic/vehicle.js b/src/router/a-rewrite/methods/route-logic/vehicle.js new file mode 100644 index 000000000..ed241d7de --- /dev/null +++ b/src/router/a-rewrite/methods/route-logic/vehicle.js @@ -0,0 +1,21 @@ +import { storeMutations } from "@/constants/store-mutations"; +import { getBoolFromString } from "@/helpers/boolean-helper"; +import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; +import { routeData } from "@/router/a-rewrite/constants/routes"; +import { isVerifiedInsurance } from "@/router/a-rewrite/methods/helpers/requires-verified-redirect"; +import store from "@/store"; + +export async function vehicleBeforeEnter(to, from) { + // If cookie indicates that vehicle has changed during insurance flow, reset parts info. + const hasVehicleChanged = getBoolFromString(getFunnelCookie()?.HasDelayedClaimRegistration); + if (hasVehicleChanged) { + store.commit(storeMutations.RESET_GLASS_PARTS_STATE); + } + + if (isVerifiedInsurance()) { + return { + name: routeData.VEHICLE_DAMAGE.name, + replace: true, + }; + } +} diff --git a/src/router/a-rewrite/methods/routes.js b/src/router/a-rewrite/methods/routes.js new file mode 100644 index 000000000..5cbc8e94e --- /dev/null +++ b/src/router/a-rewrite/methods/routes.js @@ -0,0 +1,46 @@ +import { createRoute, createVirtualRoute } from "@/router/a-rewrite/methods/helpers/create-route"; +import { routeData } from "@/router/a-rewrite/constants/routes"; + +import { vehicleBeforeEnter } from "@/router/a-rewrite/methods/route-logic/vehicle"; +import { quoteBeforeEnter } from "@/router/a-rewrite/methods/route-logic/quote"; +import { insuranceCompanyBeforeEnter } from "@/router/a-rewrite/methods/route-logic/insurance-company"; +import { landingBeforeEnter } from "@/router/a-rewrite/methods/route-logic/landing"; +import { heritageBeforeEnter } from "@/router/a-rewrite/methods/route-logic/heritage"; +import { loadSessionBeforeEnter } from "@/router/a-rewrite/methods/route-logic/load-session"; +import { autoRouteBeforeEnter } from "@/router/a-rewrite/methods/route-logic/auto-route"; +import { errorBeforeEnter } from "@/router/a-rewrite/methods/route-logic/error"; +import { restartBeforeEnter } from "@/router/a-rewrite/methods/route-logic/restart"; + +export const routes = [ + // Non-virtual pages. + createRoute(routeData.VEHICLE, vehicleBeforeEnter), + createRoute(routeData.VEHICLE_DAMAGE), + createRoute(routeData.ESTIMATE), + createRoute(routeData.ADDRESS_LOOKUP), + createRoute(routeData.VIN_LOOKUP), + createRoute(routeData.LICENSE_PLATE_LOOKUP), + createRoute(routeData.SERVICE_ZIP), + createRoute(routeData.ADDRESS_VEHICLES), + createRoute(routeData.VEHICLE_PARTS), + createRoute(routeData.PART_QUESTIONS), + createRoute(routeData.MOLDING_QUESTIONS), + createRoute(routeData.CAPABILITY_QUESTIONS), + createRoute(routeData.QUOTE, quoteBeforeEnter), + createRoute(routeData.INSURANCE_COMPANY, insuranceCompanyBeforeEnter), + createRoute(routeData.SERVICE_LOCATION), + createRoute(routeData.SCHEDULE), + createRoute(routeData.CUSTOMER_DETAILS), + createRoute(routeData.PAYMENT_METHOD), + createRoute(routeData.PAYMENT), + createRoute(routeData.PAYMENT_PIA_RETURN), + createRoute(routeData.CONFIRMATION), + createRoute(routeData.RETURN_USER), + + // Virtual pages (resolve to a non-virtual page.) + createVirtualRoute(routeData.LANDING, landingBeforeEnter), + createVirtualRoute(routeData.HERITAGE, heritageBeforeEnter), + createVirtualRoute(routeData.LOAD_SESSION, loadSessionBeforeEnter), + createVirtualRoute(routeData.AUTO_ROUTE, autoRouteBeforeEnter), + createVirtualRoute(routeData.ERROR, errorBeforeEnter), + createVirtualRoute(routeData.RESTART, restartBeforeEnter), +]; From 81a709f716b7eee54059addbc75dd0eb972ff2a4 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 13 May 2025 16:36:23 -0400 Subject: [PATCH 03/13] Reapply "Unplug Legacy Router" This reverts commit 7b73313513094ff5921570fc14d5106198db0aa7. --- src/constants/application-config.js | 1 + src/digital-components/modal/modal.vue | 8 +- src/fmg-components/nav-bar/nav-bar.vue | 9 +- src/global-methods.js | 2 +- .../heritage-integration/navigation-helper.js | 102 -- src/helpers/unit-test-helper.js | 6 +- src/layouts/address-lookup/address-lookup.vue | 5 +- .../address-vehicles/address-vehicles.vue | 7 +- .../capability-questions.vue | 6 +- src/layouts/estimate/estimate.vue | 2 +- .../license-plate-lookup.vue | 7 +- .../molding-questions/molding-questions.vue | 6 +- src/layouts/part-questions/part-questions.vue | 6 +- src/layouts/payment-method/payment-method.vue | 3 +- .../payment-pia-return/payment-pia-return.vue | 1 - src/layouts/payment/payment.vue | 8 +- src/layouts/quote/quote.vue | 8 +- src/layouts/service-zip/service-zip.vue | 6 +- src/layouts/vehicle-damage/vehicle-damage.vue | 1 - src/layouts/vehicle-parts/vehicle-parts.vue | 6 +- src/layouts/vehicle/vehicle.vue | 2 +- src/layouts/vin-lookup/vin-lookup.vue | 9 +- src/main.js | 2 +- src/mixins/analytics-mixin.js | 5 +- src/mixins/base-mixin.js | 6 +- src/mixins/vehicle-questions-mixin.js | 38 +- src/router/a-rewrite/index.js | 38 - .../constants/auto-route-table.js | 0 .../constants/externalUrl-values.js | 0 .../constants/navigation-scenarios.js | 0 .../{a-rewrite => }/constants/route-prefix.js | 0 .../{a-rewrite => }/constants/routes.js | 0 .../constants/routing-table.js | 6 +- .../dynamic-routing/component-loader.js | 3 - src/router/index.js | 947 +----------------- .../{a-rewrite => }/methods/after-each.js | 0 .../{a-rewrite => }/methods/before-each.js | 10 +- src/router/{a-rewrite => }/methods/error.js | 4 +- .../{a-rewrite => }/methods/get-route.js | 2 +- .../methods/helpers/build-manual-url.js | 2 +- .../methods/helpers/consume-referral-info.js | 0 .../methods/helpers/create-route.js | 4 +- .../methods/helpers/get-destination.js | 2 +- .../helpers/initialize-from-querystrings.js | 0 .../methods/helpers/lazy-load-component.js | 0 .../methods/helpers/querystring-stash.js | 0 .../helpers/requires-verified-redirect.js | 0 .../methods/helpers/run-experiments.js | 0 .../methods/helpers/save-page-data.js | 0 .../methods/navigate-external.js | 0 .../{a-rewrite => }/methods/navigate.js | 16 +- .../methods/page-prerequisites.js | 2 +- .../methods/route-logic/auto-route.js | 6 +- .../methods/route-logic/error.js | 4 +- .../methods/route-logic/heritage.js | 0 .../methods/route-logic/insurance-company.js | 4 +- .../methods/route-logic/landing.js | 10 +- .../methods/route-logic/load-session.js | 2 +- .../methods/route-logic/quote.js | 4 +- .../methods/route-logic/restart.js | 4 +- .../methods/route-logic/vehicle.js | 4 +- src/router/{a-rewrite => }/methods/routes.js | 22 +- src/router/methods/send-to-return-user.js | 11 + .../router-constants/externalUrl-values.js | 6 - src/router/router-constants/fmgPage-values.js | 32 - .../router-constants/navigation-scenarios.js | 59 -- src/router/router-constants/router-params.js | 6 - src/router/router-constants/routing-table.js | 546 ---------- src/store/index.js | 38 +- 69 files changed, 171 insertions(+), 1885 deletions(-) delete mode 100644 src/router/a-rewrite/index.js rename src/router/{a-rewrite => }/constants/auto-route-table.js (100%) rename src/router/{a-rewrite => }/constants/externalUrl-values.js (100%) rename src/router/{a-rewrite => }/constants/navigation-scenarios.js (100%) rename src/router/{a-rewrite => }/constants/route-prefix.js (100%) rename src/router/{a-rewrite => }/constants/routes.js (100%) rename src/router/{a-rewrite => }/constants/routing-table.js (99%) delete mode 100644 src/router/dynamic-routing/component-loader.js rename src/router/{a-rewrite => }/methods/after-each.js (100%) rename src/router/{a-rewrite => }/methods/before-each.js (86%) rename src/router/{a-rewrite => }/methods/error.js (78%) rename src/router/{a-rewrite => }/methods/get-route.js (71%) rename src/router/{a-rewrite => }/methods/helpers/build-manual-url.js (88%) rename src/router/{a-rewrite => }/methods/helpers/consume-referral-info.js (100%) rename src/router/{a-rewrite => }/methods/helpers/create-route.js (87%) rename src/router/{a-rewrite => }/methods/helpers/get-destination.js (85%) rename src/router/{a-rewrite => }/methods/helpers/initialize-from-querystrings.js (100%) rename src/router/{a-rewrite => }/methods/helpers/lazy-load-component.js (100%) rename src/router/{a-rewrite => }/methods/helpers/querystring-stash.js (100%) rename src/router/{a-rewrite => }/methods/helpers/requires-verified-redirect.js (100%) rename src/router/{a-rewrite => }/methods/helpers/run-experiments.js (100%) rename src/router/{a-rewrite => }/methods/helpers/save-page-data.js (100%) rename src/router/{a-rewrite => }/methods/navigate-external.js (100%) rename src/router/{a-rewrite => }/methods/navigate.js (79%) rename src/router/{a-rewrite => }/methods/page-prerequisites.js (87%) rename src/router/{a-rewrite => }/methods/route-logic/auto-route.js (65%) rename src/router/{a-rewrite => }/methods/route-logic/error.js (92%) rename src/router/{a-rewrite => }/methods/route-logic/heritage.js (100%) rename src/router/{a-rewrite => }/methods/route-logic/insurance-company.js (54%) rename src/router/{a-rewrite => }/methods/route-logic/landing.js (69%) rename src/router/{a-rewrite => }/methods/route-logic/load-session.js (82%) rename src/router/{a-rewrite => }/methods/route-logic/quote.js (75%) rename src/router/{a-rewrite => }/methods/route-logic/restart.js (84%) rename src/router/{a-rewrite => }/methods/route-logic/vehicle.js (81%) rename src/router/{a-rewrite => }/methods/routes.js (60%) create mode 100644 src/router/methods/send-to-return-user.js delete mode 100644 src/router/router-constants/externalUrl-values.js delete mode 100644 src/router/router-constants/fmgPage-values.js delete mode 100644 src/router/router-constants/navigation-scenarios.js delete mode 100644 src/router/router-constants/router-params.js delete mode 100644 src/router/router-constants/routing-table.js diff --git a/src/constants/application-config.js b/src/constants/application-config.js index a03e5f010..788de3fd7 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -6,6 +6,7 @@ const applicationConfig = { COOKIE_PATH: "/", CURRENT_ENVIRONMENT: process.env.VUE_APP_CURRENT_ENVIRONMENT, // "Localhost", "Dev", "QA", and "Prod" HERITAGE_FUNNEL: process.env.VUE_APP_HERITAGE_FUNNEL, + SAFELITE_HOP: process.env.VUE_APP_SAFELITE_HOP, APPLICATION_NAME: "FixMyGlass", ANALYTICS_APPLICATION_NAME: "FixMyGlassNextGen", APPLICATION_ABBREVIATION: "fmg", diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue index 7b89b7e57..4cc75f701 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -46,9 +46,7 @@