diff --git a/public/static/assets/Urbanist-Regular.woff b/public/static/assets/Urbanist-Regular.woff new file mode 100644 index 000000000..7efe9bc42 Binary files /dev/null and b/public/static/assets/Urbanist-Regular.woff differ diff --git a/public/static/assets/Urbanist-SemiBold.woff b/public/static/assets/Urbanist-SemiBold.woff new file mode 100644 index 000000000..92949770b Binary files /dev/null and b/public/static/assets/Urbanist-SemiBold.woff differ diff --git a/public/static/assets/logo.svg b/public/static/assets/logo.svg new file mode 100644 index 000000000..8f739ca15 --- /dev/null +++ b/public/static/assets/logo.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/static/error/index.html b/public/static/error/index.html new file mode 100644 index 000000000..a4c141f85 --- /dev/null +++ b/public/static/error/index.html @@ -0,0 +1,299 @@ + + + + + Error - Safelite + + + +
+
+ +
+
+

+ We're not able to schedule at this time. We apologize for the inconvenience +

+

+ We encountered an error while processing your appointment. You can return to our site and try scheduling again below. +

+
+
+ + + +
+
+
+

+ Bailout Information: +

+
+ +
+
+
+ + + \ No newline at end of file diff --git a/src/global-methods.js b/src/global-methods.js index 0bd0549ea..fc0b3cb41 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -121,7 +121,7 @@ export default { endpoint: endpoint, }; - router.bailout(errorPayload); + router.handleSoftError(errorPayload); // do not log 404 errors from services because we return NotFound // when a service doesn't return an object diff --git a/src/global-methods.spec.js b/src/global-methods.spec.js index c09bf8e97..c8c4d6da9 100644 --- a/src/global-methods.spec.js +++ b/src/global-methods.spec.js @@ -38,7 +38,7 @@ it("Global Methods - Call Http Client - Should Reject Promise", () => { isError: true, }); analyticsMixIn.methods.pushEventToGA = jest.fn(); - router.bailout = jest.fn(); + router.handleSoftError = jest.fn(); //Act globalMethods.callHttpClient(httpArgs).catch((err) => { diff --git a/src/router/constants/routes.js b/src/router/constants/routes.js index 5632fe357..98d6c503a 100644 --- a/src/router/constants/routes.js +++ b/src/router/constants/routes.js @@ -112,7 +112,6 @@ export const routeData = { path: "/virtual/auto-route", virtual: true, }, - // TODO: RENAME FROM BAILOUT ERROR: { name: "error", path: "/virtual/error", diff --git a/src/router/index.js b/src/router/index.js index cd842c5cb..aa07a7a0b 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,7 +1,7 @@ import { routes } from "@/router/methods/routes"; import { afterEach } from "@/router/methods/after-each"; import { beforeEach } from "@/router/methods/before-each"; -import { bailout } from "@/router/methods/error"; +import { handleSoftError, handleHardError } from "@/router/methods/error"; import { navigateWithoutSaving, navigateWithSaving, @@ -32,7 +32,8 @@ router.navigateWithoutSaving = navigateWithoutSaving; router.navigateWithPageData = navigateWithPageData; router.navigateAndForceTopLevelNavigation = navigateAndForceTopLevelNavigation; -router.bailout = bailout; +router.handleSoftError = handleSoftError; +router.handleHardError = handleHardError; router.navigateToExternalUrl = navigateToExternalUrl; diff --git a/src/router/methods/before-each.js b/src/router/methods/before-each.js index e742f89ff..67a6ecf84 100644 --- a/src/router/methods/before-each.js +++ b/src/router/methods/before-each.js @@ -8,7 +8,7 @@ import analyticsMixin from "@/mixins/analytics-mixin"; import { routeData, FUNNEL_START_PAGE } from "@/router/constants/routes"; import { runExperiments } from "@/router/methods/helpers/run-experiments"; -import { bailout } from "@/router/methods/error"; +import { handleSoftError, handleHardError } from "@/router/methods/error"; import { checkPagePrerequisites } from "@/router/methods/page-prerequisites"; import { checkLogParam } from "@/helpers/debug-log-helper"; import { debugLog } from "@/helpers/debug-log-helper"; @@ -41,7 +41,7 @@ export async function beforeEach(to, from) { nextPage: to?.name, }; - bailout(errorPayload, true); + handleSoftError(errorPayload, true); return false; } @@ -88,7 +88,7 @@ export async function beforeEach(to, from) { nextPage: to?.name, }; - bailout(errorPayload); + handleSoftError(errorPayload); return; } @@ -107,7 +107,8 @@ export async function beforeEach(to, from) { console.log(error); - bailout(errorPayload); + // Eject user from Vue app in this scenario and clear localstorage. + await handleHardError(errorPayload); return; } } diff --git a/src/router/methods/error.js b/src/router/methods/error.js index 06eea69b0..42807ce04 100644 --- a/src/router/methods/error.js +++ b/src/router/methods/error.js @@ -4,8 +4,9 @@ import router from "@/router"; import store from "@/store"; import { storeActions } from "@/constants/store-actions"; import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; +import experimentMixin from "../../mixins/experiment-mixin"; -export async function bailout(errorPayload, forceRestart = false) { +export async function handleSoftError(errorPayload, forceRestart = false) { if (forceRestart) { await store.dispatch(storeActions.RESET_STATE); deleteFunnelCookie(); @@ -17,3 +18,23 @@ export async function bailout(errorPayload, forceRestart = false) { name: routeData.ERROR.name, }); } + +export async function handleHardError(errorPayload) { + try { + const isInStaticErrorExperiment = experimentMixin.methods.hasSettingEqualTo( + "UseStaticErrorPage", + "true" + ); + + if (isInStaticErrorExperiment) { + analyticsMixin?.methods?.pushPageErrorToDataLayer(errorPayload); + window.top.location = "/fmg/static/error"; + return; + } else { + await handleSoftError(errorPayload, true); + return; + } + } finally { + await handleSoftError(errorPayload, true); + } +} diff --git a/src/router/methods/helpers/create-route.js b/src/router/methods/helpers/create-route.js index 32410e3b3..828777603 100644 --- a/src/router/methods/helpers/create-route.js +++ b/src/router/methods/helpers/create-route.js @@ -11,7 +11,7 @@ export function createRoute(routeDatum, beforeEnter = async (to, from) => undefi return await beforeEnter(to, from); } catch { return { - name: routeData.BAILOUT.name, + name: routeData.ERROR.name, replace: true, }; } @@ -29,7 +29,7 @@ export function createVirtualRoute(routeDatum, beforeEnter = async (to, from) => } catch (error) { console.log(error); return { - name: routeData.BAILOUT.name, + name: routeData.ERROR.name, replace: true, }; } diff --git a/src/router/methods/navigate.js b/src/router/methods/navigate.js index b15c955e9..25c58e7e5 100644 --- a/src/router/methods/navigate.js +++ b/src/router/methods/navigate.js @@ -5,7 +5,7 @@ import { savePageData } from "@/router/methods/helpers/save-page-data"; import router from "@/router"; import store from "@/store"; -import { bailout } from "@/router/methods/error"; +import { handleSoftError } from "@/router/methods/error"; async function navigate(scenario, currentPageName, withSaving = false, forceTopLevelNav = false) { // Check to see if calling page is same as current page. @@ -30,7 +30,7 @@ async function navigate(scenario, currentPageName, withSaving = false, forceTopL nextPage: nextPage?.name, }; - bailout(errorPayload); + handleSoftError(errorPayload); return; } diff --git a/src/router/methods/route-logic/error.js b/src/router/methods/route-logic/error.js index 8707a65d9..573d3cddd 100644 --- a/src/router/methods/route-logic/error.js +++ b/src/router/methods/route-logic/error.js @@ -5,15 +5,34 @@ import baseMixin from "@/mixins/base-mixin"; import router from "@/router"; import { routeData, FUNNEL_START_PAGE } from "@/router/constants/routes"; import store from "@/store"; +import { handleHardError } from "@/router/methods/error"; export async function errorBeforeEnter(to, from) { - // If we've already encountered one error, clear session to avoid more. - // Otherwise mark that we encoutnered an error here. - if (store.getters.applicationUser.hasAlreadyTriggeredError) { - return { - name: routeData.RESTART.name, - replace: true, + // Check if `hasAlreadyTriggeredErrror` is available. + // If we cannot check it (store, getters, or applicationUser is null-ish), + // act as if the flag is set, as we are in unstable state. + if (!store?.getters?.applicationUser) { + const errorPayload = { + cause: "Cannot access store during error process.", + currentPage: from?.name, + nextPage: to?.name, }; + + handleHardError(errorPayload); + return; + } + + // If we've already encountered one error, clear session to avoid more. + // Otherwise mark that we encountered an error here. + if (store.getters.applicationUser.hasAlreadyTriggeredError) { + const errorPayload = { + cause: "Successive errors triggered.", + currentPage: from?.name, + nextPage: to?.name, + }; + + handleHardError(errorPayload); + return; } else { await store.dispatch(storeActions.UPDATE_HAS_TRIGGERED_ERROR, true); }