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;