Merge pull request #427 from Safelite/feature/richardson/SSR-425.1
Access Denied implementation
This commit is contained in:
commit
bd9f9b3ccf
7 changed files with 149 additions and 72 deletions
|
|
@ -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',
|
||||
|
|
|
|||
29
src/layouts/access-denied/access-denied.vue
Normal file
29
src/layouts/access-denied/access-denied.vue
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div class="page-container-grouped-styles access-denied">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<div class="container-fluid px-5">
|
||||
<div class="row mt-5">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<span>Unauthorized Access</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Supporting files
|
||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||
|
||||
export default {
|
||||
name: 'access-denied',
|
||||
mixins: [BaseFormMixin],
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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,25 @@ 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 = {}) => {
|
||||
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.');
|
||||
|
|
@ -171,10 +192,10 @@ function navigate(scenario,
|
|||
} 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.
|
||||
|
|
@ -194,7 +215,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 +228,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 +239,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 +262,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 +275,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();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const issPageValues = Object.freeze({
|
||||
ACCESS_DENIED: 'access-denied',
|
||||
ENTRY_PAGE: 'entry-page',
|
||||
WELCOME_PAGE: 'welcome-page',
|
||||
|
||||
|
|
|
|||
|
|
@ -319,6 +319,15 @@ const routingTable = () => [
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
issPageValue: issPageValues.ACCESS_DENIED,
|
||||
maps: [
|
||||
{
|
||||
scenario: navigationScenarios.CLICKED_BACK,
|
||||
destinationIssPageValue: issPageValues.ACCESS_DENIED
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
issPageValue: issPageValues.ENTRY_PAGE,
|
||||
maps: [
|
||||
|
|
|
|||
|
|
@ -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: '/',
|
||||
|
|
|
|||
Loading…
Reference in a new issue