DigitalConsumer.ISS/src/router/index.js
2023-08-31 16:11:53 -04:00

277 lines
9.5 KiB
JavaScript

import { createWebHistory, createRouter } from 'vue-router';
import lazyLoadComponent from '@/router/dynamic-routing/component-loader';
import issPageValues from '@/router/router-constants/issPage-values';
import { routingTable } from '@/router/router-constants/routing-table';
import { useMainStore } from '@/store';
import eventBus from '@/helpers/event-bus/event-bus';
import { globalEvents, globalEventTypes } from '@/constants/events';
import baseMixin from '@/mixins/base-mixin';
import {
getDeviceIdValue,
updateOrCreateISSCookie,
updateSessionIdCookie
} from '@/helpers/cookie-helper';
import { experimentTriggers } from '@/constants/experiments';
import applicationConfig from '@/constants/application-config';
import analyticsMixin from '@/mixins/analytics-mixin';
import navigationScenarios from './router-constants/navigation-scenarios';
import { saveSession } from "@/helpers/order-helper.js";
const routes = [
{
path: '/',
name: 'root',
async beforeEnter(to, from, next) {
try {
to.query.issPage = !to.query.issPage
? issPageValues.WELCOME_PAGE
: to.query.issPage;
// Do not run these for the main entry page - as it is not part of the user flow.
if (to.query.issPage !== issPageValues.ENTRY_PAGE) {
if (analyticsMixin.methods.noSession()) {
await analyticsMixin.methods.initSession();
} else {
updateSessionIdCookie();
}
await runExperiments(to.query.issPage);
}
// Process ISS cookie.
updateOrCreateISSCookie();
if (router.hasRoute(to.query.issPage)) {
return next({ name: to.query.issPage, query: to.query, params: to.params });
}
const routeData = await GetRouteInfoFromPageName(to.query.issPage);
if (routeData[0].name.toLowerCase() === 'error') {
throw new Error('Page not found!');
}
// 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
});
// Assign current query string parameters, as well as our issPage one.
next({
name: routeData[0].name,
query: Object.assign(to.query, { issPage: routeData[0].name }),
params: to.params
});
} catch (error) {
window.console.warn(error);
GoToStartOn404(next);
}
return null;
}
}
];
const router = createRouter({
history: createWebHistory('/'),
routes,
scrollBehavior(to, from, savedPosition) {
// always scroll to top
return { top: 0 };
}
});
router.afterEach(async (to, from) => {
/*eslint-disable-line*/
const store = useMainStore();
// Update lastPageVisited in the store
store.updateLastPageVisited(to.name);
console.log('after each');
await saveSession({shouldAwaitSaveSessionQueue: true}).then(() => {
console.log('then');
}).catch((error) => {
console.log(error);
console.log("catch");
if (from.name === issPageValues.WELCOME_PAGE) {
router.navigate(navigationScenarios.SAVE_SESSION_FAILED, {query: {issPage: issPageValues.WELCOME_PAGE}})
}
});
if (to.query.issPage !== issPageValues.ENTRY_PAGE) {
// Push page view to GA
analyticsMixin.methods.pushPageViewToGA();
// Push experiments to Data Layer
analyticsMixin.methods.pushExperimentsToDataLayer();
}
});
// Get route information by page name.
// This will reach out to the Cms and there is a 1:1 relationship between page names and route names.
async function GetRouteInfoFromPageName(pageName) {
const response = await useMainStore().getRouteInfo(pageName);
const jsonFromResponse = JSON.parse(response.data.Result);
const routeData = [];
// Add our route data and return our array.
Object.keys(jsonFromResponse).forEach((key) => {
routeData.push({
path: '/',
name: `${key}`,
component: lazyLoadComponent(jsonFromResponse[key].LayoutName)
});
});
return routeData;
}
// Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example.
router.overrideNavigation = (scenario,
currentRoute,
next,
isSavingNavigation,
optionalQuery = {},
optionalParams = {},
optionalPageData) => {
navigate(scenario,
currentRoute,
isSavingNavigation,
optionalQuery,
optionalParams,
optionalPageData);
next();
};
router.navigate = (scenario,
currentRoute,
optionalQuery = {},
optionalParams = {},
optionalPageData = {}) => {
navigate(scenario, currentRoute, optionalQuery, optionalParams, optionalPageData);
};
// Navigate to the next route, depending on the scenario.
function navigate(scenario,
currentRoute,
optionalQuery = {},
optionalParams = {},
optionalPageData = {}) {
/*eslint-disable-line*/
if (!scenario) {
window.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);
if (!matchingScenarioMap) {
window.console.error('No matching scenario found. Please review the routing table.');
return;
}
if (scenario === navigationScenarios.CLICKED_BACK_PREVIOUS) {
// Update page to the prevous page in the router.
// If we need to worry about typing this in from outside of the app,
// we'll need to pre check history.length or if there is a previous page stored in state.
router.go(-1);
} else if (matchingScenarioMap.destinationIssPageValue) {
// Update page data to the store for next page if provided. Otherwise, keep existing page data or set to empty object
const existingPageDataForPage = useMainStore().pageData(matchingScenarioMap.destinationIssPageValue);
baseMixin.methods.savePageDataToStore(matchingScenarioMap.destinationIssPageValue,
Object.keys(optionalPageData).length > 0
? optionalPageData
: existingPageDataForPage ?? {});
// We're always pushing the same path, just changing query strings.
// Make sure our optional query strings get combined with our issPage one.
router.push({
name: 'root',
query: Object.assign(optionalQuery, {
issPage: matchingScenarioMap.destinationIssPageValue
}),
params: optionalParams
});
} else if (matchingScenarioMap.destinationUrl) {
navigateToUrl(matchingScenarioMap.destinationUrl, optionalQuery);
}
}
// Navigate to an external url.
function navigateToUrl(url, optionalQuery = {}) {
// possibly show some loading screen in the future here.
const externalUrl = new URL(url);
// eslint-disable-next-line no-restricted-syntax
for (const queryKey in optionalQuery) {
externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]);
}
window.location.assign(externalUrl);
}
// Get navigation map depending on the scenario and the current 'page' you're on.
function getNavigationMap(scenario, currentRoute) {
const issPageValue = currentRoute.query.issPage;
try {
const matchedQueryValue = routingTable(useMainStore())
.filter((item) =>
item.issPageValue === issPageValue
&& item.maps.filter((map) => map.scenario === scenario).length > 0);
const maps = matchedQueryValue ? matchedQueryValue.map((m) => m.maps.filter((map) => map.scenario === scenario))[0] : undefined;
return maps ? maps.filter((x) => x.filter === true || x.filter === undefined)[0] : undefined;
} catch (e) {
window.console.error(e);
return undefined;
}
}
function GoToStartOn404(next) {
const errorPageName = issPageValues.WELCOME_PAGE;
router.addRoute({
path: '/',
name: errorPageName,
component: lazyLoadComponent(errorPageName)
});
// 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({
name: errorPageName,
query: { issPage: errorPageName }
});
}
// Run SiteEntry and PageEntry triggers for experiments
async function runExperiments(nextPage) {
const store = useMainStore();
if (!store.applicationUser.triggeredSiteEntry) {
await store.runExperimentsForTrigger({
userId: getDeviceIdValue(),
triggerEvent: experimentTriggers.SITE_ENTRY,
triggerValue: applicationConfig.SITE_ENTRY_TRIGGER_VALUE
});
}
await store.runExperimentsForTrigger({
userId: getDeviceIdValue(),
triggerEvent: experimentTriggers.PAGE_ENTRY,
triggerValue: nextPage
});
}
export default router;