@shopgate/pwa-ui-shared 7.30.0-alpha.6 → 7.30.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AccordionContainer/index.js +39 -5
- package/AccordionContainer/spec.js +25 -2
- package/ActionButton/index.js +63 -7
- package/ActionButton/spec.js +59 -2
- package/ActionButton/style.js +22 -1
- package/AddToCartButton/index.js +184 -27
- package/AddToCartButton/mock.js +18 -4
- package/AddToCartButton/spec.js +51 -2
- package/AddToCartButton/style.js +127 -11
- package/Availability/index.js +34 -2
- package/Availability/spec.js +41 -1
- package/Availability/style.js +19 -1
- package/Button/index.js +76 -5
- package/Button/spec.js +33 -1
- package/Button/style.js +130 -21
- package/ButtonLink/connector.js +11 -2
- package/ButtonLink/index.js +44 -6
- package/ButtonLink/spec.js +23 -1
- package/Card/index.js +19 -2
- package/Card/style.js +11 -1
- package/CardList/components/Item/index.js +26 -2
- package/CardList/components/Item/style.js +7 -1
- package/CardList/index.js +34 -3
- package/CartTotalLine/components/Amount/index.js +28 -2
- package/CartTotalLine/components/Amount/style.js +8 -1
- package/CartTotalLine/components/Hint/index.js +23 -2
- package/CartTotalLine/components/Hint/style.js +12 -1
- package/CartTotalLine/components/Label/index.js +36 -2
- package/CartTotalLine/components/Label/style.js +17 -1
- package/CartTotalLine/components/Spacer/index.js +16 -2
- package/CartTotalLine/index.js +39 -2
- package/CartTotalLine/style.js +31 -1
- package/Checkbox/index.js +31 -2
- package/Checkbox/style.js +18 -1
- package/Chip/index.js +61 -2
- package/Chip/spec.js +24 -1
- package/Chip/style.js +71 -3
- package/ContextMenu/ContextMenu.hooks.js +6 -2
- package/ContextMenu/ContextMenuProvider.context.js +9 -3
- package/ContextMenu/ContextMenuProvider.js +21 -2
- package/ContextMenu/components/Item/index.js +67 -5
- package/ContextMenu/components/Item/style.js +32 -3
- package/ContextMenu/components/Position/index.js +61 -10
- package/ContextMenu/components/Position/style.js +11 -1
- package/ContextMenu/index.js +124 -3
- package/ContextMenu/spec.js +101 -2
- package/ContextMenu/style.js +45 -1
- package/Dialog/components/BasicDialog/index.js +5 -1
- package/Dialog/components/HtmlContentDialog/index.js +22 -2
- package/Dialog/components/HtmlContentDialog/spec.js +59 -1
- package/Dialog/components/PipelineErrorDialog/index.js +114 -25
- package/Dialog/components/PipelineErrorDialog/spec.js +92 -12
- package/Dialog/components/TextMessageDialog/index.js +28 -2
- package/Dialog/components/TextMessageDialog/spec.js +59 -1
- package/Dialog/components/VariantSelectModal/connector.js +11 -2
- package/Dialog/components/VariantSelectModal/index.js +65 -6
- package/Dialog/components/VariantSelectModal/spec.js +51 -2
- package/Dialog/constants.js +6 -1
- package/Dialog/index.js +114 -7
- package/Dialog/spec.js +81 -3
- package/DiscountBadge/index.js +30 -2
- package/DiscountBadge/spec.js +19 -1
- package/DiscountBadge/style.js +34 -2
- package/FavoritesButton/connector.js +18 -3
- package/FavoritesButton/index.js +118 -15
- package/FavoritesButton/mock.js +50 -4
- package/FavoritesButton/spec.js +120 -2
- package/FavoritesButton/style.js +26 -1
- package/Form/Builder/builders/buildCountryList.js +40 -6
- package/Form/Builder/builders/buildFormDefaults.js +35 -6
- package/Form/Builder/builders/buildFormElements.js +68 -10
- package/Form/Builder/builders/buildProvinceList.js +19 -2
- package/Form/Builder/builders/buildValidationErrorList.js +7 -2
- package/Form/Builder/classes/ActionListener/constants.js +22 -2
- package/Form/Builder/classes/ActionListener/index.js +441 -93
- package/Form/Builder/classes/ActionListener/spec.js +321 -19
- package/Form/Builder/components/CheckboxElement.js +35 -3
- package/Form/Builder/components/CountryElement.js +40 -3
- package/Form/Builder/components/ProvinceElement.js +40 -3
- package/Form/Builder/components/RadioElement.js +41 -3
- package/Form/Builder/components/SelectElement.js +39 -3
- package/Form/Builder/components/TextElement.js +49 -4
- package/Form/Builder/elementTypes.js +11 -1
- package/Form/Builder/index.js +298 -52
- package/Form/Builder/iso-3166-2.js +4943 -1
- package/Form/Builder/spec.js +300 -16
- package/Form/Checkbox/index.js +66 -4
- package/Form/Checkbox/style.js +25 -2
- package/Form/InfoField/index.js +50 -2
- package/Form/InfoField/spec.js +9 -1
- package/Form/InfoField/style.js +11 -1
- package/Form/Password/index.js +51 -6
- package/Form/Password/spec.js +34 -1
- package/Form/Password/style.js +11 -1
- package/Form/RadioGroup/components/Item/index.js +59 -3
- package/Form/RadioGroup/components/Item/style.js +32 -2
- package/Form/RadioGroup/index.js +101 -9
- package/Form/RadioGroup/spec.js +83 -3
- package/Form/RadioGroup/style.js +18 -2
- package/Form/Select/index.js +158 -10
- package/Form/Select/spec.js +36 -5
- package/Form/Select/style.js +27 -1
- package/Form/SelectContextChoices/index.js +77 -3
- package/Form/SelectContextChoices/spec.js +33 -4
- package/Form/SelectContextChoices/style.js +23 -1
- package/Form/TextField/index.js +92 -8
- package/Form/TextField/spec.js +110 -1
- package/Form/TextField/style.js +66 -8
- package/Form/index.js +54 -13
- package/FormElement/components/ErrorText/index.js +31 -2
- package/FormElement/components/ErrorText/style.js +13 -1
- package/FormElement/components/Label/index.js +35 -2
- package/FormElement/components/Label/style.js +76 -8
- package/FormElement/components/Placeholder/index.js +26 -2
- package/FormElement/components/Placeholder/style.js +48 -6
- package/FormElement/components/Underline/index.js +18 -2
- package/FormElement/components/Underline/style.js +51 -4
- package/FormElement/index.js +91 -6
- package/FormElement/spec.js +67 -2
- package/FormElement/style.js +13 -2
- package/Glow/index.js +90 -7
- package/Glow/spec.js +9 -1
- package/Glow/style.js +18 -1
- package/IndicatorCircle/index.js +33 -3
- package/IndicatorCircle/spec.js +28 -1
- package/IndicatorCircle/style.js +57 -3
- package/LoadingIndicator/index.js +29 -2
- package/LoadingIndicator/style.js +20 -1
- package/Manufacturer/index.js +20 -2
- package/Manufacturer/style.js +5 -1
- package/MessageBar/index.js +36 -2
- package/MessageBar/spec.js +79 -1
- package/MessageBar/style.js +38 -1
- package/NoResults/components/Icon/index.js +130 -2
- package/NoResults/components/Icon/style.js +17 -1
- package/NoResults/index.js +46 -2
- package/NoResults/style.js +31 -1
- package/Placeholder/index.js +25 -3
- package/Placeholder/style.js +11 -1
- package/PlaceholderLabel/index.js +27 -2
- package/PlaceholderLabel/spec.js +19 -1
- package/PlaceholderLabel/style.js +12 -1
- package/PlaceholderParagraph/index.js +36 -2
- package/PlaceholderParagraph/spec.js +19 -1
- package/Price/index.js +88 -7
- package/Price/style.js +22 -1
- package/PriceInfo/index.js +20 -2
- package/PriceInfo/style.js +5 -1
- package/PriceStriked/index.js +83 -12
- package/PriceStriked/style.js +33 -3
- package/ProductProperties/index.js +32 -2
- package/ProgressBar/index.js +101 -13
- package/ProgressBar/spec.js +13 -1
- package/ProgressBar/style.js +83 -2
- package/RadioButton/index.js +18 -2
- package/RadioButton/spec.js +21 -1
- package/RadioButton/style.js +21 -1
- package/RatingNumber/index.js +29 -2
- package/RatingStars/constants.js +2 -1
- package/RatingStars/index.js +130 -12
- package/RatingStars/spec.js +90 -3
- package/RatingStars/style.js +51 -2
- package/Ripple/components/RippleAnimation/index.js +88 -6
- package/Ripple/index.js +218 -40
- package/Ripple/style.js +18 -1
- package/RippleButton/index.js +52 -5
- package/RippleButton/spec.js +45 -1
- package/ScannerOverlay/components/CameraOverlay/index.js +13 -2
- package/ScannerOverlay/components/CameraOverlay/style.js +41 -1
- package/ScannerOverlay/components/ScannerBar/components/FlashlightButton/index.js +34 -2
- package/ScannerOverlay/components/ScannerBar/components/FlashlightButton/style.js +28 -1
- package/ScannerOverlay/components/ScannerBar/components/ScannerInstructions/index.js +11 -2
- package/ScannerOverlay/components/ScannerBar/index.js +31 -2
- package/ScannerOverlay/components/ScannerBar/style.js +20 -1
- package/ScannerOverlay/index.js +47 -7
- package/Sheet/components/Header/components/SearchBar/index.js +46 -2
- package/Sheet/components/Header/components/SearchBar/spec.js +21 -3
- package/Sheet/components/Header/components/SearchBar/style.js +47 -1
- package/Sheet/components/Header/index.js +75 -7
- package/Sheet/components/Header/spec.js +14 -1
- package/Sheet/components/Header/style.js +50 -1
- package/Sheet/index.js +170 -17
- package/Sheet/spec.js +85 -5
- package/Sheet/style.js +143 -2
- package/TaxDisclaimer/index.js +34 -4
- package/TaxDisclaimer/spec.js +31 -3
- package/TaxDisclaimer/style.js +9 -1
- package/TextField/components/ErrorText/index.js +33 -2
- package/TextField/components/ErrorText/style.js +25 -3
- package/TextField/components/FormElement/index.js +19 -2
- package/TextField/components/FormElement/style.js +32 -4
- package/TextField/components/Hint/index.js +21 -2
- package/TextField/components/Hint/style.js +40 -5
- package/TextField/components/Label/index.js +32 -3
- package/TextField/components/Label/style.js +68 -8
- package/TextField/components/Underline/index.js +19 -2
- package/TextField/components/Underline/style.js +51 -4
- package/TextField/index.js +189 -27
- package/TextField/spec.js +128 -3
- package/TextField/style.js +34 -4
- package/ToggleIcon/index.js +58 -8
- package/ToggleIcon/spec.js +35 -1
- package/icons/AccountBoxIcon.js +11 -2
- package/icons/AddMoreIcon.js +11 -2
- package/icons/ArrowDropIcon.js +11 -2
- package/icons/ArrowIcon.js +21 -2
- package/icons/BarcodeScannerIcon.js +11 -2
- package/icons/BoxIcon.js +11 -2
- package/icons/BrowseIcon.js +11 -2
- package/icons/BurgerIcon.js +11 -2
- package/icons/CalendarIcon.js +15 -3
- package/icons/CartCouponIcon.js +72 -2
- package/icons/CartIcon.js +11 -2
- package/icons/CartPlusIcon.js +11 -2
- package/icons/CheckIcon.js +11 -2
- package/icons/CheckedIcon.js +11 -2
- package/icons/ChevronIcon.js +11 -2
- package/icons/CreditCardIcon.js +11 -2
- package/icons/CrossIcon.js +11 -2
- package/icons/DescriptionIcon.js +11 -2
- package/icons/FilterIcon.js +11 -2
- package/icons/FlashDisabledIcon.js +11 -2
- package/icons/FlashEnabledIcon.js +11 -2
- package/icons/GridIcon.js +11 -2
- package/icons/HeartIcon.js +11 -2
- package/icons/HeartOutlineIcon.js +11 -2
- package/icons/HeartPlusIcon.js +12 -2
- package/icons/HeartPlusOutlineIcon.js +12 -2
- package/icons/HomeIcon.js +11 -2
- package/icons/InfoIcon.js +11 -2
- package/icons/InfoOutlineIcon.js +11 -2
- package/icons/ListIcon.js +11 -2
- package/icons/LocalShippingIcon.js +11 -2
- package/icons/LocationIcon.js +13 -3
- package/icons/LocatorIcon.js +11 -2
- package/icons/LockIcon.js +11 -2
- package/icons/LogoutIcon.js +11 -2
- package/icons/MagnifierIcon.js +11 -2
- package/icons/MapMarkerIcon.js +24 -3
- package/icons/MoreIcon.js +11 -2
- package/icons/MoreVertIcon.js +11 -2
- package/icons/NotificationIcon.js +14 -3
- package/icons/PersonIcon.js +12 -2
- package/icons/PhoneIcon.js +13 -3
- package/icons/PlaceholderIcon.js +11 -2
- package/icons/RadioCheckedIcon.js +11 -2
- package/icons/RadioUncheckedIcon.js +11 -2
- package/icons/SecurityIcon.js +11 -2
- package/icons/ShippingMethodIcon.js +18 -3
- package/icons/ShoppingCartIcon.js +11 -2
- package/icons/SortIcon.js +11 -2
- package/icons/StarHalfIcon.js +18 -2
- package/icons/StarIcon.js +18 -2
- package/icons/StarOutlineIcon.js +11 -2
- package/icons/StopIcon.js +11 -2
- package/icons/TickIcon.js +11 -2
- package/icons/TimeIcon.js +14 -3
- package/icons/TrashIcon.js +11 -2
- package/icons/TrashOutlineIcon.js +12 -2
- package/icons/UncheckedIcon.js +11 -2
- package/icons/ViewListIcon.js +11 -2
- package/icons/VisibilityIcon.js +11 -2
- package/icons/VisibilityOffIcon.js +11 -2
- package/icons/WarningIcon.js +11 -2
- package/index.js +13 -1
- package/package.json +5 -5
|
@@ -1,3 +1,52 @@
|
|
|
1
|
-
import React from'react';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { shallow } from 'enzyme';
|
|
3
|
+
import { UnwrappedVariantSelectModal as VariantSelectModal } from "./index";
|
|
4
|
+
const message = 'This is the message.';
|
|
5
|
+
const title = 'This is the title.';
|
|
6
|
+
jest.mock('@shopgate/engage/a11y/components');
|
|
7
|
+
describe('<VariantSelectModal />', () => {
|
|
8
|
+
it('should render with minimal props', () => {
|
|
9
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(VariantSelectModal, {
|
|
10
|
+
message: message,
|
|
11
|
+
actions: [],
|
|
12
|
+
navigate: () => {}
|
|
13
|
+
}));
|
|
14
|
+
expect(wrapper).toMatchSnapshot();
|
|
15
|
+
expect(wrapper.html()).toMatch(message);
|
|
16
|
+
});
|
|
17
|
+
it('should render the actions', () => {
|
|
18
|
+
const mockConfirm = jest.fn();
|
|
19
|
+
const mockNavigate = jest.fn();
|
|
20
|
+
/**
|
|
2
21
|
* Mocks named function
|
|
3
|
-
*/
|
|
22
|
+
*/
|
|
23
|
+
const onConfirm = () => {
|
|
24
|
+
mockConfirm();
|
|
25
|
+
};
|
|
26
|
+
const actions = [{
|
|
27
|
+
label: 'confirm',
|
|
28
|
+
action: onConfirm
|
|
29
|
+
}, {
|
|
30
|
+
label: 'dismiss',
|
|
31
|
+
action: () => {}
|
|
32
|
+
}];
|
|
33
|
+
const params = {
|
|
34
|
+
productId: 'product_1'
|
|
35
|
+
};
|
|
36
|
+
const mockedProps = {
|
|
37
|
+
message,
|
|
38
|
+
title,
|
|
39
|
+
params,
|
|
40
|
+
actions: [...actions],
|
|
41
|
+
navigate: mockNavigate
|
|
42
|
+
};
|
|
43
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(VariantSelectModal, mockedProps));
|
|
44
|
+
expect(wrapper).toMatchSnapshot();
|
|
45
|
+
const reordered = wrapper.find('BasicDialog').props().actions;
|
|
46
|
+
const last = reordered.slice(-1)[0];
|
|
47
|
+
expect(last.label).toEqual(actions[0].label);
|
|
48
|
+
last.action();
|
|
49
|
+
expect(mockConfirm).toHaveBeenCalledTimes(1);
|
|
50
|
+
expect(mockNavigate).toHaveBeenCalledTimes(1);
|
|
51
|
+
});
|
|
52
|
+
});
|
package/Dialog/constants.js
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
-
export
|
|
1
|
+
export const DIALOG_TEXT_MESSAGE = 'DIALOG_TEXT_MESSAGE';
|
|
2
|
+
export const DIALOG_HTML_CONTENT = 'DIALOG_HTML_CONTENT';
|
|
3
|
+
export const MODAL_VARIANT_SELECT = 'MODAL_VARIANT_SELECT';
|
|
4
|
+
export const MODAL_ACTION_TYPE_NORMAL = 'normal';
|
|
5
|
+
export const MODAL_ACTION_TYPE_PRIMARY = 'primary';
|
|
6
|
+
export const MODAL_ACTION_TYPE_DANGER = 'danger';
|
package/Dialog/index.js
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import Modal from '@shopgate/pwa-common/components/Modal';
|
|
4
|
+
import Backdrop from '@shopgate/pwa-common/components/Backdrop';
|
|
5
|
+
import { MODAL_PIPELINE_ERROR } from '@shopgate/pwa-common/constants/ModalTypes';
|
|
6
|
+
import I18n from '@shopgate/pwa-common/components/I18n';
|
|
7
|
+
import { DIALOG_TEXT_MESSAGE, MODAL_VARIANT_SELECT, MODAL_ACTION_TYPE_PRIMARY, MODAL_ACTION_TYPE_NORMAL, DIALOG_HTML_CONTENT } from "./constants";
|
|
8
|
+
import PipelineErrorDialog from "./components/PipelineErrorDialog";
|
|
9
|
+
import TextMessageDialog from "./components/TextMessageDialog";
|
|
10
|
+
import HtmlContentDialog from "./components/HtmlContentDialog";
|
|
11
|
+
import BasicDialog from "./components/BasicDialog";
|
|
12
|
+
import VariantSelectModal from "./components/VariantSelectModal";
|
|
13
|
+
const dialogTypes = {
|
|
14
|
+
[DIALOG_TEXT_MESSAGE]: TextMessageDialog,
|
|
15
|
+
[DIALOG_HTML_CONTENT]: HtmlContentDialog,
|
|
16
|
+
[MODAL_PIPELINE_ERROR]: PipelineErrorDialog,
|
|
17
|
+
[MODAL_VARIANT_SELECT]: VariantSelectModal
|
|
18
|
+
};
|
|
19
|
+
const supportsInert = 'inert' in HTMLElement.prototype;
|
|
20
|
+
|
|
21
|
+
/**
|
|
2
22
|
* The main component for rendering dialogs.
|
|
3
23
|
* This component takes care of choosing the correct component body for the given type
|
|
4
24
|
* and render it on a modal overlay.
|
|
@@ -8,9 +28,96 @@ function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj
|
|
|
8
28
|
* @param {Function} props.onDismiss The function to call when the dismiss button is clicked.
|
|
9
29
|
* @param {NodeList} props.children The children to render inside the modal.
|
|
10
30
|
* @returns {JSX.Element}
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
31
|
+
*/
|
|
32
|
+
const Dialog = ({
|
|
33
|
+
modal,
|
|
34
|
+
onConfirm,
|
|
35
|
+
onDismiss,
|
|
36
|
+
children
|
|
37
|
+
}) => {
|
|
38
|
+
// Assemble the actions.
|
|
39
|
+
const actions = [];
|
|
40
|
+
const {
|
|
41
|
+
confirm,
|
|
42
|
+
dismiss,
|
|
43
|
+
title,
|
|
44
|
+
titleParams,
|
|
45
|
+
message,
|
|
46
|
+
params,
|
|
47
|
+
type,
|
|
48
|
+
confirmDisabled,
|
|
49
|
+
dismissDisabled
|
|
50
|
+
} = modal;
|
|
51
|
+
|
|
52
|
+
// Push dismiss action first so the button is rendered first
|
|
53
|
+
if (dismiss) {
|
|
54
|
+
// We have a dismiss label, add a dismiss action.
|
|
55
|
+
actions.push({
|
|
56
|
+
label: modal.dismiss,
|
|
57
|
+
action: onDismiss,
|
|
58
|
+
type: MODAL_ACTION_TYPE_PRIMARY,
|
|
59
|
+
disabled: dismissDisabled
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (confirm) {
|
|
63
|
+
// We have a confirm label, add a confirm action.
|
|
64
|
+
actions.push({
|
|
65
|
+
label: modal.confirm,
|
|
66
|
+
action: onConfirm,
|
|
67
|
+
type: MODAL_ACTION_TYPE_NORMAL,
|
|
68
|
+
disabled: confirmDisabled
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
let dialogType = type;
|
|
72
|
+
if (!dialogType && message) {
|
|
73
|
+
dialogType = DIALOG_TEXT_MESSAGE;
|
|
74
|
+
}
|
|
75
|
+
let dialogTitle = title;
|
|
76
|
+
if (titleParams) {
|
|
77
|
+
dialogTitle = /*#__PURE__*/React.createElement(I18n.Text, {
|
|
78
|
+
string: title,
|
|
79
|
+
params: titleParams
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const dialogProps = {
|
|
83
|
+
actions,
|
|
84
|
+
title: dialogTitle,
|
|
85
|
+
params,
|
|
86
|
+
message: message || undefined,
|
|
87
|
+
children
|
|
88
|
+
};
|
|
89
|
+
const DialogComponent = dialogTypes[dialogType] || BasicDialog;
|
|
90
|
+
|
|
91
|
+
// Effect to toggle aria-hidden on all other modals when the dialog is open.
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
const otherModals = document.querySelectorAll('.common__modal:not(.ui-shared__dialog-modal), .engage__sheet-drawer');
|
|
94
|
+
otherModals.forEach(entry => {
|
|
95
|
+
if (supportsInert) {
|
|
96
|
+
entry.setAttribute('inert', '');
|
|
97
|
+
} else {
|
|
98
|
+
entry.setAttribute('aria-hidden', 'true');
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return () => {
|
|
102
|
+
otherModals.forEach(entry => {
|
|
103
|
+
entry.removeAttribute('inert');
|
|
104
|
+
entry.removeAttribute('aria-hidden');
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
}, []);
|
|
108
|
+
return /*#__PURE__*/React.createElement(Modal, {
|
|
109
|
+
classes: {
|
|
110
|
+
container: 'ui-shared__dialog-modal'
|
|
111
|
+
}
|
|
112
|
+
}, /*#__PURE__*/React.createElement(Backdrop, {
|
|
113
|
+
isVisible: true,
|
|
114
|
+
level: 0,
|
|
115
|
+
opacity: 30
|
|
116
|
+
}), /*#__PURE__*/React.createElement(DialogComponent, dialogProps));
|
|
117
|
+
};
|
|
118
|
+
Dialog.defaultProps = {
|
|
119
|
+
onConfirm: () => {},
|
|
120
|
+
onDismiss: () => {},
|
|
121
|
+
children: null
|
|
122
|
+
};
|
|
123
|
+
export default Dialog;
|
package/Dialog/spec.js
CHANGED
|
@@ -1,5 +1,83 @@
|
|
|
1
|
-
import React from'react';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { shallow, ReactWrapper } from 'enzyme';
|
|
3
|
+
import { MODAL_PIPELINE_ERROR } from '@shopgate/pwa-common/constants/ModalTypes';
|
|
4
|
+
import { MODAL_VARIANT_SELECT } from "./constants";
|
|
5
|
+
import Dialog from "./index";
|
|
6
|
+
jest.mock("./components/VariantSelectModal", () => {
|
|
7
|
+
/**
|
|
2
8
|
* VariantSelectModal mock.
|
|
3
9
|
* @return {JSX}
|
|
4
|
-
*/
|
|
5
|
-
|
|
10
|
+
*/
|
|
11
|
+
const VariantSelectModal = () => /*#__PURE__*/React.createElement("div", null);
|
|
12
|
+
return VariantSelectModal;
|
|
13
|
+
});
|
|
14
|
+
jest.mock('@shopgate/engage/components');
|
|
15
|
+
describe('<Dialog />', () => {
|
|
16
|
+
it('should render without props', () => {
|
|
17
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(Dialog, {
|
|
18
|
+
modal: {
|
|
19
|
+
message: 'msg'
|
|
20
|
+
}
|
|
21
|
+
}));
|
|
22
|
+
expect(wrapper).toMatchSnapshot();
|
|
23
|
+
expect(wrapper.find('TextMessageDialog').length).toBe(1);
|
|
24
|
+
});
|
|
25
|
+
it('should render BasicDialog when no message given', () => {
|
|
26
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(Dialog, {
|
|
27
|
+
modal: {
|
|
28
|
+
message: null
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
expect(wrapper).toMatchSnapshot();
|
|
32
|
+
expect(wrapper.find('BasicDialog').length).toBe(1);
|
|
33
|
+
});
|
|
34
|
+
it('should render a special dialog', () => {
|
|
35
|
+
const params = {
|
|
36
|
+
errorCode: '',
|
|
37
|
+
message: '',
|
|
38
|
+
pipeline: '',
|
|
39
|
+
request: {}
|
|
40
|
+
};
|
|
41
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(Dialog, {
|
|
42
|
+
modal: {
|
|
43
|
+
type: MODAL_PIPELINE_ERROR,
|
|
44
|
+
params
|
|
45
|
+
}
|
|
46
|
+
}));
|
|
47
|
+
expect(wrapper).toMatchSnapshot();
|
|
48
|
+
expect(wrapper.find('DefaultDialog').length).toBe(0);
|
|
49
|
+
expect(wrapper.find('PipelineErrorDialog').length).toBe(1);
|
|
50
|
+
});
|
|
51
|
+
it('should render variant select dialog', () => {
|
|
52
|
+
const params = {
|
|
53
|
+
productId: 'product_1'
|
|
54
|
+
};
|
|
55
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(Dialog, {
|
|
56
|
+
modal: {
|
|
57
|
+
message: 'Test',
|
|
58
|
+
type: MODAL_VARIANT_SELECT,
|
|
59
|
+
params
|
|
60
|
+
}
|
|
61
|
+
}));
|
|
62
|
+
expect(wrapper).toMatchSnapshot();
|
|
63
|
+
expect(wrapper.find('DefaultDialog').length).toBe(0);
|
|
64
|
+
expect(wrapper.find('VariantSelectModal').length).toBe(1);
|
|
65
|
+
});
|
|
66
|
+
it('should convert title into translatable element', () => {
|
|
67
|
+
const title = 'translate.me';
|
|
68
|
+
const titleParams = {
|
|
69
|
+
foo: 'bar'
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// eslint-disable-next-line extra-rules/no-single-line-objects
|
|
73
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(Dialog, {
|
|
74
|
+
modal: {
|
|
75
|
+
title,
|
|
76
|
+
titleParams
|
|
77
|
+
}
|
|
78
|
+
}));
|
|
79
|
+
const i18n = new ReactWrapper(wrapper.find('BasicDialog').prop('title'));
|
|
80
|
+
expect(i18n.prop('string')).toEqual(title);
|
|
81
|
+
expect(i18n.prop('params')).toEqual(titleParams);
|
|
82
|
+
});
|
|
83
|
+
});
|
package/DiscountBadge/index.js
CHANGED
|
@@ -1,7 +1,35 @@
|
|
|
1
|
-
import React from'react';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { I18n } from '@shopgate/engage/components';
|
|
4
|
+
import { i18n } from '@shopgate/engage/core/helpers';
|
|
5
|
+
import styles from "./style";
|
|
6
|
+
|
|
7
|
+
/**
|
|
2
8
|
* The discount badge component.
|
|
3
9
|
* @param {Object} props The component props
|
|
4
10
|
* @param {string} [props.className] Additional CSS style definitions
|
|
5
11
|
* @param {string} props.text The text contents of the component.
|
|
6
12
|
* @returns {JSX.Element}
|
|
7
|
-
*/
|
|
13
|
+
*/
|
|
14
|
+
const DiscountBadge = ({
|
|
15
|
+
text,
|
|
16
|
+
className,
|
|
17
|
+
display,
|
|
18
|
+
discount
|
|
19
|
+
}) => /*#__PURE__*/React.createElement("div", {
|
|
20
|
+
"data-test-id": text,
|
|
21
|
+
className: "ui-shared__discount-badge",
|
|
22
|
+
"aria-label": `${i18n.text('cart.discount')}: ${text}`,
|
|
23
|
+
tabIndex: -1
|
|
24
|
+
}, /*#__PURE__*/React.createElement(I18n.Text, {
|
|
25
|
+
className: `${styles[display]} ${className} theme__discount-badge`,
|
|
26
|
+
string: text,
|
|
27
|
+
params: [discount],
|
|
28
|
+
"aria-hidden": true
|
|
29
|
+
}));
|
|
30
|
+
DiscountBadge.defaultProps = {
|
|
31
|
+
className: '',
|
|
32
|
+
discount: null,
|
|
33
|
+
display: 'small'
|
|
34
|
+
};
|
|
35
|
+
export default DiscountBadge;
|
package/DiscountBadge/spec.js
CHANGED
|
@@ -1 +1,19 @@
|
|
|
1
|
-
import React from'react';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { shallow } from 'enzyme';
|
|
3
|
+
import DiscountBadge from "./index";
|
|
4
|
+
jest.mock('@shopgate/engage/components');
|
|
5
|
+
describe('<DiscountBadge />', () => {
|
|
6
|
+
it('should render the text', () => {
|
|
7
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(DiscountBadge, {
|
|
8
|
+
text: "foo"
|
|
9
|
+
}));
|
|
10
|
+
expect(wrapper).toMatchSnapshot();
|
|
11
|
+
});
|
|
12
|
+
it('should render the text and discount', () => {
|
|
13
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(DiscountBadge, {
|
|
14
|
+
text: "SAVE {0}%",
|
|
15
|
+
discount: 20
|
|
16
|
+
}));
|
|
17
|
+
expect(wrapper).toMatchSnapshot();
|
|
18
|
+
});
|
|
19
|
+
});
|
package/DiscountBadge/style.js
CHANGED
|
@@ -1,4 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
import { css } from 'glamor';
|
|
2
|
+
import { themeConfig } from '@shopgate/pwa-common/helpers/config';
|
|
3
|
+
const {
|
|
4
|
+
colors
|
|
5
|
+
} = themeConfig;
|
|
6
|
+
const badge = {
|
|
7
|
+
background: `var(--color-primary, ${colors.primary})`,
|
|
8
|
+
borderRadius: 2,
|
|
9
|
+
color: `var(--color-primary-contrast, ${colors.primaryContrast})`,
|
|
10
|
+
padding: 5,
|
|
11
|
+
width: '100%',
|
|
12
|
+
fontWeight: 700,
|
|
13
|
+
textAlign: 'center',
|
|
14
|
+
display: 'flex',
|
|
15
|
+
justifyContent: 'center',
|
|
16
|
+
alignItems: 'center',
|
|
17
|
+
lineHeight: 1,
|
|
18
|
+
whiteSpace: 'nowrap',
|
|
19
|
+
...themeConfig.variables.discountBadgeBase
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
2
23
|
* The discount badge styles that can be selected by passing the style key.
|
|
3
24
|
* @type {Object}
|
|
4
|
-
*/
|
|
25
|
+
*/
|
|
26
|
+
export default {
|
|
27
|
+
small: css({
|
|
28
|
+
...badge
|
|
29
|
+
}).toString(),
|
|
30
|
+
big: css({
|
|
31
|
+
...badge,
|
|
32
|
+
paddingTop: 5,
|
|
33
|
+
paddingLeft: 5,
|
|
34
|
+
paddingRight: 5
|
|
35
|
+
}).toString()
|
|
36
|
+
};
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
-
import{connect}from'react-redux';
|
|
1
|
+
import { connect } from 'react-redux';
|
|
2
|
+
import { toggleFavoriteWithListChooser } from '@shopgate/pwa-common-commerce/favorites/actions/toggleFavorites';
|
|
3
|
+
import { getLoadWishlistOnAppStartEnabled, getWishlistItemQuantityEnabled } from '@shopgate/engage/core/selectors/shopSettings';
|
|
4
|
+
|
|
5
|
+
/**
|
|
2
6
|
* Creates the mapStateToProps connector function.
|
|
3
7
|
* @returns {Function}
|
|
4
|
-
*/
|
|
8
|
+
*/
|
|
9
|
+
const makeMapStateToProps = () => state => ({
|
|
10
|
+
wishlistItemQuantityEnabled: getWishlistItemQuantityEnabled(state),
|
|
11
|
+
loadWishlistOnAppStartEnabled: getLoadWishlistOnAppStartEnabled(state)
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
/**
|
|
5
15
|
* Connects the dispatch function to a callable function in the props.
|
|
6
16
|
* @param {Function} dispatch The redux dispatch function.
|
|
7
17
|
* @return {Object} The extended component props.
|
|
8
|
-
*/
|
|
18
|
+
*/
|
|
19
|
+
const mapDispatchToProps = dispatch => ({
|
|
20
|
+
addFavorites: productId => dispatch(toggleFavoriteWithListChooser(productId)),
|
|
21
|
+
removeFavorites: (productId, withRelatives) => dispatch(toggleFavoriteWithListChooser(productId, withRelatives))
|
|
22
|
+
});
|
|
23
|
+
export default connect(makeMapStateToProps, mapDispatchToProps);
|
package/FavoritesButton/index.js
CHANGED
|
@@ -1,24 +1,127 @@
|
|
|
1
|
-
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import appConfig from '@shopgate/pwa-common/helpers/config';
|
|
4
|
+
import HeartIcon from "../icons/HeartIcon";
|
|
5
|
+
import HeartOutlineIcon from "../icons/HeartOutlineIcon";
|
|
6
|
+
import HeartPlusOutlineIcon from "../icons/HeartPlusOutlineIcon";
|
|
7
|
+
import HeartPlus from "../icons/HeartPlusIcon";
|
|
8
|
+
import Ripple from "../Ripple";
|
|
9
|
+
import styles from "./style";
|
|
10
|
+
import connect from "./connector";
|
|
11
|
+
|
|
12
|
+
/**
|
|
2
13
|
* The favorites button component.
|
|
3
|
-
*/
|
|
14
|
+
*/
|
|
15
|
+
class FavoritesButton extends Component {
|
|
16
|
+
/**
|
|
4
17
|
* Construct and init state
|
|
5
18
|
* @param {Object} props Component props
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
19
|
+
*/
|
|
20
|
+
constructor(props) {
|
|
21
|
+
super(props);
|
|
22
|
+
/**
|
|
23
|
+
* Callback for the moment when the ripple animation is done.
|
|
24
|
+
*/
|
|
25
|
+
this.onRippleComplete = () => {
|
|
26
|
+
this.props.onRippleComplete(this.props.active);
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Adds or removes a given product ID from the favorite list.
|
|
30
|
+
* @param {Object} event The click event object.
|
|
31
|
+
*/
|
|
32
|
+
this.handleClick = event => {
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
event.stopPropagation();
|
|
35
|
+
if (this.props.once && this.clickedOnce) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
this.clickedOnce = true;
|
|
39
|
+
if (!this.props.productId) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// When wishlist item quantity is active, items cannot be removed via the button
|
|
44
|
+
if (!this.props.active || this.props.wishlistItemQuantityEnabled) {
|
|
45
|
+
this.props.addFavorites(this.props.productId);
|
|
46
|
+
} else {
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
this.props.removeFavorites(this.props.productId, this.props.removeWithRelatives);
|
|
49
|
+
}, this.props.removeThrottle);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
this.clickedOnce = false;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
13
55
|
* Returns text for aria-label.
|
|
14
56
|
* @returns {string}
|
|
15
|
-
*/
|
|
57
|
+
*/
|
|
58
|
+
getLabel() {
|
|
59
|
+
const {
|
|
60
|
+
__
|
|
61
|
+
} = this.context.i18n();
|
|
62
|
+
const lang = this.props.active ? 'favorites.remove' : 'favorites.add';
|
|
63
|
+
return __(lang);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
16
66
|
* Renders the heart icon as filled or outlined, depending on the favorite button being active.
|
|
17
67
|
* @returns {JSX}
|
|
18
|
-
*/
|
|
68
|
+
*/
|
|
69
|
+
renderIcon() {
|
|
70
|
+
if (!this.props.loadWishlistOnAppStartEnabled || this.props.wishlistItemQuantityEnabled && !this.props.active) {
|
|
71
|
+
return /*#__PURE__*/React.createElement(HeartPlusOutlineIcon, null);
|
|
72
|
+
}
|
|
73
|
+
if (this.props.wishlistItemQuantityEnabled && this.props.active) {
|
|
74
|
+
return /*#__PURE__*/React.createElement(HeartPlus, null);
|
|
75
|
+
}
|
|
76
|
+
if (this.props.active) {
|
|
77
|
+
return /*#__PURE__*/React.createElement(HeartIcon, null);
|
|
78
|
+
}
|
|
79
|
+
return /*#__PURE__*/React.createElement(HeartOutlineIcon, null);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
19
83
|
* Renders the component.
|
|
20
84
|
* @returns {JSX|null}
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
85
|
+
*/
|
|
86
|
+
render() {
|
|
87
|
+
if (!appConfig.hasFavorites) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const className = this.props.noShadow ? styles.buttonFlat : styles.button;
|
|
91
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
92
|
+
"aria-label": this.getLabel(),
|
|
93
|
+
"aria-hidden": this.props['aria-hidden'],
|
|
94
|
+
className: `ui-shared__favorites-button ${className} ${this.props.className}`,
|
|
95
|
+
onClick: this.handleClick,
|
|
96
|
+
"data-test-id": "favoriteButton",
|
|
97
|
+
type: "button"
|
|
98
|
+
}, /*#__PURE__*/React.createElement(Ripple, {
|
|
99
|
+
className: `${styles.ripple} ${this.props.rippleClassName}`,
|
|
100
|
+
onComplete: this.onRippleComplete
|
|
101
|
+
}, this.renderIcon()));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Context types definition.
|
|
106
|
+
* @type {{i18n: shim}}
|
|
107
|
+
*/
|
|
108
|
+
FavoritesButton.contextTypes = {
|
|
109
|
+
i18n: PropTypes.func
|
|
110
|
+
};
|
|
111
|
+
FavoritesButton.defaultProps = {
|
|
112
|
+
active: false,
|
|
113
|
+
addFavorites: () => {},
|
|
114
|
+
'aria-hidden': null,
|
|
115
|
+
className: '',
|
|
116
|
+
noShadow: false,
|
|
117
|
+
once: false,
|
|
118
|
+
onRippleComplete: () => {},
|
|
119
|
+
productId: null,
|
|
120
|
+
removeFavorites: () => {},
|
|
121
|
+
removeThrottle: 0,
|
|
122
|
+
removeWithRelatives: false,
|
|
123
|
+
rippleClassName: '',
|
|
124
|
+
wishlistItemQuantityEnabled: false,
|
|
125
|
+
loadWishlistOnAppStartEnabled: true
|
|
126
|
+
};
|
|
127
|
+
export default connect(FavoritesButton);
|
package/FavoritesButton/mock.js
CHANGED
|
@@ -1,10 +1,56 @@
|
|
|
1
|
-
|
|
1
|
+
const mockedProduct1 = {
|
|
2
|
+
productId: 'foo'
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
/**
|
|
2
6
|
* Mocked state with product only. Favorites not set.
|
|
3
7
|
* @type {Object}
|
|
4
|
-
*/
|
|
8
|
+
*/
|
|
9
|
+
export const mockedStateNotOnList = {
|
|
10
|
+
product: {
|
|
11
|
+
productsById: {
|
|
12
|
+
[mockedProduct1.productId]: {
|
|
13
|
+
productData: mockedProduct1
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
favorites: {
|
|
18
|
+
products: {
|
|
19
|
+
ids: [mockedProduct1.productId]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
5
25
|
* Mocked state with product only. Favorites not set.
|
|
6
26
|
* @type {Object}
|
|
7
|
-
*/
|
|
27
|
+
*/
|
|
28
|
+
export const mockedStateOnList = {
|
|
29
|
+
product: {
|
|
30
|
+
productsById: {
|
|
31
|
+
[mockedProduct1.productId]: {
|
|
32
|
+
productData: mockedProduct1
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
favorites: {
|
|
37
|
+
products: {
|
|
38
|
+
ids: [mockedProduct1.productId]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
8
44
|
* Mocked state without data.
|
|
9
45
|
* @type {{product: {, favorites: {}}}}
|
|
10
|
-
*/
|
|
46
|
+
*/
|
|
47
|
+
export const mockedStateEmpty = {
|
|
48
|
+
product: {
|
|
49
|
+
productsById: {}
|
|
50
|
+
},
|
|
51
|
+
favorites: {
|
|
52
|
+
products: {
|
|
53
|
+
ids: []
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|