@commercetools-frontend/react-notifications
Version:
React bindings for @commercetools-frontend/notifications
826 lines (797 loc) • 45.9 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var _pt = require('prop-types');
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 _pt__default = /*#__PURE__*/_interopDefault(_pt);
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 = "23.2.2";
const Context = /*#__PURE__*/react.createContext(() => null);
function NotificationProviderForCustomComponent(props) {
return jsxRuntime.jsx(Context.Provider, {
value: props.mapNotificationToComponent,
children: props.children
});
}
NotificationProviderForCustomComponent.propTypes = {};
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.propTypes = {};
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.propTypes = {};
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 and valid dates 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 and validity date 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.propTypes = {
error: _pt__default["default"].any.isRequired
};
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.propTypes = {};
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.propTypes = {};
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.propTypes = {};
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.propTypes = {};
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.propTypes = {
domain: _pt__default["default"].any.isRequired,
kind: _pt__default["default"].any.isRequired,
text: _pt__default["default"].string,
meta: _pt__default["default"].objectOf(_pt__default["default"].any),
dismissAfter: _pt__default["default"].number
};
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;