From 3fd982f5f0d5317d50517902e0ce2010b3d59da3 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Mon, 28 Aug 2023 12:24:26 -0400 Subject: [PATCH 1/3] access denied updates --- src/layouts/access-denied/access-denied.vue | 29 ++++ src/router/index.js | 148 +++++++++++------- src/router/router-constants/issPage-values.js | 1 + src/router/router-constants/routing-table.js | 9 ++ vue.config.js | 12 +- 5 files changed, 140 insertions(+), 59 deletions(-) create mode 100644 src/layouts/access-denied/access-denied.vue diff --git a/src/layouts/access-denied/access-denied.vue b/src/layouts/access-denied/access-denied.vue new file mode 100644 index 00000000..d11870bb --- /dev/null +++ b/src/layouts/access-denied/access-denied.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/src/router/index.js b/src/router/index.js index bcf2fd46..1b2e8ace 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,3 +1,4 @@ +/* eslint-disable no-use-before-define */ import { createWebHistory, createRouter } from 'vue-router'; import lazyLoadComponent from '@/router/dynamic-routing/component-loader'; import issPageValues from '@/router/router-constants/issPage-values'; @@ -6,11 +7,8 @@ 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 { isSavedSessionStillActive } from '@/helpers/session-helper'; +import { getDeviceIdValue, getISSCookie, updateOrCreateISSCookie, updateSessionIdCookie } from '@/helpers/cookie-helper'; import { experimentTriggers } from '@/constants/experiments'; import applicationConfig from '@/constants/application-config'; @@ -23,29 +21,52 @@ const routes = [ name: 'root', async beforeEnter(to, from, next) { try { - to.query.issPage = !to.query.issPage - ? issPageValues.WELCOME_PAGE - : to.query.issPage; + const issPageToUse = !to.query.issPage ? issPageValues.WELCOME_PAGE : to.query.issPage; + + if ((issPageToUse === issPageValues.ACCESS_DENIED + || (issPageToUse !== issPageValues.ENTRY_PAGE && !useMainStore().issConfig.accountNumber)) + && process.env.VUE_APP_CURRENT_ENVIRONMENT !== 'Localhost' + ) { + return await GoToAccessIsDenied(next); + } // 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 (issPageToUse !== issPageValues.ENTRY_PAGE) { if (analyticsMixin.methods.noSession()) { await analyticsMixin.methods.initSession(); } else { updateSessionIdCookie(); } - await runExperiments(to.query.issPage); + await runExperiments(issPageToUse); // fmg has this further down + } + + // If the saved session has timed out, clear the session, execute 404 logic. + if (getISSCookie() !== null && !isSavedSessionStillActive()) { + // await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE); + await GoToStartOn404(next); } // Process ISS cookie. updateOrCreateISSCookie(); - if (router.hasRoute(to.query.issPage)) { - return next({ name: to.query.issPage, query: to.query, params: to.params }); + if (router.hasRoute(issPageToUse)) { + // Since our route is already in scope, we can grab the component and call the arePagePrerequisitesValid function. + let component = router.getRoutes().filter((x) => x.name === issPageToUse)[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)) { + await GoToStartOn404(next); + } + + return next({ name: issPageToUse, query: to.query, params: to.params }); } - const routeData = await GetRouteInfoFromPageName(to.query.issPage); + const routeData = await GetRouteInfoFromPageName(issPageToUse); if (routeData[0].name.toLowerCase() === 'error') { throw new Error('Page not found!'); @@ -58,6 +79,19 @@ const routes = [ 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)) { + const tempMsgCopy = 'Pre Requisites failed, need to handle. Default is Welcome Page.'; + const tempMsgHeadline = `${issPageToUse}: pre-req failed...`; + await GoToStartOn404(next, tempMsgCopy, tempMsgHeadline); + } + // Assign current query string parameters, as well as our issPage one. next({ name: routeData[0].name, @@ -66,7 +100,7 @@ const routes = [ }); } catch (error) { window.console.warn(error); - GoToStartOn404(next); + await GoToStartOn404(next); } return null; } @@ -76,15 +110,13 @@ const routes = [ const router = createRouter({ history: createWebHistory('/'), routes, - scrollBehavior(to, from, savedPosition) { + scrollBehavior() { // always scroll to top return { top: 0 }; } }); -router.afterEach((to, from) => { - /*eslint-disable-line*/ - +router.afterEach((to) => { const store = useMainStore(); // Update lastPageVisited in the store store.updateLastPageVisited(to.name); @@ -119,36 +151,33 @@ async function GetRouteInfoFromPageName(pageName) { } // Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example. -router.overrideNavigation = (scenario, +router.overrideNavigation = ( + scenario, currentRoute, next, isSavingNavigation, optionalQuery = {}, optionalParams = {}, - optionalPageData) => { - navigate(scenario, - currentRoute, - isSavingNavigation, - optionalQuery, - optionalParams, - optionalPageData); + optionalPageData = {} +) => { + navigate( + scenario, currentRoute, isSavingNavigation, optionalQuery, optionalParams, optionalPageData + ); next(); }; -router.navigate = (scenario, - currentRoute, - optionalQuery = {}, - optionalParams = {}, - optionalPageData = {}) => { - navigate(scenario, currentRoute, optionalQuery, optionalParams, optionalPageData); +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 = {}) { +function navigate( + scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {} +) { /*eslint-disable-line*/ if (!scenario) { window.console.error('No scenario provided. Please review the routing table.'); @@ -172,9 +201,7 @@ function navigate(scenario, // 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 ?? {}); + 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. @@ -194,7 +221,7 @@ function navigate(scenario, 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 + // eslint-disable-next-line no-restricted-syntax, guard-for-in for (const queryKey in optionalQuery) { externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]); } @@ -207,9 +234,7 @@ 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); + .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; @@ -220,7 +245,21 @@ function getNavigationMap(scenario, currentRoute) { } } -function GoToStartOn404(next) { +async function GoToAccessIsDenied(next) { + const errorPageName = issPageValues.ACCESS_DENIED; + router.addRoute({ + path: '/', + name: errorPageName, + component: lazyLoadComponent(errorPageName) + }); + + next({ + name: errorPageName, + query: { issPage: errorPageName } + }); +} + +async function GoToStartOn404(next, msgCopy = null, msgHeadline = null) { const errorPageName = issPageValues.WELCOME_PAGE; router.addRoute({ path: '/', @@ -229,14 +268,12 @@ function GoToStartOn404(next) { }); // 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 - }); + eventBus.addEventToBus(globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND, { + isDismissible: true, + messageCopy: msgCopy ?? 'You can get a quote by starting on this page.', + messageHeadline: msgHeadline ?? "We're sorry, something went wrong.", + type: globalEventTypes.Danger + }); next({ name: errorPageName, @@ -244,6 +281,11 @@ function GoToStartOn404(next) { }); } +// Checks arePagePrerequisitesValid on the component passed in. +function arePagePrerequisitesValid(component) { + return component.default.methods.arePagePrerequisitesValid === undefined || component.default.methods.arePagePrerequisitesValid(); +} + // Run SiteEntry and PageEntry triggers for experiments async function runExperiments(nextPage) { const store = useMainStore(); diff --git a/src/router/router-constants/issPage-values.js b/src/router/router-constants/issPage-values.js index 9ddfab8c..68ad4a08 100644 --- a/src/router/router-constants/issPage-values.js +++ b/src/router/router-constants/issPage-values.js @@ -1,4 +1,5 @@ const issPageValues = Object.freeze({ + ACCESS_DENIED: 'access-denied', ENTRY_PAGE: 'entry-page', WELCOME_PAGE: 'welcome-page', diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 4af22d4f..7830bac3 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -319,6 +319,15 @@ const routingTable = () => [ } ] }, + { + issPageValue: issPageValues.ACCESS_DENIED, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationIssPageValue: issPageValues.ACCESS_DENIED + } + ] + }, { issPageValue: issPageValues.ENTRY_PAGE, maps: [ diff --git a/vue.config.js b/vue.config.js index 5018024e..a13ba34c 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,14 +1,14 @@ +/* eslint-disable max-len */ process.env.VUE_APP_CONSUMER_CF_DISTRO = 'https://digitalapi.dev.safelite.io'; process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost'; -process.env.VUE_APP_GOOGLE_PLACES_API_KEY - = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0'; +process.env.VUE_APP_GOOGLE_PLACES_API_KEY = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0'; // GA & GTM // NOTE: Using the old ISS site GTM Cotnainer ID for now, will create a new one soon. -process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY - = "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-KKNWZ3');"; -process.env.VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC - = 'https://www.googletagmanager.com/ns.html?id=GTM-KKNWZ3>m_auth=amlAYNhxUxuskQo7jmjadg>m_preview=env-38>m_cookies_win=x'; +process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY = + "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-KKNWZ3');"; +process.env.VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC = + 'https://www.googletagmanager.com/ns.html?id=GTM-KKNWZ3>m_auth=amlAYNhxUxuskQo7jmjadg>m_preview=env-38>m_cookies_win=x'; module.exports = { publicPath: '/', From 406476d6a6ce43d2d50e05d7f70a148642f9c7c3 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Mon, 28 Aug 2023 12:32:42 -0400 Subject: [PATCH 2/3] linting update --- .eslintrc.js | 5 +++-- src/router/index.js | 22 ++++++++-------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index c9deb6a3..440245f9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -18,8 +18,8 @@ module.exports = { 'vue/attribute-hyphenation': ['warn', 'never'], 'vue/v-on-event-hyphenation': ['warn', 'never'], 'object-curly-newline': ['error', { consistent: true }], - 'function-paren-newline': ['error', 'never'], - 'operator-linebreak': ['error', 'before', { overrides: { '=': 'after' }}], + 'function-paren-newline': ['error', 'multiline'], + 'operator-linebreak': ['error', 'before', { overrides: { '=': 'after' } }], 'implicit-arrow-linebreak': ['off'], 'comma-dangle': ['error', 'never'], indent: ['error', 4, { SwitchCase: 1 }], @@ -33,6 +33,7 @@ module.exports = { 'jsdoc/check-tag-names': ['error', { definedTags: ['store', 'endpoint', 'category', 'subcategory', 'remarks'] }], + 'jsdoc/require-jsdoc': 0, 'vue/html-self-closing': ['error', { html: { void: 'any', diff --git a/src/router/index.js b/src/router/index.js index 1b2e8ace..2fa73c97 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -160,24 +160,16 @@ router.overrideNavigation = ( optionalParams = {}, optionalPageData = {} ) => { - navigate( - scenario, currentRoute, 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 - ); +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 = {} -) { +function navigate(scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {}) { /*eslint-disable-line*/ if (!scenario) { window.console.error('No scenario provided. Please review the routing table.'); @@ -200,8 +192,10 @@ function navigate( } 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 ?? {}); + 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. From 70ef75bbc85a36ce88c1e14253b13c9c230ee754 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Mon, 28 Aug 2023 13:43:59 -0400 Subject: [PATCH 3/3] this.mainStore not available in preReq, some linting --- src/layouts/vehicle-damage/vehicle-damage.vue | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index fc8401eb..63e1a02d 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -138,8 +138,10 @@ export default { next((vm) => { vm.setCmsContent(resultMap.cmsContent); vm.$refs.damageLocation.initializeComponent(resultMap.damageOptions); - vm.$refs.sideDoorOptions.initializeComponent(resultMap.damageOptions.driverSideOptions.availableReplacementOptions, - resultMap.damageOptions.passengerSideOptions.availableReplacementOptions); + vm.$refs.sideDoorOptions.initializeComponent( + resultMap.damageOptions.driverSideOptions.availableReplacementOptions, + resultMap.damageOptions.passengerSideOptions.availableReplacementOptions + ); vm.$refs.windshieldOptions.initializeComponent(resultMap.damageOptions.windshieldOptions.availableReplacementOptions); vm.$refs.backGlassOptions.initializeComponent(resultMap.damageOptions.backGlassOptions.availableReplacementOptions); }); @@ -228,7 +230,7 @@ export default { }, methods: { arePagePrerequisitesValid() { - if (this.mainStore.order.vehicle.carId) { + if (useMainStore().order.vehicle.carId) { return true; } return false; @@ -362,23 +364,22 @@ export default { }, async forwardButtonAction() { - await this.mainStore.saveVehicleDamage(this.isWindshieldRepair, + await this.mainStore.saveVehicleDamage( + this.isWindshieldRepair, this.selectedGlassToReplace(), - this.selectedWindshieldOptions.selectedWindshieldChipCount); + this.selectedWindshieldOptions.selectedWindshieldChipCount + ); return this.navigateForward(); }, navigateForward() { if (this.mainStore.damage.isRepair) { - this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR, - this.$route); + this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR, this.$route); } else if (this.mainStore.order.vehicle.vin) { // If vin already exists, navigate directly to vin-lookup - this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_VIN, - this.$route); + this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_VIN, this.$route); } else { - this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN, - this.$route); + this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN, this.$route); } },