@shopgate/engage
Version:
Shopgate's ENGAGE library.
174 lines (166 loc) • 4.29 kB
JavaScript
import { ToastProvider } from '@shopgate/pwa-common/providers';
import { MODAL_PIPELINE_ERROR } from '@shopgate/pwa-common/constants/ModalTypes';
import showModal from '@shopgate/pwa-common/actions/modal/showModal';
import { logger, i18n } from '@shopgate/engage/core/helpers';
/**
* Creates an error message for a pipeline and a code
* @param {string} message The pipeline message
* @param {Object} params Additional params for the message
* @param {string} [pipeline=''] Name of the pipeline which caused the error
* @returns {string}
*/
const getErrorMessage = (message, params = {}, pipeline = '') => {
if (!/^((\w+)\.){1,}/gi.test(message)) {
// Stop processing when the message is no i18n key
return i18n.text(message, params);
}
const segments = message.split('.');
const code = segments.pop();
const pipelineKeys = [];
const codeKeys = [];
const genericKeys = [];
let keys = [];
// Generate a bunch of lookup keys from the message
while (segments.length) {
pipelineKeys.push([].concat(segments, [pipeline, code]));
codeKeys.push([].concat(segments, [code]));
genericKeys.push([].concat(segments, ['generic']));
segments.pop();
}
// Add common keys
keys = [].concat(pipelineKeys, codeKeys, genericKeys, [`common.errors.${code}`, 'common.errors.generic']);
const match = keys.find(key => i18n.getPath(key));
try {
return i18n.text(match, params);
} catch (e) {
return i18n.text(keys[keys.length - 1]);
}
};
/**
* Generates an error object for the error behaviors
* @param {Object} originalError The original error object
* @returns {Object}
*/
const getErrorObject = originalError => {
const {
code,
context: pipeline = '',
meta
} = originalError;
const {
input: pipelineInput = {},
message: originalMessage,
additionalParams,
translated
} = meta;
const message = translated ? originalMessage : getErrorMessage(originalMessage, additionalParams, pipeline);
const sanitized = {
code: code ? code.toString() : code,
pipeline,
pipelineInput,
originalMessage,
message,
additionalParams,
translated
};
return sanitized;
};
/**
* Enables a custom implementation for an error behavior. The passed callback will be invoked with
* an object similar to streams (dispatch, getState, events). Additionally it contains the error
* object and the error message.
* @param {Function} callback A callback function for the custom error behavior
* @returns {Function}
*/
const custom = callback => ({
dispatch,
getState,
events,
error
}) => {
if (typeof callback !== 'function') {
logger.error('errorBehavior.custom: Please provide a callback function');
return;
}
const sanitized = getErrorObject(error);
callback({
dispatch,
getState,
events,
error: sanitized,
message: sanitized.message
});
};
/**
* Enables to dispatch a Redux action via a passed callback.
* The callback is invoked with the error message.
* @param {Function} callback A callback function for the custom error behavior
* @returns {Function}
*/
const dispatchAction = callback => ({
dispatch,
error
}) => {
const {
message
} = getErrorObject(error);
dispatch(callback(message));
};
/**
* Displays a pipeline error as a modal.
* @returns {Function}
*/
const modal = () => ({
dispatch,
error
}) => {
const {
code,
pipeline,
message,
pipelineInput,
originalMessage,
additionalParams,
translated
} = getErrorObject(error);
dispatch(showModal({
confirm: 'modal.ok',
dismiss: null,
title: null,
message,
type: MODAL_PIPELINE_ERROR,
params: {
pipeline,
request: pipelineInput,
message: originalMessage,
code,
translated,
messageParams: additionalParams
}
}));
};
/**
* Displays a pipeline error as a toast message.
* @param {number} duration An optional display duration in ms for the toast
* @returns {Function}
*/
const toast = duration => ({
events,
error
}) => {
const {
message
} = getErrorObject(error);
events.emit(ToastProvider.ADD, {
id: 'pipeline.error',
message,
duration
});
};
export default {
getErrorMessage,
toast,
modal,
custom,
dispatchAction
};