@commercetools-frontend/react-notifications
Version:
React bindings for @commercetools-frontend/notifications
807 lines (778 loc) • 45.3 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var react = require('react');
var jsxRuntime = require('@emotion/react/jsx-runtime');
var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys');
var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
var _Object$getOwnPropertyDescriptor = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor');
var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors');
var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
var _objectWithoutProperties = require('@babel/runtime-corejs3/helpers/objectWithoutProperties');
var reactIntl = require('react-intl');
var constants = require('@commercetools-frontend/constants');
var hooks = require('@commercetools-uikit/hooks');
var icons = require('@commercetools-uikit/icons');
var SecondaryIconButton = require('@commercetools-uikit/secondary-icon-button');
var utils = require('@commercetools-uikit/utils');
var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
var omitBy = require('lodash/omitBy');
var react$1 = require('@emotion/react');
var designSystem = require('@commercetools-uikit/design-system');
var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
var _valuesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/values');
var reactRedux = require('react-redux');
var notifications = require('@commercetools-frontend/notifications');
var sentry = require('@commercetools-frontend/sentry');
var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
var has = require('lodash/has');
var Spacings = require('@commercetools-uikit/spacings');
var _sliceInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/slice');
var reselect = require('reselect');
var isNumber = require('lodash/isNumber');
var actionsGlobal = require('@commercetools-frontend/actions-global');
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
var _Object$getOwnPropertyDescriptor__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptor);
var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptors);
var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
var SecondaryIconButton__default = /*#__PURE__*/_interopDefault(SecondaryIconButton);
var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
var omitBy__default = /*#__PURE__*/_interopDefault(omitBy);
var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
var _valuesInstanceProperty__default = /*#__PURE__*/_interopDefault(_valuesInstanceProperty);
var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
var has__default = /*#__PURE__*/_interopDefault(has);
var Spacings__default = /*#__PURE__*/_interopDefault(Spacings);
var _sliceInstanceProperty__default = /*#__PURE__*/_interopDefault(_sliceInstanceProperty);
var isNumber__default = /*#__PURE__*/_interopDefault(isNumber);
// NOTE: This string will be replaced on build time with the package version.
var version = "24.10.0";
const Context = /*#__PURE__*/react.createContext(() => null);
function NotificationProviderForCustomComponent(props) {
return jsxRuntime.jsx(Context.Provider, {
value: props.mapNotificationToComponent,
children: props.children
});
}
NotificationProviderForCustomComponent.displayName = 'NotificationProviderForCustomComponent';
const useCustomNotificationComponent = () => react.useContext(Context);
function filterDataAttributes(obj) {
return omitBy__default["default"](obj, (_value, key) => !_startsWithInstanceProperty__default["default"](key).call(key, 'data-'));
}
var messages = reactIntl.defineMessages({
hideNotification: {
id: 'Notification.hideNotification',
description: 'Label for button to hide notification',
defaultMessage: 'Hide notification'
}
});
const getColorByType = value => {
switch (value) {
case constants.NOTIFICATION_KINDS_SIDE.success:
return designSystem.designTokens.colorSuccess;
case constants.NOTIFICATION_KINDS_SIDE.info:
return designSystem.designTokens.colorInfo;
case constants.NOTIFICATION_KINDS_SIDE.error:
return designSystem.designTokens.colorError;
case constants.NOTIFICATION_KINDS_SIDE.warning:
return designSystem.designTokens.colorWarning60;
default:
return 'transparent';
}
};
const getBorderColor = notificationKind => {
switch (notificationKind) {
case constants.NOTIFICATION_KINDS_SIDE.success:
return designSystem.designTokens.colorSuccess85;
case constants.NOTIFICATION_KINDS_SIDE.info:
return designSystem.designTokens.colorInfo85;
case constants.NOTIFICATION_KINDS_SIDE.error:
return designSystem.designTokens.colorError85;
case constants.NOTIFICATION_KINDS_SIDE.warning:
return designSystem.designTokens.colorWarning85;
default:
return 'transparent';
}
};
const showNotificationAnimation = react$1.keyframes`
0% {
max-height: 0;
padding-top: 0;
padding-bottom: 0;
overflow: hidden;
}
100% {
max-height: 200px;
}
`;
const showNotificationSideAnimation = react$1.keyframes`
0% {
transform: translateX(50px);
}
100% {
transform: translateX(0);
}
`;
const getStylesForNotificationIcon = props => /*#__PURE__*/react$1.css("display:flex;align-items:center;justify-content:center;position:absolute;left:0;top:0;width:48px;height:100%;color:", designSystem.designTokens.colorSurface, ";border-radius:3px 0 0 3px;background:", getColorByType(props.type), ";" + ("" ), "" );
const getStylesForCloseIcon = props => /*#__PURE__*/react$1.css("display:flex;justify-content:center;& svg{width:16px;height:16px;}", props.domain !== constants.NOTIFICATION_DOMAINS.SIDE ? '& svg { fill: ' + designSystem.designTokens.colorSurface + '; }' : '', ";" + ("" ), "" );
const getStylesForContent = props => {
const fontColor = props.domain === constants.NOTIFICATION_DOMAINS.SIDE ? designSystem.designTokens.colorSolid : designSystem.designTokens.colorSurface;
return /*#__PURE__*/react$1.css("flex-basis:100%;flex-grow:1;padding:", `0 ${designSystem.designTokens.spacingM}`, ";margin:0;font-size:", props.domain === constants.NOTIFICATION_DOMAINS.SIDE ? '1rem' : 'inherit', ";color:", fontColor, ";p{color:", fontColor, ";}ul{padding:0;margin:0;list-style:none;}" + ("" ), "" );
};
const getStylesForNotification = props => {
const baseStyles = /*#__PURE__*/react$1.css("position:relative;display:flex;align-items:center;padding:", designSystem.designTokens.spacingM, ";color:", designSystem.designTokens.colorSurface, ";" + ("" ), "" );
const pageStyles = /*#__PURE__*/react$1.css(baseStyles, ";animation:", showNotificationAnimation, " 0.3s forwards;text-align:center;background-color:", props.fixed ? 'transparent' : getColorByType(props.type), ";>*+*{margin-left:", designSystem.designTokens.spacingS, ";}" + ("" ), "" );
switch (props.domain) {
case constants.NOTIFICATION_DOMAINS.GLOBAL:
return /*#__PURE__*/react$1.css(pageStyles, ";background-color:", getColorByType(props.type), ";" + ("" ), "" );
case constants.NOTIFICATION_DOMAINS.PAGE:
return pageStyles;
case constants.NOTIFICATION_DOMAINS.SIDE:
{
const sideStyles = /*#__PURE__*/react$1.css(baseStyles, ";animation:", showNotificationAnimation, " 0.3s forwards;padding:", designSystem.designTokens.spacingM, " ", designSystem.designTokens.spacingM, " ", designSystem.designTokens.spacingM, " 50px!important;text-align:left;background:", designSystem.designTokens.colorSurface, ";border:1px solid ", getBorderColor(props.type), ";box-shadow:0px 2px 5px 0px rgba(0, 0, 0, 0.15);border-radius:", designSystem.designTokens.borderRadius6, ";word-break:break-word;hyphens:auto;" + ("" ), "" );
if (props.fixed) return sideStyles;
return /*#__PURE__*/react$1.css(sideStyles, ";animation:", showNotificationSideAnimation, " 0.3s forwards;position:relative;z-index:10000;margin-top:", designSystem.designTokens.spacingL, "!important;right:", designSystem.designTokens.spacingXl, ";float:right;clear:both;max-width:50%;" + ("" ), "" );
}
default:
return /*#__PURE__*/react$1.css("" , "" );
}
};
const _excluded$2 = ["fixed"];
function ownKeys$4(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread$4(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys$4(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys$4(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
const sequentialId = utils.createSequentialId('notification-');
const NotificationIcon = props => {
if (props.type === constants.NOTIFICATION_KINDS_SIDE.error) {
return jsxRuntime.jsx(icons.ErrorIcon, {
color: props.color
});
}
if (props.type === constants.NOTIFICATION_KINDS_SIDE.info) {
return jsxRuntime.jsx(icons.InformationIcon, {
color: props.color
});
}
if (props.type === constants.NOTIFICATION_KINDS_SIDE.warning) {
return jsxRuntime.jsx(icons.WarningIcon, {
color: props.color
});
}
return jsxRuntime.jsx(icons.CheckBoldIcon, {
color: props.color
});
};
NotificationIcon.displayName = 'NotificationIcon';
const Notification = _ref => {
let _ref$fixed = _ref.fixed,
fixed = _ref$fixed === void 0 ? false : _ref$fixed,
props = _objectWithoutProperties(_ref, _excluded$2);
const intl = reactIntl.useIntl();
const id = hooks.useFieldId(undefined, sequentialId);
return jsxRuntime.jsxs("div", _objectSpread$4(_objectSpread$4({
role: "alertdialog",
"aria-describedby": id,
css: getStylesForNotification(_objectSpread$4({
fixed
}, props))
}, filterDataAttributes(props)), {}, {
children: [jsxRuntime.jsx("div", {
id: id,
css: getStylesForContent(_objectSpread$4({
fixed
}, props)),
children: props.children
}), props.onCloseClick ? jsxRuntime.jsx("div", {
css: getStylesForCloseIcon(_objectSpread$4({
fixed
}, props)),
children: jsxRuntime.jsx(SecondaryIconButton__default["default"], {
label: intl.formatMessage(messages.hideNotification),
onClick: props.onCloseClick,
icon: jsxRuntime.jsx(icons.CloseBoldIcon, {}),
size: "30"
})
}) : null, props.domain === constants.NOTIFICATION_DOMAINS.SIDE ? jsxRuntime.jsx("div", {
css: getStylesForNotificationIcon(_objectSpread$4({
fixed
}, props)),
children: jsxRuntime.jsx(NotificationIcon, {
type: props.type,
color: "surface"
})
}) : null]
}));
};
Notification.displayName = 'Notification';
var apiErrorMessages = reactIntl.defineMessages({
General: {
id: 'ApiError.General',
description: 'A general error message, usually because of internal application problems. The user should not know the details of the error.',
defaultMessage: 'Sorry, but there seems to be something wrong. Please try again. If you are seeing this message for the second time, please contact our support team.'
},
// Custom API Error messages (without a matching error.code)
OverlappingPrices: {
id: 'ApiError.OverlappingPrices',
description: '',
defaultMessage: 'Sorry, but a price with these details already exists. Please amend the price details so that they do not overlap with another price before saving.'
},
ConcurrentModificationBulkEdit: {
id: 'ApiError.ConcurrentModificationBulkEdit',
description: 'User does a bulk update but someone else has saved changes for that element',
defaultMessage: 'Sorry, but we were unable to save your changes as someone else made changes to this same source while you were editing.'
},
// API errors
ConcurrentModification: {
id: 'ApiError.ConcurrentModification',
description: 'User edits form and clicks Save but someone else has saved changes for this element while they were editing',
defaultMessage: 'Sorry, but we were unable to save your changes as someone else made changes to this same source while you were editing. Please refresh the page and re-enter your changes.'
},
DuplicateAttributeValue: {
id: 'ApiError.DuplicateAttributeValue',
description: 'User tries to enter the same attribute value for an attribute with the Unique constraint',
defaultMessage: 'This value has already been used for another variant. The "{name}" value must be unique for all variants for this product. Please enter a different value.'
},
DuplicateAttributeValues: {
id: 'ApiError.DuplicateAttributeValues',
description: 'User tries to enter existing attribute values for a combination of attributes with the CombinationUnique constraint',
defaultMessage: 'This combination has already been used for another variant. The combination of these attributes must be unique across all variants. Please enter a different version.'
},
DuplicateField: {
id: 'ApiError.DuplicateField',
description: 'The given field must be unique across the project',
defaultMessage: 'The value for the field "{field}" has already been used. Please choose another value for this field.'
},
DuplicateSlug: {
id: 'ApiError.DuplicateSlug',
description: 'User tries to create a resource with an already existing slug',
defaultMessage: '"{slugValue}" is already in use. Please enter a new slug value for this product.'
},
DuplicatePriceScope: {
id: 'ApiError.DuplicatePriceScope',
description: 'User tries to create a price with the exact same values as for an already existing price',
defaultMessage: 'A price with the same scope already exists for this product variant. Make sure that the combination of currency, country, customer group, channel, valid dates and recurrence policy is unique per price.'
},
DuplicateStandalonePriceScope: {
id: 'ApiError.DuplicateStandalonePriceScope',
description: 'User tries to create a standalone price with the exact same values as for an already existing standalone price',
defaultMessage: 'A price with the same scope already exists for this product variant. The combination of currency, country, customer group, channel, validity date and recurrence policy must be unique for each price per SKU.'
},
DuplicateVariantValues: {
id: 'ApiError.DuplicateVariantValues',
description: 'User tries to generate a variant with the same SKU or attribute values',
defaultMessage: 'The same variant already exists for this product. Please enter different values for the fields.'
},
InvalidDateRange: {
id: 'ApiError.InvalidDateRange',
description: 'User tries to input an invalid date range',
defaultMessage: 'The value entered for the field {field} is invalid. The start date must be before the end date'
},
InvalidField: {
id: 'ApiError.InvalidField',
description: 'User enters an invalid value for a field.',
defaultMessage: 'The value entered is not valid for the field "{field}".'
},
InvalidSlug: {
id: 'ApiError.InvalidSlug',
description: 'User enters an invalid value for the product slug',
defaultMessage: 'Slugs may only contain alphanumeric (0-9A-Z) characters, underscores and hyphens and must have a length between 2 and 256 characters.'
},
OverlappingPriceValidity: {
id: 'ApiError.OverlappingPriceValidity',
description: 'Returned when a given price validity period conflicts with an existing one',
defaultMessage: 'Another price with overlapping validity dates exists. Each price combination needs to have unique validity dates.'
},
OverlappingStandalonePriceValidity: {
id: 'ApiError.OverlappingStandalonePriceValidity',
description: 'Returned when a given standalone price validity period conflicts with an existing one',
defaultMessage: 'Another price with overlapping validity dates exists. Each price combination needs to have unique validity dates.'
},
PendingOperation: {
id: 'ApiError.PendingOperation',
description: 'User tries to start a new process when one is already underway',
defaultMessage: 'Sorry, but we are still processing the previous request. Please try again once it is complete.'
},
ResourceNotFound: {
id: 'ApiError.ResourceNotFound',
description: 'System cannot find the functionality or screen that the user is trying to access.',
defaultMessage: 'Sorry, but we cannot find what you are looking for.'
},
ReferenceExists: {
id: 'ApiError.ReferenceExists',
description: 'User tries to delete an element that has an existing reference to it from another element',
defaultMessage: 'Can not delete a source while it is referenced from at least one "{referencedBy}".'
},
RequiredField: {
id: 'ApiError.RequiredField',
description: 'User does not enter a required field',
defaultMessage: '"{field}" is a required field. Please enter a value.'
},
RequiredFields: {
// Client side validation
id: 'ApiError.RequiredFields',
description: 'User submits a form without having completed all mandatory fields',
defaultMessage: 'Please enter values for the following required fields: {fields}'
},
SemanticError: {
id: 'ApiError.SemanticError',
description: 'User enters a predicate query that throws a system semantic error',
defaultMessage: 'Semantic error: the given Predicate is not valid. Please read the documentation to define a correct predicate.'
},
SyntaxError: {
id: 'ApiError.SyntaxError',
description: 'User enters a predicate query that throws a system syntax error',
defaultMessage: 'Syntax error: the given Predicate is not valid. Please read the documentation to define a correct predicate.'
},
Unauthorized: {
id: 'ApiError.Unauthorized',
description: 'The access token is not valid anymore, or the user does not have a valid one',
defaultMessage: 'Sorry, but you are not authorized to access this feature.'
},
Forbidden: {
id: 'ApiError.Forbidden',
description: 'User tries to access a view that they do not have permission for',
defaultMessage: 'You are not authorized to access this feature. Please contact your system administrator with any further questions.'
},
ExtensionNoResponse: {
id: 'ApiError.ExtensionNoResponse',
description: 'User tries to access a view that they do not have permission for',
defaultMessage: 'Sorry, we could not perform the requested action due to an API extension not responding.'
},
ExtensionBadResponse: {
id: 'ApiError.ExtensionBadResponse',
description: 'User tries to access a view that they do not have permission for',
defaultMessage: 'Sorry, we could not perform the requested action due to failed processing of an API extension response.'
},
ExtensionUpdateActionsFailed: {
id: 'ApiError.ExtensionUpdateActionsFailed',
description: 'User tries to access a view that they do not have permission for',
defaultMessage: 'Sorry, we could not perform the requested action. It is not possible to perform the update actions as instructed by the API extension.'
},
TaxCategoryDuplicateCountry: {
id: 'ApiError.TaxCategoryDuplicateCountry',
description: 'User inputs duplicate country and/or state into tax category form',
defaultMessage: 'Duplicate tax rates submitted. Please remove the duplicates.'
},
MaxResourceLimitExceeded: {
id: 'ApiError.MaxResourceLimitExceeded',
description: 'User attempts to create a resource while having already reached the limit',
defaultMessage: 'The project reached the limit for the resource. To add more resources delete existing ones or reach out to the administrator or contact customer support.'
}
});
function ownKeys$3(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread$3(e) { for (var r = 1; r < arguments.length; r++) { var _context6, _context7; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context6 = ownKeys$3(Object(t), !0)).call(_context6, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context7 = ownKeys$3(Object(t))).call(_context7, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
const regexInvalidOperationRequiredAttribute = /^Required attribute '(.*)' cannot be removed/;
// `error` fields for REST errors
// `error.extensions` fields for GraphQL errors
// The values passed to the Intl message must be a map of scalar values.
// Some of the message values are already mapped in the `getSpecialFormattedMessageByErrorCode`
// function. Here we map other possible error properties that can be
// used in the message.
const mapErrorFieldsToMessageValues = error => {
const errorField = error.extensions?.field || error.field;
if (errorField) {
return {
field: errorField
};
}
const errorReferencedBy = error.extensions?.referencedBy || error.referencedBy;
if (errorReferencedBy) {
return {
referencedBy: errorReferencedBy
};
}
return {};
};
// Type-guard validation for error code to be included in the message object keys.
const hasErrorCodeAMatchingMessage = errorCode => errorCode in apiErrorMessages;
const FormattedErrorMessage = props => {
var _context2;
const intl = reactIntl.useIntl();
// Attempt to map the error by code
const extensionErrorCode = props.error.extensions?.code ?? props.error.code;
const messageCode = extensionErrorCode && hasErrorCodeAMatchingMessage(extensionErrorCode) ? apiErrorMessages[extensionErrorCode] : undefined;
react.useEffect(() => {
if (!messageCode) {
var _context;
// This error is not mapped / translated yet,
// we log, report it to sentry and show the original error, unless `error.code` is `invalid_scope`
// which an error code emitted for expired project(s)
if (extensionErrorCode !== 'invalid_scope' && !_includesInstanceProperty__default["default"](_context = props.error.message).call(_context, 'has expired')) {
sentry.reportErrorToSentry(new Error('Unmapped error'), {
extra: props.error
});
}
}
}, [extensionErrorCode, messageCode, props.error]);
if (messageCode) {
// The `error` object might contain extra fields for the specific `code`.
return jsxRuntime.jsx(jsxRuntime.Fragment, {
children: intl.formatMessage(messageCode, mapErrorFieldsToMessageValues(props.error))
});
}
return jsxRuntime.jsx(jsxRuntime.Fragment, {
children: _filterInstanceProperty__default["default"](_context2 = [props.error.message, props.error.detailedErrorMessage && `(${props.error.detailedErrorMessage})`]).call(_context2, Boolean).join(' ')
});
};
FormattedErrorMessage.displayName = 'FormattedErrorMessage';
const ApiErrorMessage = props => {
const intl = reactIntl.useIntl();
// Attempt to map the error to a specific error message
const specialFormattedMessage = getSpecialFormattedMessageByErrorCode(props.error, intl);
if (specialFormattedMessage) {
return jsxRuntime.jsx(jsxRuntime.Fragment, {
children: specialFormattedMessage
});
}
return jsxRuntime.jsx(FormattedErrorMessage, _objectSpread$3({}, props));
};
ApiErrorMessage.displayName = 'ApiErrorMessage';
function getSpecialFormattedMessageByErrorCode(error, intl) {
var _context3, _context4, _context5;
const extensionErrorCode = error.extensions?.code ?? error.code;
if (error.errorByExtension) {
let extensionMessage;
if (error.localizedMessage) {
extensionMessage = error.localizedMessage[intl.locale];
}
return extensionMessage || error.message;
}
if (!extensionErrorCode || extensionErrorCode === 'InvalidInput') return intl.formatMessage(apiErrorMessages.General);
// TODO: this is a temporary solution until we have proper pages about 403
if (extensionErrorCode === 'insufficient_scope') return intl.formatMessage(apiErrorMessages.Forbidden);
if (extensionErrorCode === 'DuplicateField') {
const errorField = error.extensions?.field || error.field;
const errorDuplicateValue = error.extensions?.duplicateValue || error.duplicateValue;
if (errorField === 'slug') {
return intl.formatMessage(apiErrorMessages.DuplicateSlug, {
slugValue: errorDuplicateValue
});
} else {
return intl.formatMessage(apiErrorMessages.DuplicateField, {
field: errorField
});
}
}
// Try to match the error with a custom error message
if (has__default["default"](error, 'invalidValue') && has__default["default"](error.invalidValue, 'overlappingPrices')) return intl.formatMessage(apiErrorMessages.OverlappingPrices);
if (extensionErrorCode === 'InvalidOperation' && _includesInstanceProperty__default["default"](_context3 = error.message).call(_context3, 'validFrom') && _includesInstanceProperty__default["default"](_context4 = error.message).call(_context4, 'validUntil')) {
return intl.formatMessage(apiErrorMessages.InvalidDateRange, {
field: 'validFrom'
});
}
if (extensionErrorCode === 'InvalidOperation' && _includesInstanceProperty__default["default"](_context5 = error.message).call(_context5, 'Duplicate tax rate for')) {
return intl.formatMessage(apiErrorMessages.TaxCategoryDuplicateCountry);
}
if (extensionErrorCode === 'InvalidOperation' && regexInvalidOperationRequiredAttribute.test(error.message)) {
const attrName = error.message.replace(regexInvalidOperationRequiredAttribute, '$1');
return intl.formatMessage(apiErrorMessages.RequiredField, {
field: attrName
});
}
// TODO: A concern has be raised that we can't accurately distinguish
// this error (invalid start / end dates with prices) from other price
// errors. We should investigate this further.
if (extensionErrorCode === 'InvalidField' && error.field === 'price' && has__default["default"](error, 'invalidValue') && has__default["default"](error.invalidValue, 'validFrom') && has__default["default"](error.invalidValue, 'validUntil')) return intl.formatMessage(apiErrorMessages.InvalidDateRange, {
field: error.field
});
if (extensionErrorCode === 'DuplicateAttributeValue' && error.attribute) {
return intl.formatMessage(apiErrorMessages.DuplicateAttributeValue, {
name: error.attribute.name
});
}
if (extensionErrorCode === 'MaxResourceLimitExceeded') {
return intl.formatMessage(apiErrorMessages.MaxResourceLimitExceeded);
}
return;
}
const ApiErrorNotification = props => {
var _context;
return jsxRuntime.jsx(Notification, {
type: "error",
domain: props.notification.domain,
onCloseClick: props.dismiss,
children: jsxRuntime.jsx("ul", {
children: _valuesInstanceProperty__default["default"](props.notification) && _mapInstanceProperty__default["default"](_context = _valuesInstanceProperty__default["default"](props.notification).errors).call(_context, (error, idx) => {
const extensionErrorCode = error.extensions?.code ?? error.code;
const shouldLogErrorToConsole = !extensionErrorCode && "production" === 'development';
if (shouldLogErrorToConsole) {
/**
* NOTE: This is an API error which usually contains
* a `code` property such as `DuplicateField` or `InvalidOperation`.
* If this `code` does not exist the API is not conforming to its
* own error specification.
*/
// eslint-disable-next-line no-console
console.error('Unknown API error', error);
}
return jsxRuntime.jsx("li", {
children: jsxRuntime.jsx(ApiErrorMessage, {
error: error
})
}, idx);
})
})
});
};
ApiErrorNotification.displayName = 'ApiErrorNotification';
const GenericNotification = props => jsxRuntime.jsx(Notification, {
domain: props.notification.domain,
type: props.notification.kind,
onCloseClick: props.dismiss,
children: props.notification.text
});
GenericNotification.displayName = 'GenericNotification';
function ownKeys$2(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread$2(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys$2(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys$2(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
const UnexpectedErrorNotification = props => jsxRuntime.jsx(Notification, {
type: "error",
domain: props.notification.domain,
onCloseClick: props.dismiss,
children: jsxRuntime.jsxs(Spacings__default["default"].Stack, {
children: [jsxRuntime.jsx("div", {
children: jsxRuntime.jsx(reactIntl.FormattedMessage, _objectSpread$2({}, apiErrorMessages.General))
}), _valuesInstanceProperty__default["default"](props.notification) && _valuesInstanceProperty__default["default"](props.notification).errorId && jsxRuntime.jsx("div", {
children: `ID (${_valuesInstanceProperty__default["default"](props.notification).errorId})`
})]
})
});
UnexpectedErrorNotification.displayName = 'UnexpectedErrorNotification';
const getStyles = props => {
const baseStyles = /*#__PURE__*/react$1.css("color:", designSystem.customProperties.colorSurface, ";position:relative;width:100%;z-index:19999;" + ("" ), "" );
switch (props.domain) {
case constants.NOTIFICATION_DOMAINS.GLOBAL:
return /*#__PURE__*/react$1.css(baseStyles, ";text-align:center;width:100%!important;" + ("" ), "" );
case constants.NOTIFICATION_DOMAINS.PAGE:
return /*#__PURE__*/react$1.css(baseStyles, ";" + ("" ), "" );
case constants.NOTIFICATION_DOMAINS.SIDE:
return /*#__PURE__*/react$1.css(baseStyles, ";position:absolute;text-align:left;height:0;overflow:visible;" + ("" ), "" );
default:
return /*#__PURE__*/react$1.css("" , "" );
}
};
// These selectors are okay memoization-wise, but once a single notifications
// is added or removed the memoization for all domain selectors is reset
const selectNotifications = state => state.notifications;
const selectGlobalNotifications = reselect.createSelector(selectNotifications, notifications => {
var _context;
return _sliceInstanceProperty__default["default"](_context = _filterInstanceProperty__default["default"](notifications).call(notifications, notification => notification.domain === constants.NOTIFICATION_DOMAINS.GLOBAL)
// Return only 1 at a time
).call(_context, 0, 1);
});
const selectPageNotifications = reselect.createSelector(selectNotifications, notifications => _filterInstanceProperty__default["default"](notifications).call(notifications, notification => notification.domain === constants.NOTIFICATION_DOMAINS.PAGE));
const selectSideNotifications = reselect.createSelector(selectNotifications, notifications => _filterInstanceProperty__default["default"](notifications).call(notifications, notification => notification.domain === constants.NOTIFICATION_DOMAINS.SIDE));
const _excluded$1 = ["values"],
_excluded2 = ["text"],
_excluded3 = ["values"],
_excluded4 = ["text"],
_excluded5 = ["text"];
function ownKeys$1(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys$1(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys$1(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
const NotificationsListGlobal = props => {
const dispatch = reactRedux.useDispatch();
const mapCustomNotificationToComponent = useCustomNotificationComponent();
const notifications$1 = reactRedux.useSelector(selectGlobalNotifications);
return jsxRuntime.jsx("div", {
id: `notifications-${props.domain}`,
css: getStyles(props),
children: _mapInstanceProperty__default["default"](notifications$1).call(notifications$1, notification => {
// 1. Check if there is a custom notification component first
const CustomNotificationComponent = mapCustomNotificationToComponent(notification);
if (CustomNotificationComponent) {
return jsxRuntime.jsx(CustomNotificationComponent, {
notification: notification,
dismiss: () => {
dispatch(notifications.removeNotification(notification.id));
}
}, notification.id);
}
switch (notification.kind) {
case constants.NOTIFICATION_KINDS_GLOBAL.error:
case constants.NOTIFICATION_KINDS_GLOBAL.warning:
case constants.NOTIFICATION_KINDS_GLOBAL.info:
case constants.NOTIFICATION_KINDS_GLOBAL.success:
{
_valuesInstanceProperty__default["default"](notification);
const genericNotification = _objectWithoutProperties(notification, _excluded$1);
return jsxRuntime.jsx(GenericNotification, {
notification: genericNotification,
dismiss: () => {
dispatch(notifications.removeNotification(notification.id));
}
}, notification.id);
}
case constants.NOTIFICATION_KINDS_GLOBAL['unexpected-error']:
{
notification.text;
const errorNotification = _objectWithoutProperties(notification, _excluded2);
return jsxRuntime.jsx(UnexpectedErrorNotification, {
notification: errorNotification,
dismiss: () => {
dispatch(notifications.removeNotification(notification.id));
}
}, notification.id);
}
default:
{
return null;
}
}
})
});
};
const NotificationsListPage = props => {
const dispatch = reactRedux.useDispatch();
const mapCustomNotificationToComponent = useCustomNotificationComponent();
const notifications$1 = reactRedux.useSelector(selectPageNotifications);
return jsxRuntime.jsx("div", {
id: `notifications-${props.domain}`,
css: getStyles(props),
children: _mapInstanceProperty__default["default"](notifications$1).call(notifications$1, notification => {
// 1. Check if there is a custom notification component first
const CustomNotificationComponent = mapCustomNotificationToComponent(notification);
if (CustomNotificationComponent) {
return jsxRuntime.jsx(CustomNotificationComponent, {
notification: notification,
dismiss: () => {
dispatch(notifications.removeNotification(notification.id));
}
}, notification.id);
}
switch (notification.kind) {
case constants.NOTIFICATION_KINDS_PAGE.error:
case constants.NOTIFICATION_KINDS_PAGE.warning:
case constants.NOTIFICATION_KINDS_PAGE.info:
case constants.NOTIFICATION_KINDS_PAGE.success:
{
_valuesInstanceProperty__default["default"](notification);
const genericNotification = _objectWithoutProperties(notification, _excluded3);
return jsxRuntime.jsx(GenericNotification, {
notification: _objectSpread$1(_objectSpread$1({}, genericNotification), {}, {
kind: notification.kind
}),
dismiss: () => {
dispatch(notifications.removeNotification(notification.id));
}
}, notification.id);
}
case constants.NOTIFICATION_KINDS_PAGE['api-error']:
{
notification.text;
const errorNotification = _objectWithoutProperties(notification, _excluded4);
return jsxRuntime.jsx(ApiErrorNotification, {
notification: errorNotification,
dismiss: () => {
dispatch(notifications.removeNotification(notification.id));
}
}, notification.id);
}
case constants.NOTIFICATION_KINDS_PAGE['unexpected-error']:
{
notification.text;
const errorNotification = _objectWithoutProperties(notification, _excluded5);
return jsxRuntime.jsx(UnexpectedErrorNotification, {
notification: _objectSpread$1(_objectSpread$1({}, errorNotification), {}, {
values: _valuesInstanceProperty__default["default"](notification)
}),
dismiss: () => {
dispatch(notifications.removeNotification(notification.id));
}
}, notification.id);
}
default:
return null;
}
})
});
};
const NotificationsListSide = props => {
const dispatch = reactRedux.useDispatch();
const mapCustomNotificationToComponent = useCustomNotificationComponent();
const notifications$1 = reactRedux.useSelector(selectSideNotifications);
return jsxRuntime.jsx("div", {
id: `notifications-${props.domain}`,
css: getStyles(props),
children: _mapInstanceProperty__default["default"](notifications$1).call(notifications$1, notification => {
// 1. Check if there is a custom notification component first
const CustomNotificationComponent = mapCustomNotificationToComponent(notification);
if (CustomNotificationComponent) {
return jsxRuntime.jsx(CustomNotificationComponent, {
notification: notification,
dismiss: () => {
dispatch(notifications.removeNotification(notification.id));
}
}, notification.id);
}
switch (notification.kind) {
case constants.NOTIFICATION_KINDS_SIDE.error:
case constants.NOTIFICATION_KINDS_SIDE.warning:
case constants.NOTIFICATION_KINDS_SIDE.info:
case constants.NOTIFICATION_KINDS_SIDE.success:
return jsxRuntime.jsx(GenericNotification, {
notification: notification,
dismiss: () => {
dispatch(notifications.removeNotification(notification.id));
}
}, notification.id);
default:
return null;
}
})
});
};
const NotificationsList = props => {
switch (props.domain) {
case constants.NOTIFICATION_DOMAINS.GLOBAL:
return jsxRuntime.jsx(NotificationsListGlobal, _objectSpread$1({}, props));
case constants.NOTIFICATION_DOMAINS.PAGE:
return jsxRuntime.jsx(NotificationsListPage, _objectSpread$1({}, props));
case constants.NOTIFICATION_DOMAINS.SIDE:
return jsxRuntime.jsx(NotificationsListSide, _objectSpread$1({}, props));
default:
return null;
}
};
NotificationsList.displayName = 'NotificationsList';
const _excluded = ["domain", "kind"];
function ownKeys(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
const Notifier = _ref => {
let _ref$domain = _ref.domain,
domain = _ref$domain === void 0 ? constants.NOTIFICATION_DOMAINS.SIDE : _ref$domain,
_ref$kind = _ref.kind,
kind = _ref$kind === void 0 ? constants.NOTIFICATION_KINDS_SIDE.success : _ref$kind,
props = _objectWithoutProperties(_ref, _excluded);
const showNotification = actionsGlobal.useShowNotification();
react.useEffect(() => {
const notification = showNotification({
domain: domain,
kind: kind,
text: props.text
}, isNumber__default["default"](props.dismissAfter) ? _objectSpread(_objectSpread({}, props.meta), {}, {
dismissAfter: props.dismissAfter
}) : props.meta);
return () => {
// Remove notification when component "unmounts"
notification.dismiss && notification.dismiss();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // We want to run this only once, when the component mounts the first time. Therefore we need to pass an empty array, even though the eslint rule shows a warning.
return null;
};
Notifier.displayName = 'Notifier';
exports.ApiErrorMessage = ApiErrorMessage;
exports.Notification = Notification;
exports.NotificationProviderForCustomComponent = NotificationProviderForCustomComponent;
exports.NotificationsList = NotificationsList;
exports.Notifier = Notifier;
exports.selectGlobalNotifications = selectGlobalNotifications;
exports.selectPageNotifications = selectPageNotifications;
exports.selectSideNotifications = selectSideNotifications;
exports.version = version;