Merge pull request #1087 from Safelite/feature/digital/global-bailouts
Initial setup of global bailout system
This commit is contained in:
commit
bc9cca6aa3
8 changed files with 66 additions and 32 deletions
|
|
@ -23,7 +23,10 @@ const applicationConfig = Object.freeze({
|
|||
YAHOO_CALENDAR: 'https://calendar.yahoo.com/?v=60',
|
||||
OUTLOOK_CALENDAR:
|
||||
'https://outlook.office.com/calendar/deeplink/compose?path=/calendar/action/compose&rru=addevent',
|
||||
FRONTEND_LOGGER_PATH: "/analytics/api/v1/logging"
|
||||
FRONTEND_LOGGER_PATH: "/analytics/api/v1/logging",
|
||||
BAILOUT_ON_APPLICATION_ERROR: true,
|
||||
BAILOUT_ON_API_ERROR: true,
|
||||
BAILOUT_ON_ROUTER_ERROR: true
|
||||
});
|
||||
|
||||
export default applicationConfig;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ const bailoutCode = Object.freeze({
|
|||
NoPartsAvailable: 10,
|
||||
PartsServiceError: 11,
|
||||
SafeliteNotTheProvider: 12,
|
||||
VehicleYMMSLookupError: 13
|
||||
VehicleYMMSLookupError: 13,
|
||||
ApplicationError: 14,
|
||||
ApiError: 15,
|
||||
RouterError: 16
|
||||
});
|
||||
|
||||
export default bailoutCode;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,18 @@ const bailoutMessage = Object.freeze({
|
|||
code: bailoutCode.Unknown,
|
||||
message: `An unknown bailout occurred: ${getItemData(error)}`
|
||||
}),
|
||||
applicationError: (error) => ({
|
||||
code: bailoutCode.ApplicationError,
|
||||
message: `An application error occurred: ${getItemData(error)}`
|
||||
}),
|
||||
apiError: (error) => ({
|
||||
code: bailoutCode.ApiError,
|
||||
message: `An API error occurred: ${getItemData(error)}`
|
||||
}),
|
||||
routerError: (error) => ({
|
||||
code: bailoutCode.RouterError,
|
||||
message: `A router error occurred: ${getItemData(error)}`
|
||||
}),
|
||||
saveSessionError: (error) => ({
|
||||
code: bailoutCode.SaveSessionError,
|
||||
message: `An error occurred during save session: ${getItemData(error)}`
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@ axios.interceptors.response.use(
|
|||
if (typeof error.response === 'undefined') {
|
||||
// The request was not made, could be a bad url, bad connection or a CORS error.
|
||||
rejectionError = {
|
||||
message:
|
||||
'A network error occurred. '
|
||||
+ 'This could be a CORS issue or a dropped internet connection. '
|
||||
+ 'It is impossible for us to know.',
|
||||
cause: error,
|
||||
response: error,
|
||||
message: axiosResponseInterceptorMessages.NETWORK_ERROR
|
||||
|
|
@ -51,7 +47,7 @@ axios.interceptors.response.use(
|
|||
);
|
||||
|
||||
export default {
|
||||
callHttpClient({ method, endpoint, payload, logApiCall = true }) {
|
||||
callHttpClient({ method, endpoint, payload, logApiCall = true, bailoutOnError = true }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const store = useMainStore();
|
||||
const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO;
|
||||
|
|
@ -66,9 +62,10 @@ export default {
|
|||
[headerKeys.SESSION_SEQUENCE_NUMBER]: sessionKey
|
||||
};
|
||||
|
||||
const url = cfDistroUrl + endpoint;
|
||||
axios({
|
||||
method,
|
||||
url: cfDistroUrl + endpoint,
|
||||
url,
|
||||
data: payloadAndAnalyticsData,
|
||||
crossDomain: true,
|
||||
responseType: 'json',
|
||||
|
|
@ -97,10 +94,11 @@ export default {
|
|||
}
|
||||
|
||||
if (error.response.status !== 404) {
|
||||
global.$logger.logError(
|
||||
`${method}: ${endpoint}: ${error.message}`,
|
||||
error.response
|
||||
);
|
||||
global.$logger.logError(`${method}: ${endpoint}: ${error.message}`, error.response);
|
||||
if (bailoutOnError && global.bailoutOnAxiosError !== undefined)
|
||||
{
|
||||
global.bailoutOnAxiosError({ url, error });
|
||||
}
|
||||
}
|
||||
return reject(error.response);
|
||||
}
|
||||
|
|
|
|||
19
src/main.js
19
src/main.js
|
|
@ -14,6 +14,8 @@ import router from './router';
|
|||
import App from './App.vue';
|
||||
|
||||
import Logger from "@/helpers/logger";
|
||||
import bailoutMessage from '@/constants/bailoutMessage';
|
||||
import applicationConfig from '@/constants/application-config';
|
||||
// Instantiate global logging object
|
||||
global.$logger = new Logger();
|
||||
|
||||
|
|
@ -46,15 +48,26 @@ function getPageName(vm) {
|
|||
// Vue Error Handling
|
||||
vueApp.config.errorHandler = (err, vm, info) => {
|
||||
const pageName = getPageName(vm);
|
||||
global.$logger.logError(
|
||||
`Page Name - ${pageName} - ${info}: ${err.message}\n${err.stack}`
|
||||
);
|
||||
global.$logger.logError(`Page Name - ${pageName} - ${info}: ${err.message}\n${err.stack}`);
|
||||
if (applicationConfig.BAILOUT_ON_APPLICATION_ERROR) {
|
||||
router.navigateBailout(bailoutMessage.applicationError(`[${pageName}] ${info}: ${err.message}\n${err.stack}`));
|
||||
}
|
||||
};
|
||||
|
||||
// Vue Router Error Handling
|
||||
router.onError((err) => {
|
||||
global.$logger.logError(err.message, err.cause);
|
||||
if (applicationConfig.BAILOUT_ON_ROUTER_ERROR) {
|
||||
router.navigateBailout(bailoutMessage.routerError(`${err.message}\n${err.stack}`));
|
||||
}
|
||||
});
|
||||
|
||||
global.bailoutOnAxiosError = (error) => {
|
||||
if (applicationConfig.BAILOUT_ON_API_ERROR) {
|
||||
router.navigateBailout(bailoutMessage.apiError(error));
|
||||
}
|
||||
}
|
||||
|
||||
vueApp.mount('#app');
|
||||
|
||||
// define global rules
|
||||
|
|
|
|||
|
|
@ -281,7 +281,10 @@ function navigate(
|
|||
}
|
||||
|
||||
// Match our maps up and navigate if we have a destination.
|
||||
const matchingScenarioMap = getNavigationMap(scenario, currentRoute);
|
||||
let matchingScenarioMap = getNavigationMap(scenario, currentRoute);
|
||||
if (!matchingScenarioMap && scenario === navigationScenarios.BAILOUT) {
|
||||
matchingScenarioMap = { destinationIssPageValue: issPageValues.BAILOUT_PAGE }
|
||||
}
|
||||
|
||||
if (!matchingScenarioMap) {
|
||||
window.console.error('No matching scenario found. Please review the routing table.');
|
||||
|
|
@ -332,6 +335,18 @@ function navigateToUrl(url, optionalQuery = {}) {
|
|||
window.location.assign(externalUrl);
|
||||
}
|
||||
|
||||
router.navigateBailout = (bailoutData = null) => {
|
||||
if (bailoutData != null && !useMainStore().isBailout) {
|
||||
useMainStore().setBailout(bailoutData)
|
||||
}
|
||||
router.navigate(
|
||||
navigationScenarios.BAILOUT,
|
||||
router.currentRoute.value,
|
||||
{},
|
||||
{ [routerParams.SKIP_SAVE_SESSION]: true }
|
||||
);
|
||||
}
|
||||
|
||||
// Get navigation map depending on the scenario and the current 'page' you're on.
|
||||
function getNavigationMap(scenario, currentRoute) {
|
||||
const issPageValue = currentRoute.query.issPage;
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ const navigationScenarios = Object.freeze({
|
|||
// Bailout
|
||||
CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT',
|
||||
CLICKED_NEED_HELP_WITH_BAILOUT: 'CLICKED_NEED_HELP_WITH_BAILOUT',
|
||||
BAILOUT: 'BAILOUT'
|
||||
});
|
||||
|
||||
export default navigationScenarios;
|
||||
|
|
|
|||
|
|
@ -879,8 +879,7 @@ export const useMainStore = defineStore({
|
|||
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetMobilePremiumFee.method,
|
||||
endpoint: `${endpoints.GetMobilePremiumFee.url}/${paymentType}/${damageType}`,
|
||||
logApiCall: true
|
||||
endpoint: `${endpoints.GetMobilePremiumFee.url}/${paymentType}/${damageType}`
|
||||
});
|
||||
},
|
||||
getMobileTimeSlots(startDate, endDate, zipCodeOverride = null) {
|
||||
|
|
@ -935,14 +934,7 @@ export const useMainStore = defineStore({
|
|||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetMobileTimeSlots.method,
|
||||
endpoint: endpoints.GetMobileTimeSlots.url,
|
||||
payload,
|
||||
logApiCall: true,
|
||||
additionalSuccessEventDataHandler: (response) =>
|
||||
getTimeSlotsAdditionalEventData(
|
||||
response.data.provisionalTriggers,
|
||||
zipCodeOverride ?? order.serviceLocation.zipCode,
|
||||
response.data.days?.[0]?.date
|
||||
)
|
||||
payload
|
||||
});
|
||||
},
|
||||
getShopTimeSlots(startDate, endDate, shopAppointmentType, providerNumber) {
|
||||
|
|
@ -998,8 +990,7 @@ export const useMainStore = defineStore({
|
|||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetShopTimeSlots.method,
|
||||
endpoint: endpoints.GetShopTimeSlots.url,
|
||||
payload,
|
||||
additionalSuccessEventDataHandler: (response) => provisionalTriggersToString(response.data.provisionalTriggers)
|
||||
payload
|
||||
});
|
||||
},
|
||||
async getWipers() {
|
||||
|
|
@ -1553,8 +1544,7 @@ export const useMainStore = defineStore({
|
|||
method: endpoints.SaveSession.method,
|
||||
endpoint: endpoints.SaveSession.url,
|
||||
payload,
|
||||
additionalSuccessEventDataHandler: () =>
|
||||
`Email provided: ${customer.emailAddress ? 'true' : 'false'}`
|
||||
bailoutOnError: false
|
||||
}).then((response) => {
|
||||
if (loadedFromDupeCheck) {
|
||||
this.order.loadedSessionClearedPreviousData = true;
|
||||
|
|
@ -2466,8 +2456,7 @@ export const useMainStore = defineStore({
|
|||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetAlertReasons.method,
|
||||
endpoint: `${endpoints.GetAlertReasons.url}/${ctu}`,
|
||||
payload: {},
|
||||
logApiCall: true
|
||||
payload: {}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue