"run" endpoint changed parameter name to deviceId to better reflect what is being passed "logExposure" sends deviceId as well as userId now because it is used by new functionality
915 lines
38 KiB
JavaScript
915 lines
38 KiB
JavaScript
// Supporting files
|
|
import { createWebHistory, createRouter } from "vue-router";
|
|
import { storeActions } from "@/constants/store-actions";
|
|
import { storeMutations } from "../constants/store-mutations";
|
|
import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js";
|
|
import { routingTable } from "@/router/router-constants/routing-table.js";
|
|
import { globalEvents, globalEventTypes } from "@/constants/events";
|
|
import { queryStrings } from "@/constants/query-strings";
|
|
import { getQuerystringParameter, buildQuerystringObject } from "@/helpers/querystring-helper";
|
|
import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper";
|
|
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
|
|
import { fmgPageValues, funnelStartPageName } from "@/router/router-constants/fmgPage-values";
|
|
import { externalParameterStatus } from "@/constants/external-parameters";
|
|
|
|
// Heritage integration
|
|
import { isSavedSessionStillActive } from "@/helpers/heritage-integration/session-helper";
|
|
import {
|
|
updateOrCreateFunnelCookie,
|
|
getFunnelCookie,
|
|
updateSessionIdCookie,
|
|
deleteFunnelCookie,
|
|
getAffiliateCookies,
|
|
setupAdvertiserTracking,
|
|
} from "@/helpers/heritage-integration/cookie-helper";
|
|
import { loadSessionIfPresent, saveSession } from "@/helpers/heritage-integration/order-helper";
|
|
import {
|
|
getPageToRouteExistingOrderTo,
|
|
navigateToHeritageFunnel,
|
|
getImplicitNavigation,
|
|
} from "@/helpers/heritage-integration/navigation-helper";
|
|
|
|
import baseMixin from "@/mixins/base-mixin";
|
|
import eventBus from "@/helpers/event-bus/event-bus";
|
|
import store from "@/store";
|
|
import analyticsMixin from "@/mixins/analytics-mixin";
|
|
import { experimentTriggers } from "../constants/experiments";
|
|
import { applicationConfig } from "../constants/application-config";
|
|
import { shouldStripPromoQueryString } from "@/helpers/promotions-helper";
|
|
import bailout from "@/layouts/bailout/bailout";
|
|
import { nextTick } from "vue";
|
|
import { getBoolFromString } from "@/helpers/boolean-helper";
|
|
|
|
const routes = [
|
|
{
|
|
path: "/bailout",
|
|
name: "bailout",
|
|
component: bailout,
|
|
},
|
|
{
|
|
path: "/",
|
|
name: "root",
|
|
async beforeEnter(to, from, next) {
|
|
// If we have no query string, or we don't have the FmgPage query string.
|
|
try {
|
|
log("------------- router index.js beforeEnter start -----------------");
|
|
log(" --to: ", to);
|
|
log(" --cookie: ", getFunnelCookie());
|
|
log(` --from.redirectedFrom:>${JSON.stringify(from.redirectedFrom)}<`, "");
|
|
|
|
await analyticsMixin.methods.validateSession();
|
|
|
|
// after session is validated, remove the fromHeritage querystring if it exists so session expiration works
|
|
if (to.query) {
|
|
delete to.query[queryStrings.FROM_HERITAGE];
|
|
}
|
|
|
|
if (getFunnelCookie()?.SuppressConceptFunnel) {
|
|
log(" --go to heritage suppressConceptFunnel: ");
|
|
await navigateToHeritageFunnel({ shouldSaveSession: false });
|
|
return next(false);
|
|
}
|
|
|
|
// If the saved session has timed out, clear the session, execute 404 logic.
|
|
if (getFunnelCookie() !== null && !isSavedSessionStillActive()) {
|
|
log(" --save session timeout go to start");
|
|
|
|
const errorPayload = {
|
|
cause: "expired session",
|
|
currentPage: from?.query?.fmgPage,
|
|
nextPage: to?.query?.fmgPage,
|
|
};
|
|
|
|
await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
|
|
deleteFunnelCookie();
|
|
GoToFunnelStartOn404(next, errorPayload);
|
|
return;
|
|
}
|
|
|
|
const fromReturnUser = from?.name === fmgPageValues.RETURN_USER;
|
|
const fromContentSite = getQuerystringParameter(queryStrings.START_TYPE) === "fmg";
|
|
const toReturnUserPage = to.query?.fmgPage === fmgPageValues.RETURN_USER;
|
|
log(" --fromReturnUser ", fromReturnUser);
|
|
log(" --to.query.fmgPage ", to.query?.fmgPage);
|
|
|
|
// Intercept all navigation if a submitted order exists in storage
|
|
if (window.sessionStorage.getItem("submittedOrder") !== null) {
|
|
if (to.query.fmgPage !== funnelStartPageName) {
|
|
to.query.fmgPage = fmgPageValues.CONFIRMATION;
|
|
log(" --has submittedOrder go to confirmation");
|
|
}
|
|
}
|
|
// On entering the funnel "fresh", read cookie information, decide what to do next.
|
|
else if (from.redirectedFrom === undefined || fromReturnUser) {
|
|
// if entering the funnel from the content site, check and see if there is already a vehicle year in vuex.
|
|
// if so, send them to return-user page.
|
|
if (
|
|
fromContentSite &&
|
|
!toReturnUserPage &&
|
|
store.getters.order.vehicle?.year > 0
|
|
) {
|
|
log(" --from content site navigate to return user");
|
|
var qso = {
|
|
fmgPage: fmgPageValues.RETURN_USER,
|
|
};
|
|
|
|
const newQueryString = buildQuerystringObject(qso, true);
|
|
log(" -- returnUser add querystring: " + JSON.stringify(newQueryString));
|
|
|
|
router.push({
|
|
path: "/",
|
|
query: Object.assign({}, newQueryString),
|
|
});
|
|
return;
|
|
}
|
|
|
|
// clear the saveSessionPromise - if it exists in the vuex store but a new instance was created
|
|
// the saveSessionPromise will no longer point to a valid promise
|
|
log(" --clear promise");
|
|
baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
|
|
|
if (!to.query.fmgPage?.startsWith("payment")) {
|
|
//payment pages used to return from safelitehop so exclude here
|
|
// Remove the parameter after quote release
|
|
|
|
// for testing end to end locally, see if there is a referralNumber on the querystring
|
|
// that could have changed in heritage and then stick it in the store and then update the cookie
|
|
// so load-session runs properly. this can be removed when heritage goes away
|
|
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();
|
|
}
|
|
|
|
//Affiliate Cookies
|
|
const affiliateCookies = getAffiliateCookies();
|
|
if (affiliateCookies != null && affiliateCookies.length > 0) {
|
|
store.commit(storeMutations.UPDATE_AFFILIATE_COOKIES, affiliateCookies);
|
|
}
|
|
setupAdvertiserTracking();
|
|
log(" --load session start");
|
|
const loadSessionResponse = await loadSessionIfPresent(
|
|
to.query.isInsurance != null
|
|
? to.query.isInsurance == "true"
|
|
? true
|
|
: false
|
|
: null,
|
|
to.query.fmgPage
|
|
);
|
|
log(" --load session end");
|
|
|
|
//Update external parameter state but not when returning from heritage
|
|
if (!to.query.fmgPage?.startsWith("service-location") && !fromReturnUser) {
|
|
updateExternalParameterState();
|
|
}
|
|
|
|
// clear part related state because heritage selected a new vehicle
|
|
if (
|
|
to.query.fmgPage === fmgPageValues.VEHICLE &&
|
|
getBoolFromString(getFunnelCookie()?.HasDelayedClaimRegistration) &&
|
|
!fromReturnUser
|
|
) {
|
|
store.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
|
}
|
|
|
|
// if coming from the return user page, clear the destination page so implicit navigation runs
|
|
log(" --to.query ", JSON.stringify(to.query));
|
|
if (fromReturnUser && to.query) {
|
|
log(" --clear to.query");
|
|
delete to.query[queryStrings.FMG_PAGE];
|
|
|
|
//to.query[queryStrings.FMG_PAGE] = "";
|
|
log(" --to.query cleared ", JSON.stringify(to.query));
|
|
}
|
|
|
|
const pageToRedirectTo = await getPageToRouteExistingOrderTo(to);
|
|
log(" --pageToRedirectTo ", JSON.stringify(pageToRedirectTo));
|
|
|
|
// This logic may determine that the user should be sent to heritage -- if so, do that here.
|
|
if (pageToRedirectTo === fmgPageValues.HERITAGE) {
|
|
// prettier-ignore
|
|
log(" --go to heritage pageToRedirectTo ", JSON.stringify(pageToRedirectTo));
|
|
await navigateToHeritageFunnel({ shouldSaveSession: false });
|
|
return next(false);
|
|
}
|
|
|
|
// Assign our fmgPage so it will load normally like the other pages.
|
|
to.query.fmgPage = pageToRedirectTo;
|
|
log(" --assign to: ", JSON.stringify(pageToRedirectTo));
|
|
}
|
|
}
|
|
|
|
// Reroute around pages that should not be available.
|
|
|
|
// Exception 1: Integrated Users should not see vehicle or quote pages.
|
|
if (
|
|
store.getters.payment?.insuranceCoverage?.isVerified ||
|
|
store.getters.order?.referralNumber?.length === 6
|
|
) {
|
|
if (to.query.fmgPage === fmgPageValues.VEHICLE) {
|
|
to.query.fmgPage = fmgPageValues.VEHICLE_DAMAGE;
|
|
} else if (
|
|
to.query.fmgPage === fmgPageValues.QUOTE ||
|
|
to.query.fmgPage === fmgPageValues.INSURANCE_COMPANY
|
|
) {
|
|
log(" --block quote page for integrated clients - go to heritage");
|
|
// Push to heritage if going to quote & integrated.
|
|
await navigateToHeritageFunnel({ shouldSaveSession: false });
|
|
return next(false);
|
|
}
|
|
}
|
|
|
|
await runExperiments(to.query.fmgPage);
|
|
|
|
//Affiliate Cookies
|
|
const affiliateCookies = getAffiliateCookies();
|
|
if (affiliateCookies != null && affiliateCookies.length > 0) {
|
|
store.commit(storeMutations.UPDATE_AFFILIATE_COOKIES, affiliateCookies);
|
|
}
|
|
setupAdvertiserTracking();
|
|
// Process funnel cookie.
|
|
updateOrCreateFunnelCookie();
|
|
|
|
// If we already have our route, go to it.
|
|
if (router.hasRoute(to.query.fmgPage)) {
|
|
// Since our route is already in scope, we can grab the component from it and call the arePagePrerequisitesValid function.
|
|
let component = router
|
|
.getRoutes()
|
|
.filter((x) => x.name === to.query.fmgPage)[0].components;
|
|
|
|
// If the component hasn't been loaded fully, load it before we check prerequisites.
|
|
if (component.default.methods === undefined) {
|
|
component = await component.default();
|
|
}
|
|
|
|
if (!arePagePrerequisitesValid(component)) {
|
|
console.log("Page prereq error: " + component.default.name);
|
|
|
|
if (to.query.fmgPage === fmgPageValues.PAYMENT) {
|
|
await store.getters.applicationUser.saveSessionPromise;
|
|
window.location = applicationConfig.PIA_CANCEL_URL;
|
|
return;
|
|
}
|
|
|
|
const errorPayload = {
|
|
cause: "invalid page prerequisites for page",
|
|
currentPage: from?.query?.fmgPage,
|
|
nextPage: to?.query?.fmgPage,
|
|
};
|
|
|
|
GoToFunnelStartOn404(next, errorPayload);
|
|
return;
|
|
}
|
|
|
|
log(" --has route:", to.query.fmgPage);
|
|
return next({ name: to.query.fmgPage, query: to.query, params: to.params });
|
|
}
|
|
|
|
if (!isExistingFmgPageName(to.query.fmgPage)) {
|
|
const errorPayload = {
|
|
cause: "invalid page name",
|
|
currentPage: from?.query?.fmgPage,
|
|
nextPage: to?.query?.fmgPage,
|
|
};
|
|
|
|
GoToFunnelStartOn404(next, errorPayload);
|
|
return;
|
|
}
|
|
|
|
// Get route info for the given url. Names will have a 1:1 relationship with names in the Cms.
|
|
const routeData = GetRouteInfoFromPageName(to.query.fmgPage);
|
|
log("--routeData:", routeData);
|
|
|
|
// Add our dynamic route.
|
|
router.addRoute({
|
|
path: routeData[0].path, // Always the same path, because we control it with query strings.
|
|
name: routeData[0].name,
|
|
component: routeData[0].component,
|
|
});
|
|
|
|
// Call the next components arePagePrerequisitesValid method before load.
|
|
// If it returns false, use the 404 logic.
|
|
const nextComponent = await router
|
|
.getRoutes()
|
|
.filter((x) => x.name === routeData[0].name)[0]
|
|
.components.default();
|
|
|
|
if (!arePagePrerequisitesValid(nextComponent)) {
|
|
// prettier-ignore
|
|
console.log("Page Prereqs not valid for next component: " + nextComponent.default.name);
|
|
|
|
const errorPayload = {
|
|
cause: "invalid page prerequisites for page",
|
|
currentPage: from?.query?.fmgPage,
|
|
nextPage: to?.query?.fmgPage,
|
|
};
|
|
|
|
GoToFunnelStartOn404(next, errorPayload);
|
|
return;
|
|
}
|
|
|
|
log("------------- router index.js beforeEnter end -----------------");
|
|
|
|
// Assign current query string parameters, as well as our fmgPage one.
|
|
next({
|
|
name: routeData[0].name,
|
|
query: Object.assign(to.query, { fmgPage: routeData[0].name }),
|
|
params: to.params,
|
|
});
|
|
} catch (error) {
|
|
global.$logger.logError(`Routing ${error.stack}`);
|
|
|
|
if (to.query?.fmgPage === funnelStartPageName) {
|
|
deleteFunnelCookie();
|
|
await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
|
|
}
|
|
|
|
console.log(new Date() + " Exception in beforeEnter:" + JSON.stringify(error));
|
|
|
|
// If we don't have a route, go to our 404 page.
|
|
const errorPayload = {
|
|
cause: "uncaught error in beforeEnter",
|
|
currentPage: from?.query?.fmgPage,
|
|
nextPage: to?.query?.fmgPage,
|
|
fullError: error,
|
|
errorStack: error?.stack,
|
|
};
|
|
|
|
GoToFunnelStartOn404(next, errorPayload);
|
|
return;
|
|
}
|
|
},
|
|
},
|
|
];
|
|
|
|
const router = createRouter({
|
|
history: createWebHistory("/fmg/"),
|
|
routes,
|
|
//Cause "page" to begin at the top when route chanages.
|
|
scrollBehavior(to, from, savedPosition) {
|
|
// always scroll to top
|
|
return { top: 0 };
|
|
},
|
|
});
|
|
|
|
//---------------------------------------------------------- Router Functions ----------------------------------------------------------
|
|
|
|
router.beforeEach(async (to, from, next) => {
|
|
log("------------- router index.js beforeEach start -----------------");
|
|
// set lastNavigationPage here to capture state before API calls for analytics.
|
|
// use current page url query string name when to.name is "root" (due to unresolved navigation in beforeEach)
|
|
router.lastNavigationPage = to.name == "root" ? analyticsMixin.methods.getPageName() : to.name;
|
|
|
|
const fromQueryPage = from.query?.fmgPage;
|
|
if (fromQueryPage === undefined) {
|
|
showFmgLoadingModal(true);
|
|
}
|
|
|
|
const toQueryPage = to.query?.fmgPage;
|
|
const notToPIAReturn = toQueryPage != fmgPageValues.PAYMENT_PIA_RETURN;
|
|
const isInIframe = window !== window.top;
|
|
|
|
if (store.getters.externalParameterState?.isExternalParameter) {
|
|
// Check if alert event is on the bus
|
|
const alertEvent = eventBus.readEventFromBus(
|
|
globalEvents.Categories.GLOBAL_ALERT,
|
|
globalEvents.SubCategories.PAGE_NOT_FOUND
|
|
);
|
|
//Uknown alerts most likely were added by a failed api call in global-methods
|
|
const unknownAlertEvent = eventBus.readEventFromBus(
|
|
globalEvents.Categories.GLOBAL_ALERT,
|
|
globalEvents.SubCategories.UNKNOWN_ERROR
|
|
);
|
|
// If alert event is on the bus, then display the alert
|
|
if (alertEvent !== undefined || unknownAlertEvent !== undefined) {
|
|
store.commit(
|
|
storeMutations.UPDATE_IS_EXTERNAL_PARAMETER,
|
|
externalParameterStatus.INACTIVE
|
|
);
|
|
}
|
|
}
|
|
// fromPaymentToConfirmation workaround for navigating from an iframe but
|
|
// isInIframe evaluates to false for some reason when navigating from payment to confirmation
|
|
const fromPaymentToConfirmation =
|
|
fromQueryPage === fmgPageValues.PAYMENT && toQueryPage === fmgPageValues.CONFIRMATION;
|
|
|
|
if ((isInIframe && notToPIAReturn) || fromPaymentToConfirmation) {
|
|
const newUrl = `${window.top.location.origin}${to.href}`;
|
|
window.top.location.href = newUrl;
|
|
next(false);
|
|
|
|
// Refresh page if navigating to self to prevent locking.
|
|
// For now only carved out for vehicle; all modals are opened through anchor tags at the moment,
|
|
// which also self navigate, but relied on the page remaining the same on self-navigation.
|
|
} else if (toQueryPage === fromQueryPage && toQueryPage === getRedirectedStartPage()) {
|
|
router.go(0);
|
|
next(false);
|
|
} else {
|
|
next();
|
|
}
|
|
log("------------- router index.js beforeEach end -----------------");
|
|
});
|
|
|
|
router.afterEach(async (to, from) => {
|
|
// Update lastPageVisited in the store
|
|
store.commit(storeMutations.UPDATE_LAST_PAGE_VISITED, to.name);
|
|
|
|
// If saving on navigation is requested, check for saved SessionId or EmailAddress to determine if saving is appropriate
|
|
if (getBoolFromString(window.history.state.isSavingNavigation)) {
|
|
if (
|
|
store.getters.applicationUser.savedSessionId ||
|
|
store.getters.order.customer?.emailAddress
|
|
) {
|
|
await saveSession({ pageNameToLog: to.query.fmgPage });
|
|
}
|
|
}
|
|
if (!store.getters.externalParameterState?.isExternalParameter) {
|
|
showFmgLoadingModal(false);
|
|
}
|
|
|
|
// 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();
|
|
|
|
if (to.query.fmgPage == fmgPageValues.CONFIRMATION) {
|
|
//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();
|
|
}
|
|
});
|
|
|
|
router.navigateWithoutSaving = (
|
|
scenario,
|
|
currentRoute,
|
|
optionalQuery = {},
|
|
optionalParams = {},
|
|
optionalPageData = {}
|
|
) => {
|
|
navigate(scenario, currentRoute, false, optionalQuery, optionalParams, optionalPageData);
|
|
};
|
|
|
|
router.navigateWithSaving = (
|
|
scenario,
|
|
currentRoute,
|
|
optionalQuery = {},
|
|
optionalParams = {},
|
|
optionalPageData = {}
|
|
) => {
|
|
navigate(scenario, currentRoute, true, optionalQuery, optionalParams, optionalPageData);
|
|
};
|
|
|
|
router.navigateToExternalUrl = (url, optionalQuery = {}) => {
|
|
log("------------- router navigateToExternalUrl -----------------");
|
|
log("url:", url);
|
|
navigateToUrl(url, optionalQuery);
|
|
};
|
|
|
|
router.navigateError = (errorPayload = null) => {
|
|
DisplayPageError(errorPayload);
|
|
};
|
|
|
|
//Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example.
|
|
router.overrideNavigation = (
|
|
scenario,
|
|
currentRoute,
|
|
next,
|
|
isSavingNavigation,
|
|
optionalQuery = {},
|
|
optionalParams = {},
|
|
optionalPageData
|
|
) => {
|
|
log("------------- router overrideNavigation -----------------");
|
|
log("scenario:", scenario);
|
|
log("currentRoute:", currentRoute);
|
|
log("isSavingNavigation:", isSavingNavigation);
|
|
log("optionalQuery:", optionalQuery);
|
|
log("optionalParams:", optionalParams);
|
|
log("optionalPageData:", optionalPageData);
|
|
navigate(
|
|
scenario,
|
|
currentRoute,
|
|
isSavingNavigation,
|
|
optionalQuery,
|
|
optionalParams,
|
|
optionalPageData
|
|
);
|
|
next();
|
|
};
|
|
|
|
router.getNextPage = () => nextPageName;
|
|
|
|
// PRIVATE VARIABLES
|
|
|
|
var nextPageName;
|
|
|
|
// PRIVATE FUNCTIONS
|
|
|
|
// Navigate to the next route, depending on the scenario.
|
|
async function navigate(
|
|
scenario,
|
|
currentRoute,
|
|
isSavingNavigation,
|
|
optionalQuery = {},
|
|
optionalParams = {},
|
|
optionalPageData = {}
|
|
) {
|
|
if (!scenario) {
|
|
console.error("No scenario provided. Please review the routing table.");
|
|
return;
|
|
}
|
|
|
|
// Match our maps up and navigate if we have a destination.
|
|
const matchingScenarioMap = getNavigationMap(scenario, currentRoute);
|
|
const destinationFmgPageValue = matchingScenarioMap.destinationFmgPageValue;
|
|
|
|
if (destinationFmgPageValue !== undefined) {
|
|
// We're always pushing the same path, just changing query strings. Make sure our optional query strings get combined with our fmgPage one.
|
|
|
|
nextPageName = destinationFmgPageValue;
|
|
|
|
// Update page data to the store for next page if provided. Otherwise, keep existing page data or set to empty object
|
|
const existingPageDataForPage = store.getters.pageData(destinationFmgPageValue);
|
|
baseMixin.methods.savePageDataToStore(
|
|
destinationFmgPageValue,
|
|
Object.keys(optionalPageData).length > 0
|
|
? optionalPageData
|
|
: (existingPageDataForPage ?? {})
|
|
);
|
|
|
|
optionalParams.isSavingNavigation = isSavingNavigation;
|
|
|
|
// add querystring params to the route. if they are already in the store then no need to add them
|
|
var queryStringsObject = {
|
|
fmgPage: destinationFmgPageValue,
|
|
};
|
|
|
|
const hasZip = getQuerystringParameter(queryStrings.ZIP_CODE);
|
|
const zip = getQuerystringParameter(queryStrings.ZIP_CODE);
|
|
const promo = getQuerystringParameter(queryStrings.PROMO);
|
|
const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
|
|
const logQs = getQuerystringParameter(queryStrings.LOG);
|
|
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, logQs, false);
|
|
|
|
log("------------- router index.js navigate start -----------------");
|
|
log(" --scenario: ", scenario);
|
|
log(" --isSavingNavigation: ", isSavingNavigation);
|
|
log(" --optionalQuery: ", optionalQuery);
|
|
log(" --optionalParams: ", optionalParams);
|
|
log(" --optionalPageData: ", optionalPageData);
|
|
log(" --nextPageName: ", nextPageName);
|
|
|
|
if (
|
|
hasZip &&
|
|
(store.getters.order.serviceLocation.zipCode === undefined ||
|
|
store.getters.order.serviceLocation.zipCode == null) &&
|
|
(store.getters.order.vehicle.registration.zipCode === undefined ||
|
|
store.getters.order.vehicle.registration.zipCode == null)
|
|
) {
|
|
queryStringsObject[queryStrings.ZIP_CODE] = zip;
|
|
}
|
|
|
|
if (promo && !shouldStripPromoQueryString(currentRoute.query.fmgPage)) {
|
|
queryStringsObject[queryStrings.PROMO] = promo;
|
|
}
|
|
|
|
if (pageError) {
|
|
queryStringsObject[queryStrings.PAGE_ERROR] = pageError;
|
|
}
|
|
|
|
if (logQs) {
|
|
queryStringsObject[queryStrings.LOG] = logQs;
|
|
}
|
|
|
|
log(" querystrings: ", queryStringsObject);
|
|
log("------------- router index.js navigate end -----------------");
|
|
|
|
router.push({
|
|
name: "root",
|
|
query: Object.assign(optionalQuery, queryStringsObject),
|
|
state: optionalParams,
|
|
});
|
|
} else if (matchingScenarioMap.destinationUrl !== undefined) {
|
|
navigateToUrl(matchingScenarioMap.destinationUrl, optionalQuery);
|
|
}
|
|
}
|
|
|
|
// Get navigation map depending on the scenario and the current 'page' you're on.
|
|
function getNavigationMap(scenario, currentRoute) {
|
|
const fmgPageValue = currentRoute.query.fmgPage;
|
|
log("------------- router index.js getNavigationMap start -----------------");
|
|
log("fmgPage: " + fmgPageValue + " scenario: " + scenario, "");
|
|
log("------------- router index.js getNavigationMap end -----------------");
|
|
const matchedQueryValue = routingTable(store)
|
|
.filter(
|
|
(item) =>
|
|
item.fmgPageValue === fmgPageValue &&
|
|
item.maps.filter((map) => map.scenario === scenario).length > 0
|
|
)
|
|
.map((m) => m.maps.filter((map) => map.scenario === scenario))[0]
|
|
.filter((x) => x.filter === true || x.filter === undefined);
|
|
|
|
return matchedQueryValue[0];
|
|
}
|
|
|
|
function log(message, data) {
|
|
const log = getQuerystringParameter(queryStrings.LOG);
|
|
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, log, false);
|
|
|
|
data = data ?? "";
|
|
const outData = typeof data === "object" ? JSON.stringify(data) : data;
|
|
|
|
if (log === "true" || store.getters.applicationUser.loggingOption) {
|
|
console.log(new Date() + message + outData);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------- Private Functions ----------------------------------------------------------
|
|
|
|
// Navigate to an external url.
|
|
function navigateToUrl(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);
|
|
}
|
|
|
|
// Get route information by page name.
|
|
// This will no longer reach out to the Cms. There is a 1:1 relationship between page names and route names and layouts.
|
|
function GetRouteInfoFromPageName(pageName) {
|
|
// check if pagename is a valid route/component
|
|
if (!isExistingFmgPageName(pageName)) {
|
|
return [];
|
|
}
|
|
|
|
const routeData = [
|
|
{
|
|
path: "/",
|
|
name: pageName,
|
|
component: lazyLoadComponent(pageName),
|
|
},
|
|
];
|
|
|
|
return routeData;
|
|
}
|
|
|
|
// Go to our start page on a 404.
|
|
function GoToFunnelStartOn404(next, errorPayload = null) {
|
|
if (errorPayload !== null) {
|
|
errorPayload.type = "GoToFunnelStartOn404";
|
|
analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload);
|
|
|
|
console.log(
|
|
"%cGoToFunnelStartOn404()... errorPayload",
|
|
"color: white; background-color: blue; padding: 5px;",
|
|
errorPayload
|
|
);
|
|
}
|
|
|
|
// Put item on the bus
|
|
eventBus.addEventToBus(
|
|
globalEvents.Categories.GLOBAL_ALERT,
|
|
globalEvents.SubCategories.PAGE_NOT_FOUND,
|
|
{
|
|
isDismissible: true,
|
|
messageCopy: "You can get a quote by starting on this page.",
|
|
messageHeadline: "We're sorry, something went wrong.",
|
|
type: globalEventTypes.Danger,
|
|
}
|
|
);
|
|
|
|
next({
|
|
path: "/",
|
|
query: { fmgPage: funnelStartPageName },
|
|
});
|
|
}
|
|
|
|
async function DisplayPageError(errorPayload = null) {
|
|
console.log("%c running DisplayPageError()... ", "font-size: 20px; color: purple;");
|
|
|
|
if (errorPayload !== null) {
|
|
errorPayload.type = "DisplayPageError";
|
|
analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload);
|
|
} else {
|
|
// very cautiously to avoid additional errors:
|
|
var currentPage = "";
|
|
try {
|
|
currentPage = getQuerystringParameter(queryStrings.FMG_PAGE);
|
|
} catch (e) {
|
|
// pass
|
|
}
|
|
errorPayload = {
|
|
type: "DisplayPageError",
|
|
cause: "Unknown page error",
|
|
currentPage: currentPage,
|
|
};
|
|
analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload);
|
|
}
|
|
|
|
// Put item on the bus
|
|
eventBus.addEventToBus(
|
|
globalEvents.Categories.GLOBAL_ALERT,
|
|
globalEvents.SubCategories.UNKNOWN_ERROR,
|
|
{
|
|
isDismissible: true,
|
|
messageCopy: "",
|
|
messageHeadline: "We're sorry, something went wrong.",
|
|
type: globalEventTypes.Danger,
|
|
}
|
|
);
|
|
if (
|
|
store.getters.externalParameterState?.isExternalParameter == externalParameterStatus.ACTIVE
|
|
) {
|
|
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.INACTIVE);
|
|
}
|
|
baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
|
const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
|
|
|
|
// we use the pageError querystring as a counter to how many times a user has experienced an error and been routed here.
|
|
// once they receive more than 1 pageerrors, we'll reset their state to hopefully correct any issues they may be having.
|
|
var navPage = fmgPageValues.VEHICLE;
|
|
if (store.getters.payment?.insuranceCoverage?.isVerified) {
|
|
navPage = fmgPageValues.VEHICLE_DAMAGE;
|
|
}
|
|
|
|
if (pageError) {
|
|
var errorCount = Number(pageError);
|
|
if (errorCount > 1) {
|
|
deleteFunnelCookie();
|
|
await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
|
|
|
|
router.push({
|
|
path: "/",
|
|
query: { fmgPage: navPage },
|
|
});
|
|
} else {
|
|
errorCount++;
|
|
router.push({
|
|
path: "/",
|
|
query: { fmgPage: navPage, pageError: errorCount },
|
|
});
|
|
}
|
|
} else {
|
|
router.push({
|
|
path: "/",
|
|
query: { fmgPage: navPage, pageError: "1" },
|
|
});
|
|
}
|
|
}
|
|
|
|
function isExistingFmgPageName(pageName) {
|
|
const names = Object.values(fmgPageValues);
|
|
|
|
return names.some((name) => name === pageName);
|
|
}
|
|
|
|
// Checks arePagePrerequisitesValid on the component passed in.
|
|
function arePagePrerequisitesValid(component) {
|
|
return component.default.methods.arePagePrerequisitesValid();
|
|
}
|
|
|
|
// Run SiteEntry and PageEntry triggers for experiments
|
|
async function runExperiments(nextPage) {
|
|
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,
|
|
},
|
|
nextPage
|
|
);
|
|
}
|
|
|
|
await baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.RUN_EXPERIMENTS_FOR_TRIGGER,
|
|
{
|
|
deviceId: getDeviceIdValue(),
|
|
triggerEvent: experimentTriggers.PAGE_ENTRY,
|
|
triggerValue: nextPage,
|
|
},
|
|
nextPage
|
|
);
|
|
}
|
|
|
|
function getRedirectedStartPage() {
|
|
if (store.getters.payment?.insuranceCoverage?.isVerified) {
|
|
return fmgPageValues.VEHICLE_DAMAGE;
|
|
} else {
|
|
return funnelStartPageName;
|
|
}
|
|
}
|
|
|
|
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);
|
|
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 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);
|
|
}
|
|
}
|
|
|
|
export default router;
|