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"; const routes = [ { path: '/', name: 'root', async beforeEnter(to, from, next) { try { to.query.issPage = !to.query.issPage ? issPageValues.VEHICLE_YEAR : to.query.issPage; 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("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) { console.log(error); GoToStartOn404(next); } } }]; const router = createRouter({ history: createWebHistory("/"), routes, }); router.afterEach((to, from) => { const store = useMainStore(); // Update lastPageVisited in the store store.updateLastPageVisited(to.name); // 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); let 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 = {}) { 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); if (!matchingScenarioMap){ console.error("No matching scenario found. Please review the routing table."); return; } 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. let externalUrl = new URL(url); 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 ); let 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) { console.error(e); return undefined; } }; function GoToStartOn404(next) { const errorPageName = issPageValues.VEHICLE_YEAR; 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;