917 lines
38 KiB
JavaScript
917 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 } 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";
|
|
|
|
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 funnel cookie.
|
|
// if so, send them to return-user page.
|
|
const funnelCookieLastTouched = getFunnelCookie()?.LastTouched;
|
|
if (
|
|
fromContentSite &&
|
|
funnelCookieLastTouched !== null &&
|
|
funnelCookieLastTouched !== undefined &&
|
|
!toReturnUserPage
|
|
) {
|
|
log(" --from content site navigate to return user");
|
|
var qso = {
|
|
fmgPage: fmgPageValues.RETURN_USER,
|
|
};
|
|
const lg = getQuerystringParameter(queryStrings.LOG);
|
|
if (lg) {
|
|
qso[queryStrings.LOG] = true;
|
|
}
|
|
|
|
router.push({
|
|
path: "/",
|
|
query: Object.assign({}, qso),
|
|
});
|
|
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 &&
|
|
eval(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 (eval(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,
|
|
{
|
|
userId: getDeviceIdValue(),
|
|
triggerEvent: experimentTriggers.SITE_ENTRY,
|
|
triggerValue: applicationConfig.SITE_ENTRY_TRIGGER_VALUE,
|
|
},
|
|
nextPage
|
|
);
|
|
}
|
|
|
|
await baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.RUN_EXPERIMENTS_FOR_TRIGGER,
|
|
{
|
|
userId: 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;
|