From 6c9dbc8a71208bf3e7f9effdd8eb29ecef288bd3 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 17 Jan 2024 16:14:40 +0100 Subject: [PATCH 01/55] Add back in stock --- .../commerce/product/constants/Portals.js | 6 + .../commerce/product/selectors/product.js | 11 + libraries/common/constants/Portals.js | 5 + .../engage/back-in-stock/actions/index.js | 108 ++++++++++ .../components/BackInStock/BackInStock.jsx | 15 ++ .../back-in-stock/components/List/index.jsx | 94 +++++++++ .../components/Subscription/connector.js | 16 ++ .../components/Subscription/index.jsx | 189 ++++++++++++++++++ .../engage/back-in-stock/constants/index.js | 13 ++ libraries/engage/back-in-stock/hooks/index.js | 9 + libraries/engage/back-in-stock/index.js | 8 + ...kInStockSubscriptionsProvider.connector.js | 32 +++ ...ackInStockSubscriptionsProvider.context.js | 5 + .../BackInStockSubscriptionsProvider.jsx | 53 +++++ .../engage/back-in-stock/reducers/index.js | 87 ++++++++ .../back-in-stock/selectors/backInStock.js | 78 ++++++++ .../engage/back-in-stock/streams/index.js | 23 +++ .../back-in-stock/subscriptions/index.js | 25 +++ libraries/engage/components/index.js | 1 + .../engage/core/actions/grantPermissions.js | 2 +- .../core/actions/grantPushPermissions.js | 59 ++++++ .../components/BackInStockRow/connector.js | 29 +++ .../components/BackInStockRow/index.jsx | 70 +++++++ .../Characteristic/components/Sheet/index.jsx | 10 +- .../components/SheetItem/index.jsx | 27 ++- .../components/SheetItem/style.js | 2 +- .../ui-shared/BackInStockButton/index.jsx | 65 ++++++ .../ui-shared/BackInStockButton/style.js | 33 +++ .../ui-shared/icons/NotificationIcon.jsx | 12 ++ .../components/Badge/connector.js | 13 ++ .../components/Badge/index.jsx | 13 ++ .../components/Badge/style.js | 16 ++ .../components/BackInStockButton/index.jsx | 44 ++++ .../NavDrawer/components/Main/connector.js | 12 ++ .../NavDrawer/components/Main/index.jsx | 13 +- themes/theme-gmd/extension-config.json | 3 +- themes/theme-gmd/extension-config.schema.json | 3 + themes/theme-gmd/locale/de-DE.json | 23 ++- themes/theme-gmd/locale/en-US.json | 23 ++- .../BackInStock/components/AppBar/index.jsx | 14 ++ themes/theme-gmd/pages/BackInStock/index.jsx | 24 +++ .../components/BackInStockRow/connector.js | 26 +++ .../components/BackInStockRow/index.jsx | 69 +++++++ .../Characteristic/components/Sheet/index.jsx | 10 +- .../components/SheetItem/index.jsx | 14 +- .../components/BackInStock/connector.js | 27 +++ .../Header/components/BackInStock/index.jsx | 72 +++++++ .../Header/components/ProductInfo/index.jsx | 11 +- .../pages/Product/components/Header/index.jsx | 2 +- themes/theme-gmd/pages/index.jsx | 6 + themes/theme-gmd/pages/reducers.js | 2 + themes/theme-gmd/pages/routes.js | 1 + themes/theme-gmd/pages/subscribers.js | 4 + themes/theme-ios11/extension-config.json | 3 +- .../theme-ios11/extension-config.schema.json | 3 + themes/theme-ios11/locale/de-DE.json | 23 ++- themes/theme-ios11/locale/en-US.json | 23 ++- .../BackInStock/components/AppBar/index.jsx | 15 ++ .../theme-ios11/pages/BackInStock/index.jsx | 24 +++ .../More/components/Quicklinks/connector.js | 2 + .../More/components/Quicklinks/index.jsx | 13 +- .../components/BackInStock/connector.js | 28 +++ .../Header/components/BackInStock/index.jsx | 72 +++++++ .../Header/components/ProductInfo/index.jsx | 7 +- .../pages/Product/components/Header/index.jsx | 2 +- themes/theme-ios11/pages/index.jsx | 20 +- themes/theme-ios11/pages/reducers.js | 2 + themes/theme-ios11/pages/routes.js | 1 + themes/theme-ios11/pages/subscribers.js | 4 + 69 files changed, 1737 insertions(+), 37 deletions(-) create mode 100644 libraries/engage/back-in-stock/actions/index.js create mode 100644 libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx create mode 100644 libraries/engage/back-in-stock/components/List/index.jsx create mode 100644 libraries/engage/back-in-stock/components/Subscription/connector.js create mode 100644 libraries/engage/back-in-stock/components/Subscription/index.jsx create mode 100644 libraries/engage/back-in-stock/constants/index.js create mode 100644 libraries/engage/back-in-stock/hooks/index.js create mode 100644 libraries/engage/back-in-stock/index.js create mode 100644 libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js create mode 100644 libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.context.js create mode 100644 libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.jsx create mode 100644 libraries/engage/back-in-stock/reducers/index.js create mode 100644 libraries/engage/back-in-stock/selectors/backInStock.js create mode 100644 libraries/engage/back-in-stock/streams/index.js create mode 100644 libraries/engage/back-in-stock/subscriptions/index.js create mode 100644 libraries/engage/core/actions/grantPushPermissions.js create mode 100644 libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js create mode 100644 libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx create mode 100644 libraries/ui-shared/BackInStockButton/index.jsx create mode 100644 libraries/ui-shared/BackInStockButton/style.js create mode 100644 libraries/ui-shared/icons/NotificationIcon.jsx create mode 100644 themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/connector.js create mode 100644 themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/index.jsx create mode 100644 themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/style.js create mode 100644 themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx create mode 100644 themes/theme-gmd/components/NavDrawer/components/Main/connector.js create mode 100644 themes/theme-gmd/pages/BackInStock/components/AppBar/index.jsx create mode 100644 themes/theme-gmd/pages/BackInStock/index.jsx create mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js create mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx create mode 100644 themes/theme-gmd/pages/Product/components/Header/components/BackInStock/connector.js create mode 100644 themes/theme-gmd/pages/Product/components/Header/components/BackInStock/index.jsx create mode 100644 themes/theme-ios11/pages/BackInStock/components/AppBar/index.jsx create mode 100644 themes/theme-ios11/pages/BackInStock/index.jsx create mode 100644 themes/theme-ios11/pages/Product/components/Header/components/BackInStock/connector.js create mode 100644 themes/theme-ios11/pages/Product/components/Header/components/BackInStock/index.jsx diff --git a/libraries/commerce/product/constants/Portals.js b/libraries/commerce/product/constants/Portals.js index c7012ab58d..3eea4fd2cc 100644 --- a/libraries/commerce/product/constants/Portals.js +++ b/libraries/commerce/product/constants/Portals.js @@ -26,6 +26,7 @@ const MANUFACTURER = 'manufacturer'; const SHIPPING = 'shipping'; const AVAILABILITY = 'availability'; const STOCK_INFO = 'stock-info'; +const BACK_IN_STOCK = 'back-in-stock'; const PRICE_STRIKED = 'price-striked'; const PRICE = 'price'; const PRICE_INFO = 'price-info'; @@ -115,6 +116,11 @@ export const PRODUCT_STOCK_INFO_BEFORE = `${PRODUCT}.${STOCK_INFO}.${BEFORE}`; export const PRODUCT_STOCK_INFO = `${PRODUCT}.${STOCK_INFO}`; export const PRODUCT_STOCK_INFO_AFTER = `${PRODUCT}.${STOCK_INFO}.${AFTER}`; +// BACKINSTOCK INFO +export const PRODUCT_BACK_IN_STOCK_BEFORE = `${PRODUCT}.${BACK_IN_STOCK}.${BEFORE}`; +export const PRODUCT_BACK_IN_STOCK = `${PRODUCT}.${BACK_IN_STOCK}`; +export const PRODUCT_BACK_IN_STOCK_AFTER = `${PRODUCT}.${BACK_IN_STOCK}.${AFTER}`; + // PRICE STRIKED export const PRODUCT_PRICE_STRIKED_BEFORE = `${PRODUCT}.${PRICE_STRIKED}.${BEFORE}`; export const PRODUCT_PRICE_STRIKED = `${PRODUCT}.${PRICE_STRIKED}`; diff --git a/libraries/commerce/product/selectors/product.js b/libraries/commerce/product/selectors/product.js index 5acf3d1d74..0526b30273 100644 --- a/libraries/commerce/product/selectors/product.js +++ b/libraries/commerce/product/selectors/product.js @@ -232,6 +232,17 @@ export const getProductLongName = createSelector( } ); +/** + * Retrieves the product type. + * @param {Object} state The current application state. + * @param {Object} props The component props. + * @return {string|null} + */ +export const getProductType = createSelector( + getProduct, + product => product?.type +); + /** * Retrieves the product rating. * @param {Object} state The current application state. diff --git a/libraries/common/constants/Portals.js b/libraries/common/constants/Portals.js index 505611ce76..36c2d639dd 100644 --- a/libraries/common/constants/Portals.js +++ b/libraries/common/constants/Portals.js @@ -17,6 +17,7 @@ const QUICK_LINKS = 'quick-links'; const HOME = 'home'; const LOGIN = 'login'; const SCANNER = 'scanner'; +const BACK_IN_STOCK = 'back-in-stock'; const REGISTER_LINK = 'register-link'; const TERMS = 'terms'; const PRIVACY = 'privacy'; @@ -82,6 +83,10 @@ export const NAV_MENU_SCANNER_BEFORE = `${NAV_MENU}.${SCANNER}.${BEFORE}`; export const NAV_MENU_SCANNER = `${NAV_MENU}.${SCANNER}`; export const NAV_MENU_SCANNER_AFTER = `${NAV_MENU}.${SCANNER}.${AFTER}`; +export const NAV_MENU_BACK_IN_STOCK_BEFORE = `${NAV_MENU}.${BACK_IN_STOCK}.${BEFORE}`; +export const NAV_MENU_BACK_IN_STOCK = `${NAV_MENU}.${BACK_IN_STOCK}`; +export const NAV_MENU_BACK_IN_STOCK_AFTER = `${NAV_MENU}.${BACK_IN_STOCK}.${AFTER}`; + export const NAV_MENU_TERMS_BEFORE = `${NAV_MENU}.${TERMS}.${BEFORE}`; export const NAV_MENU_TERMS = `${NAV_MENU}.${TERMS}`; export const NAV_MENU_TERMS_AFTER = `${NAV_MENU}.${TERMS}.${AFTER}`; diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js new file mode 100644 index 0000000000..4a28ad0982 --- /dev/null +++ b/libraries/engage/back-in-stock/actions/index.js @@ -0,0 +1,108 @@ +import { PipelineRequest } from '@shopgate/engage/core'; +import { + ADD_BACK_IN_STOCK_SUBSCRIPTION, + ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, + ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + FETCH_BACK_IN_STOCK_SUBSCRIPTIONS, + FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, + FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, + REMOVE_BACK_IN_STOCK_SUBSCRIPTION, + REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR, + REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, +} from '../constants'; + +/** + * Fetches Back in Stock Subscriptions + * @returns {Function} + */ +export const fetchBackInStoreSubscriptions = () => async (dispatch) => { + dispatch({ type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS }); + + try { + const { subscriptions } = await new PipelineRequest('shopgate.user.getBackInStockSubscriptions') + .setInput({ + limit: 100, + offset: 100, + }) + .dispatch(); + + dispatch({ + type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, + subscriptions, + }); + + return subscriptions; + } catch (error) { + dispatch({ + type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, + error, + }); + + return null; + } +}; + +/** + * Add a Back in Stock Subscription + * @param {Object} props Props. + * @param {string} props.productCode The product for which the subscription should be added + * @returns {Function} + */ +export const addBackInStoreSubscription = ({ productCode }) => async (dispatch) => { + dispatch({ type: ADD_BACK_IN_STOCK_SUBSCRIPTION }); + + try { + const { subscriptions } = await new PipelineRequest('shopgate.user.addBackInStockSubscription') + .setInput({ + productCode, + }) + .dispatch(); + + dispatch({ + type: ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + subscriptions, + }); + return subscriptions; + } catch (error) { + dispatch({ + type: ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, + error, + }); + + return null; + } +}; + +/** + * Remove a Back in Stock Subscription + * @param {Object} props Props. + * @param {string} props.subscriptionCode The subscription which should be deleted + * @returns {Function} + */ +export const removeBackInStoreSubscription = ({ subscriptionCode }) => async (dispatch) => { + dispatch({ type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION }); + + const pipelineRequest = new PipelineRequest('shopgate.user.removeBackInStockSubscription'); + + try { + const { subscriptions } = await pipelineRequest + .setInput({ + subscriptionCode, + }) + .dispatch(); + + dispatch({ + type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + subscriptions, + }); + return subscriptions; + } catch (error) { + dispatch({ + type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR, + error, + }); + + return null; + } +}; + diff --git a/libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx b/libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx new file mode 100644 index 0000000000..05e7020e08 --- /dev/null +++ b/libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx @@ -0,0 +1,15 @@ +import React from 'react'; +import BackInStockSubscriptionsProvider from '../../providers/BackInStockSubscriptionsProvider'; +import List from '../List'; + +/** + * The Back in Stock component. + * @returns {JSX} + */ +const BackInStock = () => ( + + + +); + +export default BackInStock; diff --git a/libraries/engage/back-in-stock/components/List/index.jsx b/libraries/engage/back-in-stock/components/List/index.jsx new file mode 100644 index 0000000000..09b11b76d5 --- /dev/null +++ b/libraries/engage/back-in-stock/components/List/index.jsx @@ -0,0 +1,94 @@ +import React from 'react'; +import { css } from 'glamor'; +import LoadingIndicator from '@shopgate/pwa-ui-shared/LoadingIndicator'; +import { + Accordion, + Card, +} from '@shopgate/engage/components'; +import { i18n } from '@shopgate/engage/core'; +import { useBackInStockSubscriptionsContext } from '../../hooks'; +import Subscription from '../Subscription'; + +const styles = { + divider: css({ + height: 1, + width: 'calc(100% + 32px)', + backgroundColor: 'rgb(234, 234, 234)', + marginLeft: -16, + marginRight: -16, + marginBottom: 16, + }).toString(), + emptyText: css({ + marginBottom: 16, + textAlign: 'center', + }).toString(), + listTitle: css({ + fontWeight: '700', + }).toString(), +}; + +/** + * The Back In Stock Subscriptions List. + * @returns {JSX} + */ +const List = () => { + const { + subscriptions, + isInitial, + } = useBackInStockSubscriptionsContext(); + + const groupedSubscriptions = subscriptions.reduce((acc, subscription) => { + const { status } = subscription; + const groupingStatus = (status === 'inactive' || status === 'triggered') ? 'past' : status; + acc[groupingStatus].push(subscription); + return acc; + }, { + active: [], + past: [], + }); + + // eslint-disable-next-line require-jsdoc + const renderLabel = groupKey => +
+ {i18n.text(`back_in_stock.list_states.${groupKey}`)} +
; + + return ( +
+ {Object.entries(groupedSubscriptions).map(([groupKey, filteredSubscriptions]) => ( + + renderLabel(groupKey)} + chevronPosition="left" + startOpened + > +
+ {isInitial ? : null} + {!isInitial && filteredSubscriptions.length === 0 ? ( +
{i18n.text('back_in_stock.empty_list_reminder')}
+ ) : null} + + {!isInitial && filteredSubscriptions.map((subscription, index) => ( +
+ + {(index === filteredSubscriptions.length - 1) ? + null : +
} +
+ ))} + + + ))} + +
+ ); +}; + +export default List; diff --git a/libraries/engage/back-in-stock/components/Subscription/connector.js b/libraries/engage/back-in-stock/components/Subscription/connector.js new file mode 100644 index 0000000000..9f090e0b66 --- /dev/null +++ b/libraries/engage/back-in-stock/components/Subscription/connector.js @@ -0,0 +1,16 @@ +import { connect } from 'react-redux'; +import { addBackInStoreSubscription } from '@shopgate/engage/back-in-stock/actions'; +import { getSubscriptionByVariant } from '../../selectors/backInStock'; + +/** + * @return {Object} The extended component props. + */ +const makeMapStateToProps = () => (state, props) => ({ + subscription: getSubscriptionByVariant(state, props), +}); + +const mapDispatchToProps = { + addBackInStoreSubscription, +}; + +export default connect(makeMapStateToProps, mapDispatchToProps); diff --git a/libraries/engage/back-in-stock/components/Subscription/index.jsx b/libraries/engage/back-in-stock/components/Subscription/index.jsx new file mode 100644 index 0000000000..8109415062 --- /dev/null +++ b/libraries/engage/back-in-stock/components/Subscription/index.jsx @@ -0,0 +1,189 @@ +import React from 'react'; +import { css } from 'glamor'; +import { + Link, + Ripple, + PriceInfo, +} from '@shopgate/engage/components'; +import { getProductRoute } from '@shopgate/pwa-common-commerce/product'; +import { ProductImage } from '@shopgate/engage/product'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import PriceStriked from '@shopgate/pwa-ui-shared/PriceStriked'; +import Price from '@shopgate/pwa-ui-shared/Price'; +import { themeConfig } from '@shopgate/pwa-common/helpers/config'; +import CrossIcon from '@shopgate/pwa-ui-shared/icons/CrossIcon'; +import AvailableText from '@shopgate/pwa-ui-shared/Availability'; +import BackInStockButton from '@shopgate/pwa-ui-shared/BackInStockButton'; +import { useBackInStockSubscriptionsContext } from '../../hooks'; +import { getThemeSettings, i18n } from '../../../core'; + +const { variables } = themeConfig; + +const styles = { + root: css({ + display: 'flex', + position: 'relative', + marginBottom: 16, + }).toString(), + imageContainer: css({ + flex: 0.4, + marginRight: 18, + maxWidth: 170, + minWidth: 126, + }).toString(), + infoContainer: css({ + flex: 1, + display: 'flex', + flexDirection: 'column', + flexWrap: 'wrap', + gap: 8, + }).toString(), + infoContainerRow: css({ + flexDirection: 'row', + display: 'flex', + justifyContent: 'space-between', + }).toString(), + baseContainerRow: css({ + flexDirection: 'column', + display: 'flex', + }).toString(), + priceContainerRow: css({ + flexDirection: 'column', + display: 'flex', + alignItems: 'end', + }).toString(), + priceContainer: css({ + minWidth: 100, + }).toString(), + priceInfo: css({ + wordBreak: 'break-word', + fontSize: '0.875rem', + lineHeight: '0.875rem', + color: 'var(--color-text-low-emphasis)', + padding: `${variables.gap.xsmall}px 0`, + textAlign: 'right', + }).toString(), + titleWrapper: css({ + display: 'flex', + flexDirection: 'column', + gap: 8, + }).toString(), + titleContainer: css({ + marginRight: 10, + flex: 1, + }).toString(), + title: css({ + fontSize: 17, + + fontWeight: 600, + }).toString(), + removeContainer: css({ + display: 'flex', + flexShrink: 0, + alignItems: 'flex-start', + }), +}; + +/** + * Renders on single Back in Stock subscription + * @param {Object} props Props. + * @param {string} props.subscription The subscription which should be rendered + * @returns {JSX} + */ +const Subscription = ({ + subscription, +}) => { + const { subscriptionCode, product } = subscription; + const { + removeBackInStoreSubscription, + } = useBackInStockSubscriptionsContext(); + const { ListImage: gridResolutions } = getThemeSettings('AppImages') || {}; + const currency = product.price?.currency || 'EUR'; + const defaultPrice = product.price?.unitPrice || 0; + const specialPrice = product.price?.unitPriceStriked; + const hasStrikePrice = product.price?.discount > 0; + const productLink = getProductRoute(product.id); + + return ( +
+ + + + +
+
+
+ + + +
+
+ +
+
+
+ + {}} + /> +
+
+ {hasStrikePrice ? ( + + ) : null} + + {!!product.price.info && ( + + )} +
+ +
+
+ ); +}; + +Subscription.propTypes = { + subscription: PropTypes.shape({ + product: PropTypes.shape().isRequired, + productCode: PropTypes.string.isRequired, + subscriptionCode: PropTypes.string.isRequired, + status: PropTypes.oneOf(['active', 'inactive', 'triggered']).isRequired, + }).isRequired, +}; + +export default Subscription; diff --git a/libraries/engage/back-in-stock/constants/index.js b/libraries/engage/back-in-stock/constants/index.js new file mode 100644 index 0000000000..d081952de2 --- /dev/null +++ b/libraries/engage/back-in-stock/constants/index.js @@ -0,0 +1,13 @@ +export const BACK_IN_STOCK_PATTERN = '/back-in-stock'; + +export const FETCH_BACK_IN_STOCK_SUBSCRIPTIONS = 'FETCH_BACK_IN_STOCK_SUBSCRIPTIONS'; +export const FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS = 'FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS'; +export const FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR = 'FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR'; + +export const ADD_BACK_IN_STOCK_SUBSCRIPTION = 'ADD_BACK_IN_STOCK_SUBSCRIPTION'; +export const ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS = 'ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS'; +export const ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR = 'ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR'; + +export const REMOVE_BACK_IN_STOCK_SUBSCRIPTION = 'REMOVE_BACK_IN_STOCK_SUBSCRIPTION'; +export const REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS = 'REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS'; +export const REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR = 'REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR'; diff --git a/libraries/engage/back-in-stock/hooks/index.js b/libraries/engage/back-in-stock/hooks/index.js new file mode 100644 index 0000000000..5875be74f0 --- /dev/null +++ b/libraries/engage/back-in-stock/hooks/index.js @@ -0,0 +1,9 @@ +import React from 'react'; +import BackInStockSubscriptionsProvider from '../providers/BackInStockSubscriptionsProvider.context'; + +/** + * Injects the Back in Stock Subscription Context + * @returns {JSX} + */ +export const useBackInStockSubscriptionsContext = () => + React.useContext(BackInStockSubscriptionsProvider); diff --git a/libraries/engage/back-in-stock/index.js b/libraries/engage/back-in-stock/index.js new file mode 100644 index 0000000000..323f1179f2 --- /dev/null +++ b/libraries/engage/back-in-stock/index.js @@ -0,0 +1,8 @@ +// CONSTANTS +export * from './constants'; + +// Components +export { default as BackInStockReminders } from './components/BackInStock/BackInStock'; + +// STREAMS +export * from './streams'; diff --git a/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js new file mode 100644 index 0000000000..800f8dc487 --- /dev/null +++ b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js @@ -0,0 +1,32 @@ +import { connect } from 'react-redux'; +import { + getBackInStockSubscriptions, + getBackInStockSubscriptionsFetching, getBackInStockSubscriptionsInitial, +} from '../selectors/backInStock'; +import { + addBackInStoreSubscription, + removeBackInStoreSubscription, +} from '../actions'; + +/** + * @return {Function} The extended component props. + */ +function makeMapStateToProps() { + /** + * @param {Object} state The application state. + * @param {Object} props The component props + * @returns {Object} + */ + return (state, props) => ({ + subscriptions: getBackInStockSubscriptions(state, props), + isFetching: getBackInStockSubscriptionsFetching(state, props), + isInitial: getBackInStockSubscriptionsInitial(state, props), + }); +} + +const mapDispatchToProps = { + addBackInStoreSubscription, + removeBackInStoreSubscription, +}; + +export default connect(makeMapStateToProps, mapDispatchToProps); diff --git a/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.context.js b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.context.js new file mode 100644 index 0000000000..c5f5159bd8 --- /dev/null +++ b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.context.js @@ -0,0 +1,5 @@ +import React from 'react'; + +const initialContext = {}; + +export default React.createContext(initialContext); diff --git a/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.jsx b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.jsx new file mode 100644 index 0000000000..ad8e5a4995 --- /dev/null +++ b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.jsx @@ -0,0 +1,53 @@ +import React, { useMemo } from 'react'; +import PropTypes from 'prop-types'; +import Context from './BackInStockSubscriptionsProvider.context'; +import connect from './BackInStockSubscriptionsProvider.connector'; + +/** + * Back in Stock Provider + * @returns {JSX} + */ +const BackInStoreSubscriptionsProvider = ({ + subscriptions, + children, + addBackInStoreSubscription, + isFetching, + isInitial, + removeBackInStoreSubscription, +}) => { + // Create memoized context value. + const value = useMemo(() => ({ + subscriptions, + addBackInStoreSubscription, + removeBackInStoreSubscription, + isFetching, + isInitial, + }), [ + addBackInStoreSubscription, + isFetching, + isInitial, + removeBackInStoreSubscription, + subscriptions]); + + return ( + + {children} + + ); +}; + +BackInStoreSubscriptionsProvider.propTypes = { + addBackInStoreSubscription: PropTypes.func.isRequired, + removeBackInStoreSubscription: PropTypes.func.isRequired, + subscriptions: PropTypes.arrayOf(PropTypes.shape()).isRequired, + children: PropTypes.node, + isFetching: PropTypes.bool, + isInitial: PropTypes.bool, +}; +BackInStoreSubscriptionsProvider.defaultProps = { + children: null, + isFetching: false, + isInitial: true, +}; + +export default connect(BackInStoreSubscriptionsProvider); diff --git a/libraries/engage/back-in-stock/reducers/index.js b/libraries/engage/back-in-stock/reducers/index.js new file mode 100644 index 0000000000..29186e016d --- /dev/null +++ b/libraries/engage/back-in-stock/reducers/index.js @@ -0,0 +1,87 @@ +import { + ADD_BACK_IN_STOCK_SUBSCRIPTION, + ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, + ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + FETCH_BACK_IN_STOCK_SUBSCRIPTIONS, + FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, + FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, + REMOVE_BACK_IN_STOCK_SUBSCRIPTION, + REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR, + REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, +} from '../constants'; + +const initialState = { + isFetching: false, + isInitial: true, + subscriptions: [], +}; + +/** + * @param {Object} state The application state. + * @param {Object} action The redux action. + * @returns {Object} + */ +export default (state = initialState, action) => { + switch (action.type) { + case FETCH_BACK_IN_STOCK_SUBSCRIPTIONS: { + return { + ...state, + isFetching: true, + }; + } + case FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS: { + return { + ...state, + isInitial: false, + isFetching: false, + subscriptions: action.subscriptions, + }; + } + case FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR: { + return { + ...state, + isFetching: false, + }; + } + + case ADD_BACK_IN_STOCK_SUBSCRIPTION: { + return { + ...state, + isFetching: true, + }; + } + case ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS: { + return { + ...state, + isFetching: false, + }; + } + case ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR: { + return { + ...state, + isFetching: false, + }; + } + + case REMOVE_BACK_IN_STOCK_SUBSCRIPTION: { + return { + ...state, + isFetching: true, + }; + } + case REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS: { + return { + ...state, + isFetching: false, + }; + } + case REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR: { + return { + ...state, + isFetching: false, + }; + } + default: + return state; + } +}; diff --git a/libraries/engage/back-in-stock/selectors/backInStock.js b/libraries/engage/back-in-stock/selectors/backInStock.js new file mode 100644 index 0000000000..b865e4a748 --- /dev/null +++ b/libraries/engage/back-in-stock/selectors/backInStock.js @@ -0,0 +1,78 @@ +import { createSelector } from 'reselect'; +import { getProductVariants } from '@shopgate/pwa-common-commerce/product'; +import isEqual from 'lodash/isEqual'; + +/** + * @param {Object} state The application state. + * @returns {Object} + */ +export const getBackInStockSubscriptions = state => state.backInStock.subscriptions; + +/** + * @param {Object} state The application state. + * @returns {Object} + */ +export const getBackInStockSubscriptionsFetching = state => state.backInStock.isFetching; + +/** + * @param {Object} state The application state. + * @returns {Object} + */ +export const getBackInStockSubscriptionsInitial = state => state.backInStock.isInitial; + +/** + * Creates a selector that retrieves the subscription of a product / variant or null + * @returns {Function} + */ +export const getSubscriptionByVariant = createSelector( + (state, props = {}) => (props.variantId ? props.variantId : props.productId), + getBackInStockSubscriptions, + (variantId, subscriptions) => { + if (!variantId) { + return false; + } + + return subscriptions.find(({ productCode }) => + productCode === variantId) || null; + } +); + +/** + * Creates a selector that retrieves if a specific product is already on the Back in Stock list + * @returns {Function} + */ +export const getSubscriptionByCharacteristics = createSelector( + getProductVariants, + (state, props = {}) => props.characteristics, + getBackInStockSubscriptions, + (variants, characteristics, subscriptions) => { + if (!variants) { + return false; + } + + const found = variants.products.find(product => + isEqual(product.characteristics, characteristics)); + + if (!found) { + return null; + } + + return subscriptions.find(({ productCode }) => + productCode === found.id) || null; + } +); + +/** + * Returns if the back in stock feature is enabled + * @returns {Function} + */ +export const getIsBackInStockEnabled = () => true; + +/** + * Returns if subscription list is in use + * @returns {Function} + */ +export const getHasBackInStockSubscriptions = createSelector( + getBackInStockSubscriptions, + subscriptions => !!subscriptions.length +); diff --git a/libraries/engage/back-in-stock/streams/index.js b/libraries/engage/back-in-stock/streams/index.js new file mode 100644 index 0000000000..a25b77f46f --- /dev/null +++ b/libraries/engage/back-in-stock/streams/index.js @@ -0,0 +1,23 @@ +import { appDidStart$, main$, routeDidEnter$ } from '@shopgate/pwa-common/streams'; +import { productWillEnter$ } from '@shopgate/pwa-common-commerce/product'; +import { + ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + BACK_IN_STOCK_PATTERN, + REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, +} from '../constants'; + +export const backInStockRemindersDidEnter$ = routeDidEnter$ + .filter(({ action }) => action.route.pattern === BACK_IN_STOCK_PATTERN); + +export const addBackInStockReminderSuccess$ = main$ + .filter(({ action }) => action.type === ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS); + +export const removeBackInStockReminderSuccess$ = main$ + .filter(({ action }) => action.type === REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS); + +export const backInStockReminderNeedsFetch$ = addBackInStockReminderSuccess$.merge( + appDidStart$, + removeBackInStockReminderSuccess$, + backInStockRemindersDidEnter$, + productWillEnter$ +); diff --git a/libraries/engage/back-in-stock/subscriptions/index.js b/libraries/engage/back-in-stock/subscriptions/index.js new file mode 100644 index 0000000000..5d3fe173f1 --- /dev/null +++ b/libraries/engage/back-in-stock/subscriptions/index.js @@ -0,0 +1,25 @@ +import showModal from '@shopgate/pwa-common/actions/modal/showModal'; +import { + addBackInStockReminderSuccess$, + backInStockReminderNeedsFetch$, +} from '../streams'; +import { fetchBackInStoreSubscriptions } from '../actions'; + +/** + * @param {Function} subscribe The subscribe function. + */ +export default function backInStock(subscribe) { + subscribe(backInStockReminderNeedsFetch$, ({ dispatch }) => { + dispatch(fetchBackInStoreSubscriptions()); + }); + + subscribe(addBackInStockReminderSuccess$, ({ dispatch }) => { + dispatch(showModal({ + title: 'back_in_stock.add_back_in_stock_success_modal.title', + message: 'back_in_stock.add_back_in_stock_success_modal.message', + confirm: 'modal.confirm', + dismiss: null, + })); + }); +} + diff --git a/libraries/engage/components/index.js b/libraries/engage/components/index.js index 9eae962f62..df93926466 100644 --- a/libraries/engage/components/index.js +++ b/libraries/engage/components/index.js @@ -158,6 +158,7 @@ export { default as UncheckedIcon } from '@shopgate/pwa-ui-shared/icons/Unchecke export { default as ViewListIcon } from '@shopgate/pwa-ui-shared/icons/ViewListIcon'; export { default as VisibilityIcon } from '@shopgate/pwa-ui-shared/icons/VisibilityIcon'; export { default as VisibilityOffIcon } from '@shopgate/pwa-ui-shared/icons/VisibilityOffIcon'; +export { default as NotificationIcon } from '@shopgate/pwa-ui-shared/icons/NotificationIcon'; // LOCAL export { default as NavigationHandler } from './NavigationHandler'; diff --git a/libraries/engage/core/actions/grantPermissions.js b/libraries/engage/core/actions/grantPermissions.js index 29dafeae67..7a07caa889 100644 --- a/libraries/engage/core/actions/grantPermissions.js +++ b/libraries/engage/core/actions/grantPermissions.js @@ -46,7 +46,7 @@ const grantPermissions = (options = {}) => dispatch => new Promise(async (resolv let status; - // Check the current status of the camera permissions. + // Check the current status of the requested permission. [{ status }] = await getAppPermissions([permissionId]); // Stop the process when the permission type is not supported. diff --git a/libraries/engage/core/actions/grantPushPermissions.js b/libraries/engage/core/actions/grantPushPermissions.js new file mode 100644 index 0000000000..3fdd7b7384 --- /dev/null +++ b/libraries/engage/core/actions/grantPushPermissions.js @@ -0,0 +1,59 @@ +import { + PERMISSION_ID_PUSH, + STATUS_GRANTED, +} from '@shopgate/pwa-core/constants/AppPermissions'; +import showModal from '@shopgate/pwa-common/actions/modal/showModal'; +import { getAppPermissions } from '@shopgate/pwa-core'; +import grantPermissions from './grantPermissions'; + +/** + * Determines the current state of the push permissions. + * If not already happened, the user will be prompted to grant permissions. + * The action returns a promise which resolves with a boolean value, that indicates the state. + * @param {Object} options Action options. + * @param {boolean} [options.useSettingsModal=false] Whether in case of declined permissions a modal + * shall be presented, which redirects to the app settings. + * @param {Object} [options.modal={}] Options for the settings modal. + * @param {string} options.modal.title Modal title. + * @param {string} options.modal.message Modal message. + * @param {string} options.modal.confirm Label for the confirm button. + * @param {string} options.modal.dismiss Label for the dismiss button. + * @param {Object} options.modal.params Additional parameters for i18n strings. + * @return { Function } A redux thunk. + */ +const grantPushPermissions = (options = {}) => dispatch => new Promise(async (resolve) => { + const { useSettingsModal = true, modal = {} } = options; + const [{ status }] = await getAppPermissions([PERMISSION_ID_PUSH]); + + if (status === STATUS_GRANTED) { + resolve(true); + return; + } + + const openSettings = await dispatch(showModal({ + message: 'permissions.push_notifications.message', + confirm: 'permissions.push_notifications.confirm', + dismiss: 'permissions.push_notifications.dismiss', + params: {}, + })); + + if (openSettings === false) { + resolve(false); + return; + } + + const allowed = await dispatch(grantPermissions({ + permissionId: PERMISSION_ID_PUSH, + useSettingsModal, + modal: { + title: null, + message: 'permissions.access_denied.push_message', + confirm: 'permissions.access_denied.settings_button', + ...modal, + }, + })); + + resolve(allowed); +}); + +export default grantPushPermissions; diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js b/libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js new file mode 100644 index 0000000000..2fff4df6d5 --- /dev/null +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js @@ -0,0 +1,29 @@ +import { connect } from 'react-redux'; +import { + getIsBackInStockEnabled, + getSubscriptionByCharacteristics, +} from '@shopgate/engage/back-in-stock/selectors/backInStock'; +import { + getProductVariants, + getVariantAvailabilityByCharacteristics, +} from '@shopgate/pwa-common-commerce/product'; +import { addBackInStoreSubscription } from '@shopgate/engage/back-in-stock/actions'; +import grantPushPermissions from '@shopgate/engage/core/actions/grantPushPermissions'; + +/** + * @return {Object} The extended component props. + */ +const makeMapStateToProps = () => (state, props) => ({ + availability: getVariantAvailabilityByCharacteristics(state, props), + subscription: getSubscriptionByCharacteristics(state, props), + productVariants: getProductVariants(state, props), + isBackinStockEnabled: getIsBackInStockEnabled(state, props), +}); + +const mapDispatchToProps = { + addBackInStoreSubscription, + grantPushPermissions, + +}; + +export default connect(makeMapStateToProps, mapDispatchToProps); diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx b/libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx new file mode 100644 index 0000000000..6495009ca8 --- /dev/null +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx @@ -0,0 +1,70 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import BackInStockButton from '@shopgate/pwa-ui-shared/BackInStockButton'; +import { AVAILABILITY_STATE_OK } from '@shopgate/pwa-common-commerce/product'; +import isEqual from 'lodash/isEqual'; +import connect from './connector'; + +/** + * The BackInStockRow component. + * @param {Object} props The component props. + * @param {boolean} props.isBackinStockEnabled Whether the back in stock feature is enabled + * @param {Array} props.productVariants The product variants + * @param {Object} props.availability The product availability + * @param {Object} props.subscription The subscription + * @param {Object} props.characteristics The variant characteristics + * @param {Function} props.grantPushPermissions Request / Set push permission + * @return {JSX} + */ +const BackInStockRow = ({ + availability, + addBackInStoreSubscription, + productVariants, + characteristics, + isBackinStockEnabled, + grantPushPermissions, + subscription, +}) => { + const foundVariant = productVariants?.products.find(product => + isEqual(product.characteristics, characteristics)); + + if (availability?.state === AVAILABILITY_STATE_OK || + availability === null || !foundVariant || !isBackinStockEnabled) return null; + + return ( +
+ { + e.stopPropagation(); + const allowed = await grantPushPermissions(); + if (allowed) { + addBackInStoreSubscription({ productCode: foundVariant.id }); + } + }} + /> +
); +}; + +BackInStockRow.propTypes = { + addBackInStoreSubscription: PropTypes.func.isRequired, + grantPushPermissions: PropTypes.func.isRequired, + isBackinStockEnabled: PropTypes.bool.isRequired, + availability: PropTypes.shape(), + characteristics: PropTypes.shape(), + productVariants: PropTypes.shape(), + subscription: PropTypes.shape(), +}; + +BackInStockRow.defaultProps = { + availability: null, + productVariants: {}, + characteristics: {}, + subscription: null, +}; + +export default connect(BackInStockRow); diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/Sheet/index.jsx b/libraries/engage/product/components/Characteristics/Characteristic/components/Sheet/index.jsx index 5d72c7c57a..a21f81b597 100644 --- a/libraries/engage/product/components/Characteristics/Characteristic/components/Sheet/index.jsx +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/Sheet/index.jsx @@ -55,10 +55,11 @@ class CharacteristicSheet extends PureComponent { /** * @param {Object} event The event object. + * @param {string} itemId The id that was selected */ - handleItemClick = (event) => { + handleItemClick = (event, itemId) => { event.stopPropagation(); - this.props.onSelect(event.target.value); + this.props.onSelect(itemId); } /** @@ -102,6 +103,11 @@ class CharacteristicSheet extends PureComponent { rightComponent={() => this.renderAvailability(item.id)} selected={item.id === selectedValue} ref={index === selectedIndex ? this.firstSelectableItemRef : null} + productId={this.props.productId} + characteristics={{ + ...this.props.selection, + [this.props.charId]: item.id, + }} /> ))} diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx index 51d0ff218b..2b43bc5abd 100644 --- a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx @@ -2,15 +2,19 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { withForwardedRef } from '@shopgate/engage/core'; import styles from './style'; +import BackInStockRow from '../BackInStockRow'; /** * The SheetItem component. */ class SheetItem extends PureComponent { static propTypes = { + characteristics: PropTypes.shape().isRequired, item: PropTypes.shape().isRequired, + productId: PropTypes.string.isRequired, forwardedRef: PropTypes.shape(), onClick: PropTypes.func, + rightComponent: PropTypes.func, selected: PropTypes.bool, }; @@ -54,7 +58,7 @@ class SheetItem extends PureComponent { ref: forwardedRef, value: item.id, 'aria-hidden': !item.selectable, - ...item.selectable && { onClick }, + ...item.selectable && { onClick: event => onClick(event, item.id) }, }; }; @@ -62,13 +66,24 @@ class SheetItem extends PureComponent { * @returns {JSX} */ render() { - const { item, rightComponent: Right, selected } = this.props; + const { + item, + rightComponent: Right, + selected, + productId, + characteristics, + } = this.props; + const buildProps = this.buildProps(); return ( - +
+ + +
); } } diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/style.js b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/style.js index 7e879c531e..ff78bb9977 100644 --- a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/style.js +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/style.js @@ -5,7 +5,7 @@ const { colors, variables } = themeConfig; const button = css({ outline: 0, - padding: '16px 16px 16px 0', + padding: '16px 0 16px 0', textAlign: 'left', width: '100%', }); diff --git a/libraries/ui-shared/BackInStockButton/index.jsx b/libraries/ui-shared/BackInStockButton/index.jsx new file mode 100644 index 0000000000..a045c5add9 --- /dev/null +++ b/libraries/ui-shared/BackInStockButton/index.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import NotificationIcon from '@shopgate/pwa-ui-shared/icons/NotificationIcon'; +import CheckedIcon from '@shopgate/pwa-ui-shared/icons/CheckedIcon'; +import PropTypes from 'prop-types'; +import { themeConfig } from '@shopgate/pwa-common/helpers/config'; +import Link from '@shopgate/pwa-common/components/Link'; +import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; +import { i18n } from '@shopgate/engage/core'; +import styles from './style'; + +const { colors } = themeConfig; +/** + * This component renders a button to subscribe a product or a hint + * that the product is already subscribed + * @param {Object} props The component props + * @param {boolean} props.isLinkToBackInStockEnabled Whether the link to the back in + * stock page is active + * @param {Object} props.subscription The subscription + * @param {Function} props.onClick Action to subscribe the product + * @return {JSX} + */ +const BackInStockButton = ({ + onClick, + isLinkToBackInStockEnabled = false, + subscription, +}) => { + if (subscription?.status === 'active') { + return ( + + + {i18n.text('back_in_stock.we_will_remind_you')} + + ); + } + + return ( +
+ {/* eslint-disable-next-line max-len */} + {/* eslint-disable-next-line jsx-a11y/anchor-is-valid,jsx-a11y/interactive-supports-focus,jsx-a11y/click-events-have-key-events */} + +
+ + {i18n.text('back_in_stock.get_notified')} +
+
+
); +}; + +BackInStockButton.propTypes = { + onClick: PropTypes.func.isRequired, + isLinkToBackInStockEnabled: PropTypes.bool, + subscription: PropTypes.shape(), +}; + +BackInStockButton.defaultProps = { + isLinkToBackInStockEnabled: false, + subscription: null, +}; + +export default BackInStockButton; diff --git a/libraries/ui-shared/BackInStockButton/style.js b/libraries/ui-shared/BackInStockButton/style.js new file mode 100644 index 0000000000..36e510a3a6 --- /dev/null +++ b/libraries/ui-shared/BackInStockButton/style.js @@ -0,0 +1,33 @@ +import { css } from 'glamor'; +import { themeConfig } from '@shopgate/pwa-common/helpers/config'; + +export default { + button: css({ + marginTop: '4px', + color: themeConfig.colors.primary, + textDecoration: 'underline', + }).toString(), + buttonContent: css({ + display: 'flex', + alignItems: 'center', + }).toString(), + backInStockMessageContainer: css({ + marginTop: '4px', + display: 'inline', + alignItems: 'center', + }).toString(), + backInStockMessage: css({ + marginLeft: '4px', + verticalAlign: 'middle', + textDecoration: 'underline', + }).toString(), + buttonText: css({ + marginLeft: '4px', + textDecoration: 'underline', + }).toString(), + icon: css({ + verticalAlign: 'middle', + display: 'inline', + }).toString(), + +}; diff --git a/libraries/ui-shared/icons/NotificationIcon.jsx b/libraries/ui-shared/icons/NotificationIcon.jsx new file mode 100644 index 0000000000..ad760858fd --- /dev/null +++ b/libraries/ui-shared/icons/NotificationIcon.jsx @@ -0,0 +1,12 @@ +import React from 'react'; +import Icon from '@shopgate/pwa-common/components/Icon'; +import { themeConfig } from '@shopgate/pwa-common/helpers/config'; + +/** + * The description icon component. + * @param {Object} props The icon component properties. + * @returns {JSX} + */ +const Notification = props => ; + +export default Notification; diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/connector.js b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/connector.js new file mode 100644 index 0000000000..7da82ca1de --- /dev/null +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/connector.js @@ -0,0 +1,13 @@ +import { connect } from 'react-redux'; +import { getHasBackInStockSubscriptions } from '@shopgate/engage/back-in-stock/selectors/backInStock'; + +/** + * Maps the contents of the state to the component props. + * @param {Object} state The application state. + * @return {Object} + */ +const mapStateToProps = state => ({ + visible: getHasBackInStockSubscriptions(state), +}); + +export default connect(mapStateToProps); diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/index.jsx b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/index.jsx new file mode 100644 index 0000000000..ae13a45e62 --- /dev/null +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/index.jsx @@ -0,0 +1,13 @@ +import React, { memo } from 'react'; +import connect from './connector'; +import styles from './style'; + +/** + * @param {number} visible Whether or not the user has back in stock subscriptions. + * @returns {JSX} + */ +const BackInStockButtonBadge = ({ visible }) => ( + (visible > 0) && +); + +export default connect(memo(BackInStockButtonBadge)); diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/style.js b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/style.js new file mode 100644 index 0000000000..adfff771fe --- /dev/null +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/style.js @@ -0,0 +1,16 @@ +import { css } from 'glamor'; +import { themeConfig } from '@shopgate/pwa-common/helpers/config'; + +const { colors } = themeConfig; + +export default css({ + background: colors.primary, + borderRadius: '50%', + content: ' ', + display: 'block', + height: 8, + position: 'absolute', + right: 21, + top: 23, + width: 8, +}); diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx new file mode 100644 index 0000000000..b49fb9f9b8 --- /dev/null +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx @@ -0,0 +1,44 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import { + NAV_MENU_BACK_IN_STOCK, + NAV_MENU_BACK_IN_STOCK_AFTER, + NAV_MENU_BACK_IN_STOCK_BEFORE, +} from '@shopgate/pwa-common/constants/Portals'; +import Portal from '@shopgate/pwa-common/components/Portal'; +import NotificationIcon from '@shopgate/pwa-ui-shared/icons/NotificationIcon'; +import { NavDrawer } from '@shopgate/pwa-ui-material'; +import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; +import navDrawerConnect from '../../../../connector'; +import portalProps from '../../../../portalProps'; +import Badge from './components/Badge'; + +const LABEL = 'navigation.back_in_stock'; + +/** + * @param {Function} navigate The navigate action. + * @returns {JSX} + */ +const BackInStockButton = ({ navigate }) => ( + + + + + + + +); + +BackInStockButton.propTypes = { + navigate: PropTypes.func.isRequired, +}; + +// Combine two different connectors to reuse the existing functionality. +export default navDrawerConnect(BackInStockButton); diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/connector.js b/themes/theme-gmd/components/NavDrawer/components/Main/connector.js new file mode 100644 index 0000000000..da6973512e --- /dev/null +++ b/themes/theme-gmd/components/NavDrawer/components/Main/connector.js @@ -0,0 +1,12 @@ +import { connect } from 'react-redux'; +import { getIsBackInStockEnabled } from '@shopgate/engage/back-in-stock/selectors/backInStock'; + +/** + * @param {Object} state The application state. + * @return {Object} + */ +const mapStateToProps = state => ({ + isBackInStockEnabled: getIsBackInStockEnabled(state), +}); + +export default connect(mapStateToProps); diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/index.jsx b/themes/theme-gmd/components/NavDrawer/components/Main/index.jsx index 0b06b86049..128957f5be 100644 --- a/themes/theme-gmd/components/NavDrawer/components/Main/index.jsx +++ b/themes/theme-gmd/components/NavDrawer/components/Main/index.jsx @@ -1,23 +1,32 @@ import React from 'react'; import { NavDrawer } from '@shopgate/pwa-ui-material'; import appConfig from '@shopgate/pwa-common/helpers/config'; +import PropTypes from 'prop-types'; import HomeButton from './components/HomeButton'; import CategoryButton from './components/CategoryButton'; import FavoritesButton from './components/FavoritesButton'; import CartButton from './components/CartButton'; import ScannerButton from './components/ScannerButton'; +import BackInStockButton from './components/BackInStockButton'; +import connect from './connector'; /** + * @param {boolean} isBackinStockEnabled Whether the back in stock feature is enabled * @return {JSX} */ -const MainSection = () => ( +const MainSection = ({ isBackInStockEnabled }) => ( {appConfig.hasFavorites && } + {isBackInStockEnabled && } ); -export default MainSection; +MainSection.propTypes = { + isBackInStockEnabled: PropTypes.bool.isRequired, +}; + +export default connect(MainSection); diff --git a/themes/theme-gmd/extension-config.json b/themes/theme-gmd/extension-config.json index 1909e289ab..fc74d3e863 100644 --- a/themes/theme-gmd/extension-config.json +++ b/themes/theme-gmd/extension-config.json @@ -417,7 +417,8 @@ "unchecked": "", "viewList": "", "visibility": "", - "visibilityOff": "" + "visibilityOff": "", + "notification": "" }, "assets": {}, "pages": [] diff --git a/themes/theme-gmd/extension-config.schema.json b/themes/theme-gmd/extension-config.schema.json index c6b1cb4efb..0022f56707 100644 --- a/themes/theme-gmd/extension-config.schema.json +++ b/themes/theme-gmd/extension-config.schema.json @@ -408,6 +408,9 @@ }, "visibilityOff": { "$ref": "#/definitions/icon" + }, + "notification": { + "$ref": "#/definitions/icon" } } }, diff --git a/themes/theme-gmd/locale/de-DE.json b/themes/theme-gmd/locale/de-DE.json index 65e980e192..5336010439 100644 --- a/themes/theme-gmd/locale/de-DE.json +++ b/themes/theme-gmd/locale/de-DE.json @@ -19,7 +19,21 @@ "shipping": "Versand", "reviews": "Bewertungen", "favorites": "Merkliste", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Auf Lager Erinnerungen" + }, + "back_in_stock": { + "list_states": { + "active": "Aktiv Erinnerungen", + "past": "Abgelaufene Erinnerungen" + }, + "empty_list_reminder": "Sie haben keine Erinnerungen in dieser Liste.", + "get_notified": "Erinnere mich", + "we_will_remind_you": "Sie werden benachrichtigt.", + "add_back_in_stock_success_modal": { + "title": "Erinnerung hinzugefügt!", + "message": "Wir werden Ihnen eine Push Nachricht senden wenn das Produkt wieder verfügbar ist. Sie können Ihre Erinnerungen in den Einstellungen verwalten." + } }, "favorites": { "add": "Zur Merkliste hinzufügen", @@ -239,6 +253,7 @@ "more": "Mehr", "about": "Über uns" }, + "back_in_stock": "Auf Lager Erinnerungen", "back": "Zurück zu {title}", "open_menu": "Menü öffnen" }, @@ -268,9 +283,15 @@ } }, "permissions": { + "push_notifications": { + "message": "Bitte erlauben Sie Push Nachrichten im nächsten Schritt damit wir Sie Benachrichtigen können wenn das Produkt wieder auf Lager ist.", + "confirm": "Push Nachrichten erlauben", + "dismiss": "Abbrechen" + }, "access_denied": { "settings_button": "Zu den Einstellungen", "camera_message": "Diese Funktion benötigt Zugriff auf die Kamera. Bitte erlauben Sie den Zugriff in den Einstellungen.", + "push_message": "Dieser Service benötigt Ihre Berechtigung für Push Nachrichten. Bitte erlauben Sie den Zugriff in den Einstellungen.", "geolocation_message": "Wir benötigen Zugriff auf den Standort um Filialen in der Nähe zu zeigen." } }, diff --git a/themes/theme-gmd/locale/en-US.json b/themes/theme-gmd/locale/en-US.json index 21f9d7a383..a3f5f474b1 100644 --- a/themes/theme-gmd/locale/en-US.json +++ b/themes/theme-gmd/locale/en-US.json @@ -19,7 +19,21 @@ "shipping": "Shipping", "reviews": "Reviews", "favorites": "Favorites", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Back in Stock Reminders" + }, + "back_in_stock": { + "list_states": { + "active": "Active reminders", + "past": "Past reminders" + }, + "empty_list_reminder": "You don't have reminders in this list.", + "get_notified": "Get notified", + "we_will_remind_you": "We will remind you.", + "add_back_in_stock_success_modal": { + "title": "Back-in-Stock reminder added!", + "message": "We will send you a push notification when the product is back in stock. You can manage your notifications in the settings." + } }, "favorites": { "add": "Add to favorites list", @@ -227,6 +241,7 @@ "my_orders": "My orders", "cart": "Shopping cart", "scanner": "Scanner", + "back_in_stock": "Back in Stock reminder", "shipping": "Shipping methods", "about": "Contact us", "payment": "Payment methods", @@ -268,9 +283,15 @@ } }, "permissions": { + "push_notifications": { + "message": "Please allow push notifications in the next step, so that we can send you a notification when the product is back in stock.", + "confirm": "Allow push notifications", + "dismiss": "Cancel" + }, "access_denied": { "settings_button": "Go to settings", "camera_message": "This feature requires access to your camera. Please allow access in the settings.", + "push_message": "This feature requires access to push notifications. Please allow access in the settings.", "geolocation_message": "To find stores near you, please go to Settings and enable location permissions." } }, diff --git a/themes/theme-gmd/pages/BackInStock/components/AppBar/index.jsx b/themes/theme-gmd/pages/BackInStock/components/AppBar/index.jsx new file mode 100644 index 0000000000..db6a07743d --- /dev/null +++ b/themes/theme-gmd/pages/BackInStock/components/AppBar/index.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { BackBar } from 'Components/AppBar/presets'; + +/** + * The BackInStockAppBar component. + * @returns {JSX} + */ +function BackInStockAppBar() { + return ( + + ); +} + +export default BackInStockAppBar; diff --git a/themes/theme-gmd/pages/BackInStock/index.jsx b/themes/theme-gmd/pages/BackInStock/index.jsx new file mode 100644 index 0000000000..938d5b5c49 --- /dev/null +++ b/themes/theme-gmd/pages/BackInStock/index.jsx @@ -0,0 +1,24 @@ +import { View } from '@shopgate/engage/components'; +import React from 'react'; +import { i18n } from '@shopgate/engage/core'; +import { BackBar } from 'Components/AppBar/presets'; +import { AppBar } from '@shopgate/pwa-ui-ios'; +import { BackInStockReminders } from '@shopgate/engage/back-in-stock'; + +/** + * The BackInStockPage component. + * @returns {JSX} + */ +const BackInStockPage = () => ( + + + } + /> + + +); + +export default BackInStockPage; diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js new file mode 100644 index 0000000000..4d04145b22 --- /dev/null +++ b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js @@ -0,0 +1,26 @@ +import { connect } from 'react-redux'; +import { + getIsBackInStockEnabled, + getSubscriptionByCharacteristics, +} from '@shopgate/engage/back-in-stock/selectors/backInStock'; +import { + getProductVariants, + getVariantAvailabilityByCharacteristics, +} from '@shopgate/pwa-common-commerce/product'; +import { addBackInStoreSubscription } from '@shopgate/engage/back-in-stock/actions'; + +/** + * @return {Object} The extended component props. + */ +const makeMapStateToProps = () => (state, props) => ({ + subscription: getSubscriptionByCharacteristics(state, props), + availability: getVariantAvailabilityByCharacteristics(state, props), + productVariants: getProductVariants(state, props), + isBackinStockEnabled: getIsBackInStockEnabled(state, props), +}); + +const mapDispatchToProps = { + addBackInStoreSubscription, +}; + +export default connect(makeMapStateToProps, mapDispatchToProps); diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx new file mode 100644 index 0000000000..da868962d9 --- /dev/null +++ b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx @@ -0,0 +1,69 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import BackInStockButton from '@shopgate/pwa-ui-shared/BackInStockButton'; +import { AVAILABILITY_STATE_OK } from '@shopgate/pwa-common-commerce/product'; +import isEqual from 'lodash/isEqual'; +import connect from './connector'; + +/** + * The BackInStockRow component. + * @param {Object} props The component props. + * @param {boolean} props.isBackinStockEnabled Whether the back in stock feature is enabled + * @param {Array} props.productVariants The product variants + * @param {Object} props.availability The product availability + * @param {Object} props.characteristics The variant characteristics + * @param {Object} props.subscription The subscription + * @param {Function} props.grantPushPermissions Request / Set push permission + * @return {JSX} + */ +const BackInStockRow = ({ + availability, + addBackInStoreSubscription, + productVariants, + characteristics, + isBackinStockEnabled, + subscription, + grantPushPermissions, +}) => { + const foundVariant = productVariants?.products.find(product => + isEqual(product.characteristics, characteristics)); + + if (availability?.state === AVAILABILITY_STATE_OK || + availability === null || !foundVariant || !isBackinStockEnabled) return null; + + return ( +
+ { + const allowed = await grantPushPermissions(); + if (allowed) { + addBackInStoreSubscription({ productCode: foundVariant.id }); + } + }} + /> +
); +}; + +BackInStockRow.propTypes = { + addBackInStoreSubscription: PropTypes.func.isRequired, + grantPushPermissions: PropTypes.func.isRequired, + isBackinStockEnabled: PropTypes.bool.isRequired, + availability: PropTypes.shape(), + characteristics: PropTypes.shape(), + productVariants: PropTypes.shape(), + subscription: PropTypes.shape(), +}; + +BackInStockRow.defaultProps = { + availability: null, + productVariants: {}, + characteristics: {}, + subscription: null, +}; + +export default connect(BackInStockRow); diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/Sheet/index.jsx b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/Sheet/index.jsx index 5d72c7c57a..a21f81b597 100644 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/Sheet/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/Sheet/index.jsx @@ -55,10 +55,11 @@ class CharacteristicSheet extends PureComponent { /** * @param {Object} event The event object. + * @param {string} itemId The id that was selected */ - handleItemClick = (event) => { + handleItemClick = (event, itemId) => { event.stopPropagation(); - this.props.onSelect(event.target.value); + this.props.onSelect(itemId); } /** @@ -102,6 +103,11 @@ class CharacteristicSheet extends PureComponent { rightComponent={() => this.renderAvailability(item.id)} selected={item.id === selectedValue} ref={index === selectedIndex ? this.firstSelectableItemRef : null} + productId={this.props.productId} + characteristics={{ + ...this.props.selection, + [this.props.charId]: item.id, + }} /> ))} diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/index.jsx b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/index.jsx index 51d0ff218b..7a79e67c1a 100644 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/index.jsx @@ -1,6 +1,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { withForwardedRef } from '@shopgate/engage/core'; +import BackInStockRow from '../BackInStockRow'; import styles from './style'; /** @@ -8,7 +9,9 @@ import styles from './style'; */ class SheetItem extends PureComponent { static propTypes = { + characteristics: PropTypes.shape().isRequired, item: PropTypes.shape().isRequired, + productId: PropTypes.string.isRequired, forwardedRef: PropTypes.shape(), onClick: PropTypes.func, rightComponent: PropTypes.func, @@ -54,7 +57,7 @@ class SheetItem extends PureComponent { ref: forwardedRef, value: item.id, 'aria-hidden': !item.selectable, - ...item.selectable && { onClick }, + ...item.selectable && { onClick: event => onClick(event, item.id) }, }; }; @@ -62,12 +65,19 @@ class SheetItem extends PureComponent { * @returns {JSX} */ render() { - const { item, rightComponent: Right, selected } = this.props; + const { + item, + rightComponent: Right, + selected, + productId, + characteristics, + } = this.props; return ( ); } diff --git a/themes/theme-gmd/pages/Product/components/Header/components/BackInStock/connector.js b/themes/theme-gmd/pages/Product/components/Header/components/BackInStock/connector.js new file mode 100644 index 0000000000..71fa323fed --- /dev/null +++ b/themes/theme-gmd/pages/Product/components/Header/components/BackInStock/connector.js @@ -0,0 +1,27 @@ +import { connect } from 'react-redux'; +import { + getIsBackInStockEnabled, + getSubscriptionByVariant, +} from '@shopgate/engage/back-in-stock/selectors/backInStock'; +import { + getProductAvailability, + getProductType, +} from '@shopgate/pwa-common-commerce/product'; +import { addBackInStoreSubscription } from '@shopgate/engage/back-in-stock/actions'; +import grantPushPermissions from '@shopgate/engage/core/actions/grantPushPermissions'; +/** + * @return {Object} The extended component props. + */ +const makeMapStateToProps = () => (state, props) => ({ + subscription: getSubscriptionByVariant(state, props), + productType: getProductType(state, props), + stock: getProductAvailability(state, props), + isBackinStockEnabled: getIsBackInStockEnabled(state, props), +}); + +const mapDispatchToProps = { + addBackInStoreSubscription, + grantPushPermissions, +}; + +export default connect(makeMapStateToProps, mapDispatchToProps); diff --git a/themes/theme-gmd/pages/Product/components/Header/components/BackInStock/index.jsx b/themes/theme-gmd/pages/Product/components/Header/components/BackInStock/index.jsx new file mode 100644 index 0000000000..d69bcd93fb --- /dev/null +++ b/themes/theme-gmd/pages/Product/components/Header/components/BackInStock/index.jsx @@ -0,0 +1,72 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import Portal from '@shopgate/pwa-common/components/Portal'; +import * as portals from '@shopgate/pwa-common-commerce/product/constants/Portals'; +import BackInStockButton from '@shopgate/pwa-ui-shared/BackInStockButton'; +import { AVAILABILITY_STATE_OK } from '@shopgate/pwa-common-commerce/product'; +import connect from './connector'; + +/** + * The BackInStock component. + * @param {Object} props The component props. + * @param {boolean} props.isBackinStockEnabled Whether the back in stock feature is enabled + * @param {string} props.productId The product id + * @param {string} props.productType The product type + * @param {Object} props.stock The product stock info + * @param {Function} props.addBackInStoreSubscription Add product to back in stock list + * @param {Function} props.grantPushPermissions Request / Set push permission + * @param {Object} props.subscription The subscription + * @return {JSX} + */ +const BackInStock = ({ + productType, + stock, + productId, + addBackInStoreSubscription, + isBackinStockEnabled, + grantPushPermissions, + subscription, +}) => { + const showBackInStock = productType !== 'parent' && + productType !== null && + stock?.state !== AVAILABILITY_STATE_OK && + isBackinStockEnabled; + + return ( + + + + {showBackInStock && + { + const allowed = await grantPushPermissions(); + if (allowed) { + addBackInStoreSubscription({ productCode: productId }); + } + }} + />} + + + + ); +}; + +BackInStock.propTypes = { + addBackInStoreSubscription: PropTypes.func.isRequired, + grantPushPermissions: PropTypes.func.isRequired, + isBackinStockEnabled: PropTypes.bool.isRequired, + productId: PropTypes.string.isRequired, + productType: PropTypes.string, + stock: PropTypes.shape(), + subscription: PropTypes.shape(), +}; + +BackInStock.defaultProps = { + subscription: null, + productType: null, + stock: null, +}; + +export default connect(BackInStock); diff --git a/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx b/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx index 12b8b0cf63..1d9a1b701d 100644 --- a/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx @@ -13,6 +13,7 @@ import { import Shipping from '@shopgate/engage/product/components/Header/Shipping'; import Tiers from '@shopgate/engage/product/components/Header/Tiers'; import PriceStriked from '@shopgate/engage/product/components/Header/PriceStriked'; +import BackInStock from '../BackInStock'; import Manufacturer from '../Manufacturer'; import Availability from '../Availability'; import Price from '../Price'; @@ -25,7 +26,7 @@ import * as styles from './style'; * @param {Object} props The component props. * @returns {JSX} */ -const ProductInfo = ({ productId, options }) => ( +const ProductInfo = ({ productId, options, variantId }) => ( @@ -58,6 +59,9 @@ const ProductInfo = ({ productId, options }) => (
+
+ +
@@ -86,6 +90,11 @@ const ProductInfo = ({ productId, options }) => ( ProductInfo.propTypes = { options: PropTypes.shape().isRequired, productId: PropTypes.string.isRequired, + variantId: PropTypes.string, +}; + +ProductInfo.defaultProps = { + variantId: null, }; export default memo(ProductInfo); diff --git a/themes/theme-gmd/pages/Product/components/Header/index.jsx b/themes/theme-gmd/pages/Product/components/Header/index.jsx index e61967f1d1..5b41ac97b2 100644 --- a/themes/theme-gmd/pages/Product/components/Header/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Header/index.jsx @@ -29,7 +29,7 @@ class ProductHeader extends PureComponent {
- +
); diff --git a/themes/theme-gmd/pages/index.jsx b/themes/theme-gmd/pages/index.jsx index 138aa54111..02b3908a72 100644 --- a/themes/theme-gmd/pages/index.jsx +++ b/themes/theme-gmd/pages/index.jsx @@ -41,6 +41,7 @@ import { ThemeContext } from '@shopgate/pwa-common/context'; import { APP_GLOBALS } from '@shopgate/pwa-common/constants/Portals'; import Viewport from 'Components/Viewport'; import Dialog from '@shopgate/pwa-ui-shared/Dialog'; +import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; import * as routes from './routes'; import { routesTransforms } from './routesTransforms'; import themeApi from '../themeApi'; @@ -112,6 +113,11 @@ const Pages = ({ store }) => ( cache transform={routesTransforms[SEARCH_PATTERN]} /> + import('./Search')); export const Login = lazy(() => import('./Login')); export const WriteReview = lazy(() => import('./WriteReview')); export const Scanner = lazy(() => import('./Scanner')); +export const BackInStock = lazy(() => import('./BackInStock')); diff --git a/themes/theme-gmd/pages/subscribers.js b/themes/theme-gmd/pages/subscribers.js index 06ca103646..9230011979 100644 --- a/themes/theme-gmd/pages/subscribers.js +++ b/themes/theme-gmd/pages/subscribers.js @@ -14,6 +14,8 @@ import commerceProduct from '@shopgate/pwa-common-commerce/product/subscriptions import commerceReviews from '@shopgate/pwa-common-commerce/reviews/subscriptions'; import commerceSearch from '@shopgate/pwa-common-commerce/search/subscriptions'; import commerceScanner from '@shopgate/pwa-common-commerce/scanner/subscriptions'; +// Engage +import engageBackInStock from '@shopgate/engage/back-in-stock/subscriptions'; // PWA Tracking import trackingSetup from '@shopgate/pwa-tracking/subscriptions/setup'; import trackingPages from '@shopgate/pwa-tracking/subscriptions/pages'; @@ -72,6 +74,8 @@ const subscriptions = [ commerceReviews, commerceSearch, commerceScanner, + // Engage subscribers + engageBackInStock, // App rating subscribers appRating, // Theme subscribers. diff --git a/themes/theme-ios11/extension-config.json b/themes/theme-ios11/extension-config.json index fc740904ef..cf9e40f6b2 100644 --- a/themes/theme-ios11/extension-config.json +++ b/themes/theme-ios11/extension-config.json @@ -416,7 +416,8 @@ "unchecked": "", "viewList": "", "visibility": "", - "visibilityOff": "" + "visibilityOff": "", + "notification": "" }, "assets": {}, "pages": [] diff --git a/themes/theme-ios11/extension-config.schema.json b/themes/theme-ios11/extension-config.schema.json index 707ebe2458..c1335f8938 100644 --- a/themes/theme-ios11/extension-config.schema.json +++ b/themes/theme-ios11/extension-config.schema.json @@ -412,6 +412,9 @@ }, "visibilityOff": { "$ref": "#/definitions/icon" + }, + "notification": { + "$ref": "#/definitions/icon" } } }, diff --git a/themes/theme-ios11/locale/de-DE.json b/themes/theme-ios11/locale/de-DE.json index fa8d969445..4f7d24b808 100644 --- a/themes/theme-ios11/locale/de-DE.json +++ b/themes/theme-ios11/locale/de-DE.json @@ -20,7 +20,21 @@ "reviews": "Bewertungen", "browse": "Durchsuchen", "favorites": "Merkliste", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Auf Lager Erinnerungen" + }, + "back_in_stock": { + "list_states": { + "active": "Aktiv Erinnerungen", + "past": "Abgelaufene Erinnerungen" + }, + "empty_list_reminder": "Sie haben keine Erinnerungen in dieser Liste.", + "get_notified": "Erinnere mich", + "we_will_remind_you": "Sie werden benachrichtigt.", + "add_back_in_stock_success_modal": { + "title": "Erinnerung hinzugefügt!", + "message": "Wir werden Ihnen eine Push Nachricht senden wenn das Produkt wieder verfügbar ist. Sie können Ihre Erinnerungen in den Einstellungen verwalten." + } }, "favorites": { "add": "Zur Merkliste hinzufügen", @@ -240,6 +254,7 @@ "logout": "Abmelden", "store_information": "Über uns", "more_menu": "Mehr", + "back_in_stock": "Auf Lager Erinnerungen", "back": "Zurück zu {title}" }, "reviews": { @@ -275,9 +290,15 @@ } }, "permissions": { + "push_notifications": { + "message": "Bitte erlauben Sie Push Nachrichten im nächsten Schritt damit wir Sie Benachrichtigen können wenn das Produkt wieder auf Lager ist.", + "confirm": "Push Nachrichten erlauben", + "dismiss": "Abbrechen" + }, "access_denied": { "settings_button": "Zu den Einstellungen", "camera_message": "Diese Funktion benötigt Zugriff auf die Kamera. Bitte erlauben Sie den Zugriff in den Einstellungen.", + "push_message": "Dieser Service benötigt Ihre Berechtigung für Push Nachrichten. Bitte erlauben Sie den Zugriff in den Einstellungen.", "geolocation_message": "Wir benötigen Zugriff auf den Standort um Filialen in der Nähe zu zeigen." } }, diff --git a/themes/theme-ios11/locale/en-US.json b/themes/theme-ios11/locale/en-US.json index 4f816deb9c..6b5df91e39 100644 --- a/themes/theme-ios11/locale/en-US.json +++ b/themes/theme-ios11/locale/en-US.json @@ -20,7 +20,21 @@ "reviews": "Reviews", "browse": "Browse", "favorites": "Favorites", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Back in Stock Reminders" + }, + "back_in_stock": { + "list_states": { + "active": "Active reminders", + "past": "Past reminders" + }, + "empty_list_reminder": "You don't have reminders in this list.", + "get_notified": "Get notified", + "we_will_remind_you": "We will remind you.", + "add_back_in_stock_success_modal": { + "title": "Back-in-Stock reminder added!", + "message": "We will send you a push notification when the product is back in stock. You can manage your notifications in the settings." + } }, "favorites": { "add": "Add to favorites list", @@ -239,6 +253,7 @@ "logout": "Logout", "store_information": "Store Information", "more_menu": "More", + "back_in_stock": "Back in Stock reminder", "back": "Back to {title}" }, "reviews": { @@ -274,9 +289,15 @@ } }, "permissions": { + "push_notifications": { + "message": "Please allow push notifications in the next step, so that we can send you a notification when the product is back in stock.", + "confirm": "Allow push notifications", + "dismiss": "Cancel" + }, "access_denied": { "settings_button": "Go to settings", "camera_message": "This feature requires access to your camera. Please allow access in the settings.", + "push_message": "This feature requires access to push notifications. Please allow access in the settings.", "geolocation_message": "To find stores near you, please go to Settings and enable location permissions." } }, diff --git a/themes/theme-ios11/pages/BackInStock/components/AppBar/index.jsx b/themes/theme-ios11/pages/BackInStock/components/AppBar/index.jsx new file mode 100644 index 0000000000..9dfe5e7fbe --- /dev/null +++ b/themes/theme-ios11/pages/BackInStock/components/AppBar/index.jsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { BackBar } from 'Components/AppBar/presets'; +import CartButton from 'Components/AppBar/components/CartButton'; + +/** + * The BackInStockAppBar component. + * @returns {JSX} + */ +function BackInStockAppBar() { + return ( + } /> + ); +} + +export default BackInStockAppBar; diff --git a/themes/theme-ios11/pages/BackInStock/index.jsx b/themes/theme-ios11/pages/BackInStock/index.jsx new file mode 100644 index 0000000000..938d5b5c49 --- /dev/null +++ b/themes/theme-ios11/pages/BackInStock/index.jsx @@ -0,0 +1,24 @@ +import { View } from '@shopgate/engage/components'; +import React from 'react'; +import { i18n } from '@shopgate/engage/core'; +import { BackBar } from 'Components/AppBar/presets'; +import { AppBar } from '@shopgate/pwa-ui-ios'; +import { BackInStockReminders } from '@shopgate/engage/back-in-stock'; + +/** + * The BackInStockPage component. + * @returns {JSX} + */ +const BackInStockPage = () => ( + + + } + /> + + +); + +export default BackInStockPage; diff --git a/themes/theme-ios11/pages/More/components/Quicklinks/connector.js b/themes/theme-ios11/pages/More/components/Quicklinks/connector.js index 78a6cef099..d32860be9e 100644 --- a/themes/theme-ios11/pages/More/components/Quicklinks/connector.js +++ b/themes/theme-ios11/pages/More/components/Quicklinks/connector.js @@ -1,6 +1,7 @@ import { connect } from 'react-redux'; import { QUICKLINKS_MENU } from '@shopgate/pwa-common/constants/MenuIDs'; import { getMenuById } from '@shopgate/pwa-common/selectors/menu'; +import { getIsBackInStockEnabled } from '@shopgate/engage/back-in-stock/selectors/backInStock'; const props = { id: QUICKLINKS_MENU, @@ -13,6 +14,7 @@ const props = { */ const mapStateToProps = state => ({ entries: getMenuById(state, props), + isBackInStockEnabled: getIsBackInStockEnabled(state, props), }); export default connect(mapStateToProps); diff --git a/themes/theme-ios11/pages/More/components/Quicklinks/index.jsx b/themes/theme-ios11/pages/More/components/Quicklinks/index.jsx index 144c5c9b9a..c6e735dfe6 100644 --- a/themes/theme-ios11/pages/More/components/Quicklinks/index.jsx +++ b/themes/theme-ios11/pages/More/components/Quicklinks/index.jsx @@ -6,6 +6,7 @@ import { import { NAV_MENU_QUICK_LINKS, } from '@shopgate/pwa-common/constants/Portals'; +import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; import portalProps from '../../portalProps'; import Section from '../Section'; @@ -15,17 +16,22 @@ import connect from './connector'; * The Quicklinks component. * @param {Object} props The component props. * @param {Array} props.entries The quicklinks. + * @param {boolean} props.isBackInStockEnabled Whether back in stock is enabled. * @returns {JSX} */ -function Quicklinks({ entries }) { - if (!entries || !entries.length) { +function Quicklinks({ entries, isBackInStockEnabled }) { + const allEntries = isBackInStockEnabled ? + [...entries, { url: BACK_IN_STOCK_PATTERN, label: 'navigation.back_in_stock', key: 'back_in_stock' }] : + [...entries]; + + if (!allEntries || !allEntries.length) { return null; } return (
- {entries.map(entry => ( + {allEntries.map(entry => ( ))}
@@ -34,6 +40,7 @@ function Quicklinks({ entries }) { } Quicklinks.propTypes = { + isBackInStockEnabled: PropTypes.bool.isRequired, entries: PropTypes.arrayOf(PropTypes.shape()), }; diff --git a/themes/theme-ios11/pages/Product/components/Header/components/BackInStock/connector.js b/themes/theme-ios11/pages/Product/components/Header/components/BackInStock/connector.js new file mode 100644 index 0000000000..e41fb35a15 --- /dev/null +++ b/themes/theme-ios11/pages/Product/components/Header/components/BackInStock/connector.js @@ -0,0 +1,28 @@ +import { connect } from 'react-redux'; +import { + getIsBackInStockEnabled, + getSubscriptionByVariant, +} from '@shopgate/engage/back-in-stock/selectors/backInStock'; +import { + getProductAvailability, + getProductType, +} from '@shopgate/pwa-common-commerce/product'; +import { addBackInStoreSubscription } from '@shopgate/engage/back-in-stock/actions'; +import grantPushPermissions from '@shopgate/engage/core/actions/grantPushPermissions'; + +/** + * @return {Object} The extended component props. + */ +const makeMapStateToProps = () => (state, props) => ({ + subscription: getSubscriptionByVariant(state, props), + productType: getProductType(state, props), + stock: getProductAvailability(state, props), + isBackinStockEnabled: getIsBackInStockEnabled(state, props), +}); + +const mapDispatchToProps = { + addBackInStoreSubscription, + grantPushPermissions, +}; + +export default connect(makeMapStateToProps, mapDispatchToProps); diff --git a/themes/theme-ios11/pages/Product/components/Header/components/BackInStock/index.jsx b/themes/theme-ios11/pages/Product/components/Header/components/BackInStock/index.jsx new file mode 100644 index 0000000000..d69bcd93fb --- /dev/null +++ b/themes/theme-ios11/pages/Product/components/Header/components/BackInStock/index.jsx @@ -0,0 +1,72 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import Portal from '@shopgate/pwa-common/components/Portal'; +import * as portals from '@shopgate/pwa-common-commerce/product/constants/Portals'; +import BackInStockButton from '@shopgate/pwa-ui-shared/BackInStockButton'; +import { AVAILABILITY_STATE_OK } from '@shopgate/pwa-common-commerce/product'; +import connect from './connector'; + +/** + * The BackInStock component. + * @param {Object} props The component props. + * @param {boolean} props.isBackinStockEnabled Whether the back in stock feature is enabled + * @param {string} props.productId The product id + * @param {string} props.productType The product type + * @param {Object} props.stock The product stock info + * @param {Function} props.addBackInStoreSubscription Add product to back in stock list + * @param {Function} props.grantPushPermissions Request / Set push permission + * @param {Object} props.subscription The subscription + * @return {JSX} + */ +const BackInStock = ({ + productType, + stock, + productId, + addBackInStoreSubscription, + isBackinStockEnabled, + grantPushPermissions, + subscription, +}) => { + const showBackInStock = productType !== 'parent' && + productType !== null && + stock?.state !== AVAILABILITY_STATE_OK && + isBackinStockEnabled; + + return ( + + + + {showBackInStock && + { + const allowed = await grantPushPermissions(); + if (allowed) { + addBackInStoreSubscription({ productCode: productId }); + } + }} + />} + + + + ); +}; + +BackInStock.propTypes = { + addBackInStoreSubscription: PropTypes.func.isRequired, + grantPushPermissions: PropTypes.func.isRequired, + isBackinStockEnabled: PropTypes.bool.isRequired, + productId: PropTypes.string.isRequired, + productType: PropTypes.string, + stock: PropTypes.shape(), + subscription: PropTypes.shape(), +}; + +BackInStock.defaultProps = { + subscription: null, + productType: null, + stock: null, +}; + +export default connect(BackInStock); diff --git a/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx b/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx index 12b8b0cf63..0d1af184b9 100644 --- a/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx +++ b/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx @@ -20,12 +20,13 @@ import PriceInfo from '../PriceInfo'; import TaxDisclaimer from '../TaxDisclaimer'; import StockInfo from '../StockInfo'; import * as styles from './style'; +import BackInStock from '../BackInStock'; /** * @param {Object} props The component props. * @returns {JSX} */ -const ProductInfo = ({ productId, options }) => ( +const ProductInfo = ({ productId, options, variantId }) => ( @@ -58,6 +59,9 @@ const ProductInfo = ({ productId, options }) => (
+
+ +
@@ -86,6 +90,7 @@ const ProductInfo = ({ productId, options }) => ( ProductInfo.propTypes = { options: PropTypes.shape().isRequired, productId: PropTypes.string.isRequired, + variantId: PropTypes.string.isRequired, }; export default memo(ProductInfo); diff --git a/themes/theme-ios11/pages/Product/components/Header/index.jsx b/themes/theme-ios11/pages/Product/components/Header/index.jsx index e61967f1d1..5b41ac97b2 100644 --- a/themes/theme-ios11/pages/Product/components/Header/index.jsx +++ b/themes/theme-ios11/pages/Product/components/Header/index.jsx @@ -29,7 +29,7 @@ class ProductHeader extends PureComponent {
- +
); diff --git a/themes/theme-ios11/pages/index.jsx b/themes/theme-ios11/pages/index.jsx index 31a5bbeafb..4042bd58f1 100644 --- a/themes/theme-ios11/pages/index.jsx +++ b/themes/theme-ios11/pages/index.jsx @@ -38,6 +38,7 @@ import { APP_GLOBALS } from '@shopgate/pwa-common/constants/Portals'; import { BROWSE_PATH } from 'Pages/Browse/constants'; import Viewport from 'Components/Viewport'; import Dialog from '@shopgate/pwa-ui-shared/Dialog'; +import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock/constants'; import themeApi from '../themeApi'; import * as routes from './routes'; import { routesTransforms } from './routesTransforms'; @@ -96,13 +97,13 @@ const Pages = ({ store }) => ( transform={routesTransforms[MORE_PATH]} /> { - appConfig.hasFavorites - && - } + appConfig.hasFavorites + && + } ( transform={routesTransforms[SEARCH_FILTER_PATTERN]} /> + {React.Children.map(routePortals, Component => Component)} @@ -126,7 +131,6 @@ const Pages = ({ store }) => ( ); - Pages.propTypes = { store: PropTypes.shape().isRequired, }; diff --git a/themes/theme-ios11/pages/reducers.js b/themes/theme-ios11/pages/reducers.js index 4661aaefc7..9f14c265e8 100644 --- a/themes/theme-ios11/pages/reducers.js +++ b/themes/theme-ios11/pages/reducers.js @@ -4,6 +4,7 @@ import { configuration, RESET_APP_REDUCERS, } from '@shopgate/engage/core'; +import backInStock from '@shopgate/engage/back-in-stock/reducers'; import client from '@shopgate/pwa-common/reducers/client'; import url from '@shopgate/pwa-common/reducers/url'; import user from '@shopgate/pwa-common/reducers/user'; @@ -45,6 +46,7 @@ const reducers = combineReducers({ router, cart, category, + backInStock, client, ...extensions && { extensions: combineReducers(extensions) }, favorites, diff --git a/themes/theme-ios11/pages/routes.js b/themes/theme-ios11/pages/routes.js index ab2ebd559e..04417c6095 100644 --- a/themes/theme-ios11/pages/routes.js +++ b/themes/theme-ios11/pages/routes.js @@ -15,3 +15,4 @@ export const WriteReview = lazy(() => import('./WriteReview')); export const Browse = lazy(() => import('./Browse')); export const More = lazy(() => import('./More')); export const Scanner = lazy(() => import('./Scanner')); +export const BackInStock = lazy(() => import('./BackInStock')); diff --git a/themes/theme-ios11/pages/subscribers.js b/themes/theme-ios11/pages/subscribers.js index a99b467531..88c756ef0e 100644 --- a/themes/theme-ios11/pages/subscribers.js +++ b/themes/theme-ios11/pages/subscribers.js @@ -14,6 +14,8 @@ import commerceProduct from '@shopgate/pwa-common-commerce/product/subscriptions import commerceReviews from '@shopgate/pwa-common-commerce/reviews/subscriptions'; import commerceSearch from '@shopgate/pwa-common-commerce/search/subscriptions'; import commerceScanner from '@shopgate/pwa-common-commerce/scanner/subscriptions'; +// Engage +import engageBackInStock from '@shopgate/engage/back-in-stock/subscriptions'; // PWA Tracking import trackingSetup from '@shopgate/pwa-tracking/subscriptions/setup'; import trackingPages from '@shopgate/pwa-tracking/subscriptions/pages'; @@ -74,6 +76,8 @@ const subscriptions = [ commerceReviews, commerceSearch, commerceScanner, + // Engage subscribers + engageBackInStock, // App rating subscribers appRating, // Theme subscribers. From a4a03e794959f4fa303e01553b23c027a1387d37 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Fri, 2 Feb 2024 12:57:51 +0100 Subject: [PATCH 02/55] CURB-3886 Some fixes and rework. --- .../commerce/favorites/constants/Pipelines.js | 3 ++ .../engage/back-in-stock/actions/index.js | 45 ++++++++++--------- .../components/BackInStock/BackInStock.jsx | 2 +- .../components/Subscription/connector.js | 2 +- .../components/Subscription/index.jsx | 6 ++- libraries/engage/back-in-stock/hooks/index.js | 2 +- ...kInStockSubscriptionsProvider.connector.js | 7 +-- .../back-in-stock/selectors/backInStock.js | 6 ++- .../core/actions/grantPushPermissions.js | 6 +-- themes/theme-gmd/locale/de-DE.json | 4 +- themes/theme-gmd/locale/en-US.json | 2 +- themes/theme-ios11/locale/de-DE.json | 4 +- themes/theme-ios11/locale/en-US.json | 2 +- 13 files changed, 52 insertions(+), 39 deletions(-) diff --git a/libraries/commerce/favorites/constants/Pipelines.js b/libraries/commerce/favorites/constants/Pipelines.js index 0a6242577e..617fc05b0a 100644 --- a/libraries/commerce/favorites/constants/Pipelines.js +++ b/libraries/commerce/favorites/constants/Pipelines.js @@ -6,3 +6,6 @@ export const SHOPGATE_USER_GET_FAVORITES_LIST = 'shopgate.user.getFavoritesLists export const SHOPGATE_USER_ADD_FAVORITES_LIST = 'shopgate.user.addFavoritesList'; export const SHOPGATE_USER_UPDATE_FAVORITES_LIST = 'shopgate.user.updateFavoritesList'; export const SHOPGATE_USER_REMOVE_FAVORITES_LIST = 'shopgate.user.removeFavoritesList'; +export const SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS = 'shopgate.user.getBackInStockSubscriptions'; +export const SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTIONS = 'shopgate.user.addBackInStockSubscription'; +export const SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTIONS = 'shopgate.user.removeBackInStockSubscription'; diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index 4a28ad0982..d1dbadcb61 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -1,4 +1,8 @@ import { PipelineRequest } from '@shopgate/engage/core'; +import { + SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTIONS, SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTIONS, + SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS, +} from '@shopgate/pwa-common-commerce/favorites'; import { ADD_BACK_IN_STOCK_SUBSCRIPTION, ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, @@ -12,19 +16,20 @@ import { } from '../constants'; /** - * Fetches Back in Stock Subscriptions + * Fetch Back in Stock Subscriptions * @returns {Function} */ export const fetchBackInStoreSubscriptions = () => async (dispatch) => { dispatch({ type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS }); try { - const { subscriptions } = await new PipelineRequest('shopgate.user.getBackInStockSubscriptions') - .setInput({ - limit: 100, - offset: 100, - }) - .dispatch(); + const { subscriptions } = + await new PipelineRequest(SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS) + .setInput({ + limit: 100, + offset: 0, + }) + .dispatch(); dispatch({ type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, @@ -43,7 +48,7 @@ export const fetchBackInStoreSubscriptions = () => async (dispatch) => { }; /** - * Add a Back in Stock Subscription + * Add a Back in Stock Subscription * @param {Object} props Props. * @param {string} props.productCode The product for which the subscription should be added * @returns {Function} @@ -52,11 +57,12 @@ export const addBackInStoreSubscription = ({ productCode }) => async (dispatch) dispatch({ type: ADD_BACK_IN_STOCK_SUBSCRIPTION }); try { - const { subscriptions } = await new PipelineRequest('shopgate.user.addBackInStockSubscription') - .setInput({ - productCode, - }) - .dispatch(); + const { subscriptions } = + await new PipelineRequest(SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTIONS) + .setInput({ + productCode, + }) + .dispatch(); dispatch({ type: ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, @@ -82,14 +88,13 @@ export const addBackInStoreSubscription = ({ productCode }) => async (dispatch) export const removeBackInStoreSubscription = ({ subscriptionCode }) => async (dispatch) => { dispatch({ type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION }); - const pipelineRequest = new PipelineRequest('shopgate.user.removeBackInStockSubscription'); - try { - const { subscriptions } = await pipelineRequest - .setInput({ - subscriptionCode, - }) - .dispatch(); + const { subscriptions } = + await new PipelineRequest(SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTIONS) + .setInput({ + subscriptionCode, + }) + .dispatch(); dispatch({ type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, diff --git a/libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx b/libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx index 05e7020e08..c8b32c2c95 100644 --- a/libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx +++ b/libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import BackInStockSubscriptionsProvider from '../../providers/BackInStockSubscriptionsProvider'; +import BackInStockSubscriptionsProvider from '@shopgate/engage/back-in-stock/providers/BackInStockSubscriptionsProvider'; import List from '../List'; /** diff --git a/libraries/engage/back-in-stock/components/Subscription/connector.js b/libraries/engage/back-in-stock/components/Subscription/connector.js index 9f090e0b66..7ea17fb689 100644 --- a/libraries/engage/back-in-stock/components/Subscription/connector.js +++ b/libraries/engage/back-in-stock/components/Subscription/connector.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { addBackInStoreSubscription } from '@shopgate/engage/back-in-stock/actions'; -import { getSubscriptionByVariant } from '../../selectors/backInStock'; +import { getSubscriptionByVariant } from '@shopgate/engage/back-in-stock/selectors/backInStock'; /** * @return {Object} The extended component props. diff --git a/libraries/engage/back-in-stock/components/Subscription/index.jsx b/libraries/engage/back-in-stock/components/Subscription/index.jsx index 8109415062..600c4c2ffb 100644 --- a/libraries/engage/back-in-stock/components/Subscription/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscription/index.jsx @@ -15,8 +15,10 @@ import { themeConfig } from '@shopgate/pwa-common/helpers/config'; import CrossIcon from '@shopgate/pwa-ui-shared/icons/CrossIcon'; import AvailableText from '@shopgate/pwa-ui-shared/Availability'; import BackInStockButton from '@shopgate/pwa-ui-shared/BackInStockButton'; -import { useBackInStockSubscriptionsContext } from '../../hooks'; -import { getThemeSettings, i18n } from '../../../core'; +import { + getThemeSettings, i18n, +} from '@shopgate/engage/core'; +import { useBackInStockSubscriptionsContext } from '@shopgate/engage/back-in-stock/hooks'; const { variables } = themeConfig; diff --git a/libraries/engage/back-in-stock/hooks/index.js b/libraries/engage/back-in-stock/hooks/index.js index 5875be74f0..ea23447a8e 100644 --- a/libraries/engage/back-in-stock/hooks/index.js +++ b/libraries/engage/back-in-stock/hooks/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import BackInStockSubscriptionsProvider from '../providers/BackInStockSubscriptionsProvider.context'; +import BackInStockSubscriptionsProvider from '@shopgate/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.context'; /** * Injects the Back in Stock Subscription Context diff --git a/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js index 800f8dc487..fda8bb0526 100644 --- a/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js +++ b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js @@ -1,12 +1,13 @@ import { connect } from 'react-redux'; import { getBackInStockSubscriptions, - getBackInStockSubscriptionsFetching, getBackInStockSubscriptionsInitial, -} from '../selectors/backInStock'; + getBackInStockSubscriptionsFetching, + getBackInStockSubscriptionsInitial, +} from '@shopgate/engage/back-in-stock/selectors/backInStock'; import { addBackInStoreSubscription, removeBackInStoreSubscription, -} from '../actions'; +} from '@shopgate/engage/back-in-stock/actions'; /** * @return {Function} The extended component props. diff --git a/libraries/engage/back-in-stock/selectors/backInStock.js b/libraries/engage/back-in-stock/selectors/backInStock.js index b865e4a748..b7b3a23e17 100644 --- a/libraries/engage/back-in-stock/selectors/backInStock.js +++ b/libraries/engage/back-in-stock/selectors/backInStock.js @@ -21,7 +21,8 @@ export const getBackInStockSubscriptionsFetching = state => state.backInStock.is export const getBackInStockSubscriptionsInitial = state => state.backInStock.isInitial; /** - * Creates a selector that retrieves the subscription of a product / variant or null + * Creates a selector that retrieves the subscription of + * a product / variant or null by its variantId / productId * @returns {Function} */ export const getSubscriptionByVariant = createSelector( @@ -38,7 +39,8 @@ export const getSubscriptionByVariant = createSelector( ); /** - * Creates a selector that retrieves if a specific product is already on the Back in Stock list + * Creates a selector that retrieves the subscription of + * a product / variant by its characteristics * @returns {Function} */ export const getSubscriptionByCharacteristics = createSelector( diff --git a/libraries/engage/core/actions/grantPushPermissions.js b/libraries/engage/core/actions/grantPushPermissions.js index 3fdd7b7384..8eb87f3143 100644 --- a/libraries/engage/core/actions/grantPushPermissions.js +++ b/libraries/engage/core/actions/grantPushPermissions.js @@ -31,9 +31,9 @@ const grantPushPermissions = (options = {}) => dispatch => new Promise(async (re } const openSettings = await dispatch(showModal({ - message: 'permissions.push_notifications.message', - confirm: 'permissions.push_notifications.confirm', - dismiss: 'permissions.push_notifications.dismiss', + message: 'permissions.back_in_stock_push_notifications.message', + confirm: 'permissions.back_in_stock_push_notifications.confirm', + dismiss: 'permissions.back_in_stock_push_notifications.dismiss', params: {}, })); diff --git a/themes/theme-gmd/locale/de-DE.json b/themes/theme-gmd/locale/de-DE.json index 5336010439..cbaf7e5785 100644 --- a/themes/theme-gmd/locale/de-DE.json +++ b/themes/theme-gmd/locale/de-DE.json @@ -24,7 +24,7 @@ }, "back_in_stock": { "list_states": { - "active": "Aktiv Erinnerungen", + "active": "Aktive Erinnerungen", "past": "Abgelaufene Erinnerungen" }, "empty_list_reminder": "Sie haben keine Erinnerungen in dieser Liste.", @@ -283,7 +283,7 @@ } }, "permissions": { - "push_notifications": { + "back_in_stock_push_notifications": { "message": "Bitte erlauben Sie Push Nachrichten im nächsten Schritt damit wir Sie Benachrichtigen können wenn das Produkt wieder auf Lager ist.", "confirm": "Push Nachrichten erlauben", "dismiss": "Abbrechen" diff --git a/themes/theme-gmd/locale/en-US.json b/themes/theme-gmd/locale/en-US.json index a3f5f474b1..e139e8ed6c 100644 --- a/themes/theme-gmd/locale/en-US.json +++ b/themes/theme-gmd/locale/en-US.json @@ -283,7 +283,7 @@ } }, "permissions": { - "push_notifications": { + "back_in_stock_push_notifications": { "message": "Please allow push notifications in the next step, so that we can send you a notification when the product is back in stock.", "confirm": "Allow push notifications", "dismiss": "Cancel" diff --git a/themes/theme-ios11/locale/de-DE.json b/themes/theme-ios11/locale/de-DE.json index 4f7d24b808..825fab86af 100644 --- a/themes/theme-ios11/locale/de-DE.json +++ b/themes/theme-ios11/locale/de-DE.json @@ -25,7 +25,7 @@ }, "back_in_stock": { "list_states": { - "active": "Aktiv Erinnerungen", + "active": "Aktive Erinnerungen", "past": "Abgelaufene Erinnerungen" }, "empty_list_reminder": "Sie haben keine Erinnerungen in dieser Liste.", @@ -290,7 +290,7 @@ } }, "permissions": { - "push_notifications": { + "back_in_stock_push_notifications": { "message": "Bitte erlauben Sie Push Nachrichten im nächsten Schritt damit wir Sie Benachrichtigen können wenn das Produkt wieder auf Lager ist.", "confirm": "Push Nachrichten erlauben", "dismiss": "Abbrechen" diff --git a/themes/theme-ios11/locale/en-US.json b/themes/theme-ios11/locale/en-US.json index 6b5df91e39..ef5c65b6a7 100644 --- a/themes/theme-ios11/locale/en-US.json +++ b/themes/theme-ios11/locale/en-US.json @@ -289,7 +289,7 @@ } }, "permissions": { - "push_notifications": { + "back_in_stock_push_notifications": { "message": "Please allow push notifications in the next step, so that we can send you a notification when the product is back in stock.", "confirm": "Allow push notifications", "dismiss": "Cancel" From 82f22380ec06469caba686f5636b598df1f4552a Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 7 Feb 2024 09:30:36 +0100 Subject: [PATCH 03/55] CURB-3886 Remove / rename backinstock constants --- libraries/commerce/favorites/constants/Pipelines.js | 3 --- libraries/engage/back-in-stock/actions/index.js | 13 +++++++------ libraries/engage/back-in-stock/constants/Portals.js | 3 +++ 3 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 libraries/engage/back-in-stock/constants/Portals.js diff --git a/libraries/commerce/favorites/constants/Pipelines.js b/libraries/commerce/favorites/constants/Pipelines.js index 617fc05b0a..0a6242577e 100644 --- a/libraries/commerce/favorites/constants/Pipelines.js +++ b/libraries/commerce/favorites/constants/Pipelines.js @@ -6,6 +6,3 @@ export const SHOPGATE_USER_GET_FAVORITES_LIST = 'shopgate.user.getFavoritesLists export const SHOPGATE_USER_ADD_FAVORITES_LIST = 'shopgate.user.addFavoritesList'; export const SHOPGATE_USER_UPDATE_FAVORITES_LIST = 'shopgate.user.updateFavoritesList'; export const SHOPGATE_USER_REMOVE_FAVORITES_LIST = 'shopgate.user.removeFavoritesList'; -export const SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS = 'shopgate.user.getBackInStockSubscriptions'; -export const SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTIONS = 'shopgate.user.addBackInStockSubscription'; -export const SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTIONS = 'shopgate.user.removeBackInStockSubscription'; diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index d1dbadcb61..f2be5424ee 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -1,8 +1,4 @@ import { PipelineRequest } from '@shopgate/engage/core'; -import { - SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTIONS, SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTIONS, - SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS, -} from '@shopgate/pwa-common-commerce/favorites'; import { ADD_BACK_IN_STOCK_SUBSCRIPTION, ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, @@ -14,6 +10,11 @@ import { REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR, REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, } from '../constants'; +import { + SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION, + SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION, + SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS, +} from '../constants/Portals'; /** * Fetch Back in Stock Subscriptions @@ -58,7 +59,7 @@ export const addBackInStoreSubscription = ({ productCode }) => async (dispatch) try { const { subscriptions } = - await new PipelineRequest(SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTIONS) + await new PipelineRequest(SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION) .setInput({ productCode, }) @@ -90,7 +91,7 @@ export const removeBackInStoreSubscription = ({ subscriptionCode }) => async (di try { const { subscriptions } = - await new PipelineRequest(SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTIONS) + await new PipelineRequest(SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION) .setInput({ subscriptionCode, }) diff --git a/libraries/engage/back-in-stock/constants/Portals.js b/libraries/engage/back-in-stock/constants/Portals.js new file mode 100644 index 0000000000..b51efef76f --- /dev/null +++ b/libraries/engage/back-in-stock/constants/Portals.js @@ -0,0 +1,3 @@ +export const SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS = 'shopgate.user.getBackInStockSubscriptions'; +export const SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION = 'shopgate.user.addBackInStockSubscription'; +export const SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION = 'shopgate.user.removeBackInStockSubscription'; From f074f26c42bfeab07be274900be1610f80491d43 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 7 Feb 2024 09:36:44 +0100 Subject: [PATCH 04/55] CURB-3886 Rename productCode to productId --- libraries/engage/back-in-stock/actions/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index f2be5424ee..1796a26102 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -51,17 +51,17 @@ export const fetchBackInStoreSubscriptions = () => async (dispatch) => { /** * Add a Back in Stock Subscription * @param {Object} props Props. - * @param {string} props.productCode The product for which the subscription should be added + * @param {string} props.productId The product for which the subscription should be added * @returns {Function} */ -export const addBackInStoreSubscription = ({ productCode }) => async (dispatch) => { +export const addBackInStoreSubscription = ({ productId }) => async (dispatch) => { dispatch({ type: ADD_BACK_IN_STOCK_SUBSCRIPTION }); try { const { subscriptions } = await new PipelineRequest(SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION) .setInput({ - productCode, + productCode: productId, }) .dispatch(); From 327ac83c710454416d877bae559bca2efbf8d897 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 7 Feb 2024 09:52:47 +0100 Subject: [PATCH 05/55] CURB-3886 Refactor back-in-stock components folder --- .../{ => Subscriptions/components}/List/index.jsx | 7 ++----- .../components}/Subscription/connector.js | 0 .../{ => Subscriptions/components}/Subscription/index.jsx | 7 +++---- .../BackInStock.jsx => Subscriptions/index.jsx} | 8 ++++---- 4 files changed, 9 insertions(+), 13 deletions(-) rename libraries/engage/back-in-stock/components/{ => Subscriptions/components}/List/index.jsx (94%) rename libraries/engage/back-in-stock/components/{ => Subscriptions/components}/Subscription/connector.js (100%) rename libraries/engage/back-in-stock/components/{ => Subscriptions/components}/Subscription/index.jsx (95%) rename libraries/engage/back-in-stock/components/{BackInStock/BackInStock.jsx => Subscriptions/index.jsx} (65%) diff --git a/libraries/engage/back-in-stock/components/List/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx similarity index 94% rename from libraries/engage/back-in-stock/components/List/index.jsx rename to libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx index 09b11b76d5..80bef734bf 100644 --- a/libraries/engage/back-in-stock/components/List/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx @@ -1,12 +1,9 @@ import React from 'react'; import { css } from 'glamor'; import LoadingIndicator from '@shopgate/pwa-ui-shared/LoadingIndicator'; -import { - Accordion, - Card, -} from '@shopgate/engage/components'; +import { Accordion, Card } from '@shopgate/engage/components'; import { i18n } from '@shopgate/engage/core'; -import { useBackInStockSubscriptionsContext } from '../../hooks'; +import { useBackInStockSubscriptionsContext } from '../../../../hooks'; import Subscription from '../Subscription'; const styles = { diff --git a/libraries/engage/back-in-stock/components/Subscription/connector.js b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js similarity index 100% rename from libraries/engage/back-in-stock/components/Subscription/connector.js rename to libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js diff --git a/libraries/engage/back-in-stock/components/Subscription/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx similarity index 95% rename from libraries/engage/back-in-stock/components/Subscription/index.jsx rename to libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx index 600c4c2ffb..70a9a1a604 100644 --- a/libraries/engage/back-in-stock/components/Subscription/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx @@ -4,15 +4,14 @@ import { Link, Ripple, PriceInfo, + CrossIcon, } from '@shopgate/engage/components'; -import { getProductRoute } from '@shopgate/pwa-common-commerce/product'; -import { ProductImage } from '@shopgate/engage/product'; +import { getProductRoute, ProductImage } from '@shopgate/engage/product'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import { themeConfig } from '@shopgate/engage'; import PriceStriked from '@shopgate/pwa-ui-shared/PriceStriked'; import Price from '@shopgate/pwa-ui-shared/Price'; -import { themeConfig } from '@shopgate/pwa-common/helpers/config'; -import CrossIcon from '@shopgate/pwa-ui-shared/icons/CrossIcon'; import AvailableText from '@shopgate/pwa-ui-shared/Availability'; import BackInStockButton from '@shopgate/pwa-ui-shared/BackInStockButton'; import { diff --git a/libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx b/libraries/engage/back-in-stock/components/Subscriptions/index.jsx similarity index 65% rename from libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx rename to libraries/engage/back-in-stock/components/Subscriptions/index.jsx index c8b32c2c95..b241658388 100644 --- a/libraries/engage/back-in-stock/components/BackInStock/BackInStock.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/index.jsx @@ -1,15 +1,15 @@ import React from 'react'; import BackInStockSubscriptionsProvider from '@shopgate/engage/back-in-stock/providers/BackInStockSubscriptionsProvider'; -import List from '../List'; +import List from './components/List'; /** - * The Back in Stock component. + * The Back in Stock Subscriptions component. * @returns {JSX} */ -const BackInStock = () => ( +const Subscriptions = () => ( ); -export default BackInStock; +export default Subscriptions; From 42e6939e9c3a172a7f2d4ae1148576f2e5e41149 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 7 Feb 2024 10:03:15 +0100 Subject: [PATCH 06/55] CURB-3886 Refactor theme subscribers --- themes/theme-gmd/pages/subscribers.js | 5 ++--- themes/theme-ios11/pages/subscribers.js | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/themes/theme-gmd/pages/subscribers.js b/themes/theme-gmd/pages/subscribers.js index 9230011979..470cb7d9c1 100644 --- a/themes/theme-gmd/pages/subscribers.js +++ b/themes/theme-gmd/pages/subscribers.js @@ -14,8 +14,6 @@ import commerceProduct from '@shopgate/pwa-common-commerce/product/subscriptions import commerceReviews from '@shopgate/pwa-common-commerce/reviews/subscriptions'; import commerceSearch from '@shopgate/pwa-common-commerce/search/subscriptions'; import commerceScanner from '@shopgate/pwa-common-commerce/scanner/subscriptions'; -// Engage -import engageBackInStock from '@shopgate/engage/back-in-stock/subscriptions'; // PWA Tracking import trackingSetup from '@shopgate/pwa-tracking/subscriptions/setup'; import trackingPages from '@shopgate/pwa-tracking/subscriptions/pages'; @@ -43,7 +41,8 @@ import writeReview from 'Pages/WriteReview/subscriptions'; import appConfig from '@shopgate/pwa-common/helpers/config'; // Extensions import extensions from 'Extensions/subscribers'; -// App rating +// Engage +import engageBackInStock from '@shopgate/engage/back-in-stock/subscriptions'; import appRating from '@shopgate/engage/app-rating/subscriptions'; const subscriptions = [ diff --git a/themes/theme-ios11/pages/subscribers.js b/themes/theme-ios11/pages/subscribers.js index 88c756ef0e..dac164a4a0 100644 --- a/themes/theme-ios11/pages/subscribers.js +++ b/themes/theme-ios11/pages/subscribers.js @@ -14,8 +14,6 @@ import commerceProduct from '@shopgate/pwa-common-commerce/product/subscriptions import commerceReviews from '@shopgate/pwa-common-commerce/reviews/subscriptions'; import commerceSearch from '@shopgate/pwa-common-commerce/search/subscriptions'; import commerceScanner from '@shopgate/pwa-common-commerce/scanner/subscriptions'; -// Engage -import engageBackInStock from '@shopgate/engage/back-in-stock/subscriptions'; // PWA Tracking import trackingSetup from '@shopgate/pwa-tracking/subscriptions/setup'; import trackingPages from '@shopgate/pwa-tracking/subscriptions/pages'; @@ -45,7 +43,8 @@ import tabBar from 'Components/TabBar/subscriptions'; import appConfig from '@shopgate/pwa-common/helpers/config'; // Extensions import extensions from 'Extensions/subscribers'; -// App rating +// Engage +import engageBackInStock from '@shopgate/engage/back-in-stock/subscriptions'; import appRating from '@shopgate/engage/app-rating/subscriptions'; const subscriptions = [ From 891140ca1fd80ee8faecfa9e9155b5dc592fc5be Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 7 Feb 2024 10:25:17 +0100 Subject: [PATCH 07/55] CURB-3886 Refactor gmd nav_menu portals --- libraries/common/constants/Portals.js | 5 ---- .../engage/back-in-stock/actions/index.js | 2 +- .../back-in-stock/constants/Pipelines.js | 3 +++ .../engage/back-in-stock/constants/Portals.js | 23 ++++++++++++++++--- .../components/BackInStockButton/index.jsx | 10 ++++---- 5 files changed, 29 insertions(+), 14 deletions(-) create mode 100644 libraries/engage/back-in-stock/constants/Pipelines.js diff --git a/libraries/common/constants/Portals.js b/libraries/common/constants/Portals.js index 36c2d639dd..505611ce76 100644 --- a/libraries/common/constants/Portals.js +++ b/libraries/common/constants/Portals.js @@ -17,7 +17,6 @@ const QUICK_LINKS = 'quick-links'; const HOME = 'home'; const LOGIN = 'login'; const SCANNER = 'scanner'; -const BACK_IN_STOCK = 'back-in-stock'; const REGISTER_LINK = 'register-link'; const TERMS = 'terms'; const PRIVACY = 'privacy'; @@ -83,10 +82,6 @@ export const NAV_MENU_SCANNER_BEFORE = `${NAV_MENU}.${SCANNER}.${BEFORE}`; export const NAV_MENU_SCANNER = `${NAV_MENU}.${SCANNER}`; export const NAV_MENU_SCANNER_AFTER = `${NAV_MENU}.${SCANNER}.${AFTER}`; -export const NAV_MENU_BACK_IN_STOCK_BEFORE = `${NAV_MENU}.${BACK_IN_STOCK}.${BEFORE}`; -export const NAV_MENU_BACK_IN_STOCK = `${NAV_MENU}.${BACK_IN_STOCK}`; -export const NAV_MENU_BACK_IN_STOCK_AFTER = `${NAV_MENU}.${BACK_IN_STOCK}.${AFTER}`; - export const NAV_MENU_TERMS_BEFORE = `${NAV_MENU}.${TERMS}.${BEFORE}`; export const NAV_MENU_TERMS = `${NAV_MENU}.${TERMS}`; export const NAV_MENU_TERMS_AFTER = `${NAV_MENU}.${TERMS}.${AFTER}`; diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index 1796a26102..51bc4b4a87 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -14,7 +14,7 @@ import { SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION, SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION, SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS, -} from '../constants/Portals'; +} from '../constants/Pipelines'; /** * Fetch Back in Stock Subscriptions diff --git a/libraries/engage/back-in-stock/constants/Pipelines.js b/libraries/engage/back-in-stock/constants/Pipelines.js new file mode 100644 index 0000000000..b51efef76f --- /dev/null +++ b/libraries/engage/back-in-stock/constants/Pipelines.js @@ -0,0 +1,3 @@ +export const SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS = 'shopgate.user.getBackInStockSubscriptions'; +export const SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION = 'shopgate.user.addBackInStockSubscription'; +export const SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION = 'shopgate.user.removeBackInStockSubscription'; diff --git a/libraries/engage/back-in-stock/constants/Portals.js b/libraries/engage/back-in-stock/constants/Portals.js index b51efef76f..57c46ffb72 100644 --- a/libraries/engage/back-in-stock/constants/Portals.js +++ b/libraries/engage/back-in-stock/constants/Portals.js @@ -1,3 +1,20 @@ -export const SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS = 'shopgate.user.getBackInStockSubscriptions'; -export const SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION = 'shopgate.user.addBackInStockSubscription'; -export const SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION = 'shopgate.user.removeBackInStockSubscription'; +/** + * Copyright (c) 2017-present, Shopgate, Inc. All rights reserved. + * + * This source code is licensed under the Apache 2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +// FEATURES +const NAV_MENU = 'nav-menu'; + +// CONTENTS +const BACK_IN_STOCK = 'back-in-stock'; + +// POSITIONS +const BEFORE = 'before'; +const AFTER = 'after'; + +export const NAV_MENU_BACK_IN_STOCK_BEFORE = `${NAV_MENU}.${BACK_IN_STOCK}.${BEFORE}`; +export const NAV_MENU_BACK_IN_STOCK = `${NAV_MENU}.${BACK_IN_STOCK}`; +export const NAV_MENU_BACK_IN_STOCK_AFTER = `${NAV_MENU}.${BACK_IN_STOCK}.${AFTER}`; diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx index b49fb9f9b8..5c341d9ab4 100644 --- a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx @@ -1,14 +1,14 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import { - NAV_MENU_BACK_IN_STOCK, - NAV_MENU_BACK_IN_STOCK_AFTER, - NAV_MENU_BACK_IN_STOCK_BEFORE, -} from '@shopgate/pwa-common/constants/Portals'; import Portal from '@shopgate/pwa-common/components/Portal'; import NotificationIcon from '@shopgate/pwa-ui-shared/icons/NotificationIcon'; import { NavDrawer } from '@shopgate/pwa-ui-material'; import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; +import { + NAV_MENU_BACK_IN_STOCK, + NAV_MENU_BACK_IN_STOCK_AFTER, + NAV_MENU_BACK_IN_STOCK_BEFORE, +} from '@shopgate/engage/back-in-stock/constants/Portals'; import navDrawerConnect from '../../../../connector'; import portalProps from '../../../../portalProps'; import Badge from './components/Badge'; From 80de111a7608c26c5ec23a916360638627a1b014 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 7 Feb 2024 11:19:10 +0100 Subject: [PATCH 08/55] CURB-3886 Refactor back on stock portal constants --- libraries/commerce/product/constants/Portals.js | 6 ------ libraries/engage/back-in-stock/constants/Portals.js | 5 +++++ .../Header/components/BackInStock/index.jsx | 12 ++++++++---- .../Header/components/BackInStock/index.jsx | 12 ++++++++---- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/libraries/commerce/product/constants/Portals.js b/libraries/commerce/product/constants/Portals.js index 3eea4fd2cc..c7012ab58d 100644 --- a/libraries/commerce/product/constants/Portals.js +++ b/libraries/commerce/product/constants/Portals.js @@ -26,7 +26,6 @@ const MANUFACTURER = 'manufacturer'; const SHIPPING = 'shipping'; const AVAILABILITY = 'availability'; const STOCK_INFO = 'stock-info'; -const BACK_IN_STOCK = 'back-in-stock'; const PRICE_STRIKED = 'price-striked'; const PRICE = 'price'; const PRICE_INFO = 'price-info'; @@ -116,11 +115,6 @@ export const PRODUCT_STOCK_INFO_BEFORE = `${PRODUCT}.${STOCK_INFO}.${BEFORE}`; export const PRODUCT_STOCK_INFO = `${PRODUCT}.${STOCK_INFO}`; export const PRODUCT_STOCK_INFO_AFTER = `${PRODUCT}.${STOCK_INFO}.${AFTER}`; -// BACKINSTOCK INFO -export const PRODUCT_BACK_IN_STOCK_BEFORE = `${PRODUCT}.${BACK_IN_STOCK}.${BEFORE}`; -export const PRODUCT_BACK_IN_STOCK = `${PRODUCT}.${BACK_IN_STOCK}`; -export const PRODUCT_BACK_IN_STOCK_AFTER = `${PRODUCT}.${BACK_IN_STOCK}.${AFTER}`; - // PRICE STRIKED export const PRODUCT_PRICE_STRIKED_BEFORE = `${PRODUCT}.${PRICE_STRIKED}.${BEFORE}`; export const PRODUCT_PRICE_STRIKED = `${PRODUCT}.${PRICE_STRIKED}`; diff --git a/libraries/engage/back-in-stock/constants/Portals.js b/libraries/engage/back-in-stock/constants/Portals.js index 57c46ffb72..a52847bbd0 100644 --- a/libraries/engage/back-in-stock/constants/Portals.js +++ b/libraries/engage/back-in-stock/constants/Portals.js @@ -7,6 +7,7 @@ // FEATURES const NAV_MENU = 'nav-menu'; +const PRODUCT = 'product'; // CONTENTS const BACK_IN_STOCK = 'back-in-stock'; @@ -18,3 +19,7 @@ const AFTER = 'after'; export const NAV_MENU_BACK_IN_STOCK_BEFORE = `${NAV_MENU}.${BACK_IN_STOCK}.${BEFORE}`; export const NAV_MENU_BACK_IN_STOCK = `${NAV_MENU}.${BACK_IN_STOCK}`; export const NAV_MENU_BACK_IN_STOCK_AFTER = `${NAV_MENU}.${BACK_IN_STOCK}.${AFTER}`; + +export const PRODUCT_BACK_IN_STOCK_BEFORE = `${PRODUCT}.${BACK_IN_STOCK}.${BEFORE}`; +export const PRODUCT_BACK_IN_STOCK = `${PRODUCT}.${BACK_IN_STOCK}`; +export const PRODUCT_BACK_IN_STOCK_AFTER = `${PRODUCT}.${BACK_IN_STOCK}.${AFTER}`; diff --git a/themes/theme-gmd/pages/Product/components/Header/components/BackInStock/index.jsx b/themes/theme-gmd/pages/Product/components/Header/components/BackInStock/index.jsx index d69bcd93fb..b26156ef9f 100644 --- a/themes/theme-gmd/pages/Product/components/Header/components/BackInStock/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Header/components/BackInStock/index.jsx @@ -1,9 +1,13 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import Portal from '@shopgate/pwa-common/components/Portal'; -import * as portals from '@shopgate/pwa-common-commerce/product/constants/Portals'; import BackInStockButton from '@shopgate/pwa-ui-shared/BackInStockButton'; import { AVAILABILITY_STATE_OK } from '@shopgate/pwa-common-commerce/product'; +import { + PRODUCT_BACK_IN_STOCK, + PRODUCT_BACK_IN_STOCK_AFTER, + PRODUCT_BACK_IN_STOCK_BEFORE, +} from '@shopgate/engage/back-in-stock/constants/Portals'; import connect from './connector'; /** @@ -34,8 +38,8 @@ const BackInStock = ({ return ( - - + + {showBackInStock && } - + ); }; diff --git a/themes/theme-ios11/pages/Product/components/Header/components/BackInStock/index.jsx b/themes/theme-ios11/pages/Product/components/Header/components/BackInStock/index.jsx index d69bcd93fb..b26156ef9f 100644 --- a/themes/theme-ios11/pages/Product/components/Header/components/BackInStock/index.jsx +++ b/themes/theme-ios11/pages/Product/components/Header/components/BackInStock/index.jsx @@ -1,9 +1,13 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import Portal from '@shopgate/pwa-common/components/Portal'; -import * as portals from '@shopgate/pwa-common-commerce/product/constants/Portals'; import BackInStockButton from '@shopgate/pwa-ui-shared/BackInStockButton'; import { AVAILABILITY_STATE_OK } from '@shopgate/pwa-common-commerce/product'; +import { + PRODUCT_BACK_IN_STOCK, + PRODUCT_BACK_IN_STOCK_AFTER, + PRODUCT_BACK_IN_STOCK_BEFORE, +} from '@shopgate/engage/back-in-stock/constants/Portals'; import connect from './connector'; /** @@ -34,8 +38,8 @@ const BackInStock = ({ return ( - - + + {showBackInStock && } - + ); }; From d5df4e517edf348c5edfc77bd46e0922bf6a6f9f Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 7 Feb 2024 11:34:18 +0100 Subject: [PATCH 09/55] CURB-3886 Move groupedLabels in BackInStockSubscriptionsProvider --- .../Subscriptions/components/List/index.jsx | 19 ++++--------------- .../BackInStockSubscriptionsProvider.jsx | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx index 80bef734bf..16f369f3b5 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import { css } from 'glamor'; import LoadingIndicator from '@shopgate/pwa-ui-shared/LoadingIndicator'; import { Accordion, Card } from '@shopgate/engage/components'; @@ -30,25 +30,14 @@ const styles = { */ const List = () => { const { - subscriptions, isInitial, + groupedSubscriptions, } = useBackInStockSubscriptionsContext(); - const groupedSubscriptions = subscriptions.reduce((acc, subscription) => { - const { status } = subscription; - const groupingStatus = (status === 'inactive' || status === 'triggered') ? 'past' : status; - acc[groupingStatus].push(subscription); - return acc; - }, { - active: [], - past: [], - }); - - // eslint-disable-next-line require-jsdoc - const renderLabel = groupKey => + const renderLabel = useCallback(groupKey =>
{i18n.text(`back_in_stock.list_states.${groupKey}`)} -
; + , []); return (
diff --git a/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.jsx b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.jsx index ad8e5a4995..0bc91a823b 100644 --- a/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.jsx +++ b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.jsx @@ -15,15 +15,26 @@ const BackInStoreSubscriptionsProvider = ({ isInitial, removeBackInStoreSubscription, }) => { + const groupedSubscriptions = useMemo(() => subscriptions.reduce((acc, subscription) => { + const { status } = subscription; + const groupingStatus = (status === 'inactive' || status === 'triggered') ? 'past' : status; + acc[groupingStatus].push(subscription); + return acc; + }, { + active: [], + past: [], + }), [subscriptions]); + // Create memoized context value. const value = useMemo(() => ({ subscriptions, + groupedSubscriptions, addBackInStoreSubscription, removeBackInStoreSubscription, isFetching, isInitial, - }), [ - addBackInStoreSubscription, + }), [addBackInStoreSubscription, + groupedSubscriptions, isFetching, isInitial, removeBackInStoreSubscription, From b3cab93040e876a6f0da7175d571663db4abecfd Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 7 Feb 2024 12:09:04 +0100 Subject: [PATCH 10/55] CURB-3886 Refactor backinstock actions. --- .../engage/back-in-stock/actions/index.js | 122 +++++++++--------- libraries/engage/back-in-stock/index.js | 2 +- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index 51bc4b4a87..00ac1ffe33 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -20,32 +20,32 @@ import { * Fetch Back in Stock Subscriptions * @returns {Function} */ -export const fetchBackInStoreSubscriptions = () => async (dispatch) => { +export const fetchBackInStoreSubscriptions = () => (dispatch) => { dispatch({ type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS }); - try { - const { subscriptions } = - await new PipelineRequest(SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS) - .setInput({ - limit: 100, - offset: 0, - }) - .dispatch(); + const request = new PipelineRequest(SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS) + .setInput({ + limit: 100, + offset: 0, + }) + .setRetries(0) + .dispatch(); - dispatch({ - type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, - subscriptions, + request + .then(({ subscriptions }) => { + dispatch({ + type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, + subscriptions, + }); + }) + .catch((error) => { + dispatch({ + type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, + error, + }); }); - return subscriptions; - } catch (error) { - dispatch({ - type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, - error, - }); - - return null; - } + return request; }; /** @@ -54,30 +54,30 @@ export const fetchBackInStoreSubscriptions = () => async (dispatch) => { * @param {string} props.productId The product for which the subscription should be added * @returns {Function} */ -export const addBackInStoreSubscription = ({ productId }) => async (dispatch) => { +export const addBackInStoreSubscription = ({ productId }) => (dispatch) => { dispatch({ type: ADD_BACK_IN_STOCK_SUBSCRIPTION }); + const request = new PipelineRequest(SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION) + .setInput({ + productCode: productId, + }) + .setRetries(0) + .dispatch(); - try { - const { subscriptions } = - await new PipelineRequest(SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION) - .setInput({ - productCode: productId, - }) - .dispatch(); - - dispatch({ - type: ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, - subscriptions, - }); - return subscriptions; - } catch (error) { - dispatch({ - type: ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, - error, + request + .then(({ subscriptions }) => { + dispatch({ + type: ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + subscriptions, + }); + }) + .catch((error) => { + dispatch({ + type: ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, + error, + }); }); - return null; - } + return request; }; /** @@ -86,29 +86,29 @@ export const addBackInStoreSubscription = ({ productId }) => async (dispatch) => * @param {string} props.subscriptionCode The subscription which should be deleted * @returns {Function} */ -export const removeBackInStoreSubscription = ({ subscriptionCode }) => async (dispatch) => { +export const removeBackInStoreSubscription = ({ subscriptionCode }) => (dispatch) => { dispatch({ type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION }); + const request = new PipelineRequest(SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION) + .setInput({ + subscriptionCode, + }) + .setRetries(0) + .dispatch(); - try { - const { subscriptions } = - await new PipelineRequest(SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION) - .setInput({ - subscriptionCode, - }) - .dispatch(); - - dispatch({ - type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, - subscriptions, - }); - return subscriptions; - } catch (error) { - dispatch({ - type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR, - error, + request + .then(({ subscriptions }) => { + dispatch({ + type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + subscriptions, + }); + }) + .catch((error) => { + dispatch({ + type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR, + error, + }); }); - return null; - } + return request; }; diff --git a/libraries/engage/back-in-stock/index.js b/libraries/engage/back-in-stock/index.js index 323f1179f2..1b921a421d 100644 --- a/libraries/engage/back-in-stock/index.js +++ b/libraries/engage/back-in-stock/index.js @@ -2,7 +2,7 @@ export * from './constants'; // Components -export { default as BackInStockReminders } from './components/BackInStock/BackInStock'; +export { default as BackInStockReminders } from './components/Subscriptions'; // STREAMS export * from './streams'; From 78add06ccf717356848d9b6013bb374610430598 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 7 Feb 2024 12:17:28 +0100 Subject: [PATCH 11/55] CURB-3886 Remove back in stock typo --- .../engage/back-in-stock/actions/index.js | 6 ++--- .../components/Subscription/connector.js | 4 ++-- .../components/Subscription/index.jsx | 4 ++-- ...kInStockSubscriptionsProvider.connector.js | 8 +++---- .../BackInStockSubscriptionsProvider.jsx | 24 +++++++++---------- .../back-in-stock/subscriptions/index.js | 4 ++-- .../components/BackInStockRow/connector.js | 4 ++-- .../components/BackInStockRow/index.jsx | 6 ++--- .../components/BackInStockRow/connector.js | 4 ++-- .../components/BackInStockRow/index.jsx | 6 ++--- .../components/BackInStock/connector.js | 4 ++-- .../Header/components/BackInStock/index.jsx | 8 +++---- .../components/BackInStock/connector.js | 4 ++-- .../Header/components/BackInStock/index.jsx | 8 +++---- 14 files changed, 47 insertions(+), 47 deletions(-) diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index 00ac1ffe33..9c90b1730d 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -20,7 +20,7 @@ import { * Fetch Back in Stock Subscriptions * @returns {Function} */ -export const fetchBackInStoreSubscriptions = () => (dispatch) => { +export const fetchBackInStockSubscriptions = () => (dispatch) => { dispatch({ type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS }); const request = new PipelineRequest(SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS) @@ -54,7 +54,7 @@ export const fetchBackInStoreSubscriptions = () => (dispatch) => { * @param {string} props.productId The product for which the subscription should be added * @returns {Function} */ -export const addBackInStoreSubscription = ({ productId }) => (dispatch) => { +export const addBackInStockSubscription = ({ productId }) => (dispatch) => { dispatch({ type: ADD_BACK_IN_STOCK_SUBSCRIPTION }); const request = new PipelineRequest(SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION) .setInput({ @@ -86,7 +86,7 @@ export const addBackInStoreSubscription = ({ productId }) => (dispatch) => { * @param {string} props.subscriptionCode The subscription which should be deleted * @returns {Function} */ -export const removeBackInStoreSubscription = ({ subscriptionCode }) => (dispatch) => { +export const removeBackInStockSubscription = ({ subscriptionCode }) => (dispatch) => { dispatch({ type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION }); const request = new PipelineRequest(SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION) .setInput({ diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js index 7ea17fb689..e1b9455497 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { addBackInStoreSubscription } from '@shopgate/engage/back-in-stock/actions'; +import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; import { getSubscriptionByVariant } from '@shopgate/engage/back-in-stock/selectors/backInStock'; /** @@ -10,7 +10,7 @@ const makeMapStateToProps = () => (state, props) => ({ }); const mapDispatchToProps = { - addBackInStoreSubscription, + addBackInStockSubscription, }; export default connect(makeMapStateToProps, mapDispatchToProps); diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx index 70a9a1a604..34e437a18d 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx @@ -97,7 +97,7 @@ const Subscription = ({ }) => { const { subscriptionCode, product } = subscription; const { - removeBackInStoreSubscription, + removeBackInStockSubscription, } = useBackInStockSubscriptionsContext(); const { ListImage: gridResolutions } = getThemeSettings('AppImages') || {}; const currency = product.price?.currency || 'EUR'; @@ -135,7 +135,7 @@ const Subscription = ({
- +
@@ -90,11 +90,6 @@ const ProductInfo = ({ productId, options, variantId }) => ( ProductInfo.propTypes = { options: PropTypes.shape().isRequired, productId: PropTypes.string.isRequired, - variantId: PropTypes.string, -}; - -ProductInfo.defaultProps = { - variantId: null, }; export default memo(ProductInfo); diff --git a/themes/theme-gmd/pages/Product/components/Header/index.jsx b/themes/theme-gmd/pages/Product/components/Header/index.jsx index 5b41ac97b2..e61967f1d1 100644 --- a/themes/theme-gmd/pages/Product/components/Header/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Header/index.jsx @@ -29,7 +29,7 @@ class ProductHeader extends PureComponent {
- +
); diff --git a/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx b/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx index 4fec33e6d3..074e7964b3 100644 --- a/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx +++ b/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx @@ -26,7 +26,7 @@ import * as styles from './style'; * @param {Object} props The component props. * @returns {JSX} */ -const ProductInfo = ({ productId, options, variantId }) => ( +const ProductInfo = ({ productId, options }) => ( @@ -60,7 +60,7 @@ const ProductInfo = ({ productId, options, variantId }) => (
- +
@@ -90,7 +90,6 @@ const ProductInfo = ({ productId, options, variantId }) => ( ProductInfo.propTypes = { options: PropTypes.shape().isRequired, productId: PropTypes.string.isRequired, - variantId: PropTypes.string.isRequired, }; export default memo(ProductInfo); diff --git a/themes/theme-ios11/pages/Product/components/Header/index.jsx b/themes/theme-ios11/pages/Product/components/Header/index.jsx index 5b41ac97b2..e61967f1d1 100644 --- a/themes/theme-ios11/pages/Product/components/Header/index.jsx +++ b/themes/theme-ios11/pages/Product/components/Header/index.jsx @@ -29,7 +29,7 @@ class ProductHeader extends PureComponent {
- +
); From 7c74927528a1a69bf0010f528af11f973f3cd7d5 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 13 Feb 2024 10:07:11 +0100 Subject: [PATCH 16/55] CURB-3886 Merge ios/gmd characteristics --- .../components/BackInStockRow/connector.js | 26 --- .../components/BackInStockRow/index.jsx | 69 ------- .../Characteristic/components/Sheet/index.jsx | 145 --------------- .../components/SheetItem/index.jsx | 86 --------- .../components/SheetItem/style.js | 32 ---- .../VariantAvailability/connector.js | 27 --- .../components/VariantAvailability/index.jsx | 48 ----- .../components/VariantAvailability/style.js | 6 - .../Characteristics/Characteristic/index.jsx | 169 ------------------ .../Characteristics/Characteristic/style.js | 36 ---- .../Characteristics/Swatch/index.jsx | 105 ----------- .../Characteristics/Swatch/style.js | 31 ---- .../components/Characteristics/index.jsx | 87 --------- .../components/Characteristics/transition.js | 14 -- .../Product/components/Content/index.jsx | 4 +- .../Product/components/Content/index.jsx | 2 +- 16 files changed, 3 insertions(+), 884 deletions(-) delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/Sheet/index.jsx delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/index.jsx delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/style.js delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/connector.js delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/index.jsx delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/style.js delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/index.jsx delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/style.js delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Swatch/index.jsx delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/Swatch/style.js delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/index.jsx delete mode 100644 themes/theme-gmd/pages/Product/components/Characteristics/transition.js diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js deleted file mode 100644 index 462a8b41fc..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js +++ /dev/null @@ -1,26 +0,0 @@ -import { connect } from 'react-redux'; -import { - getIsBackInStockEnabled, - getSubscriptionByCharacteristics, -} from '@shopgate/engage/back-in-stock'; -import { - getProductVariants, - getVariantAvailabilityByCharacteristics, -} from '@shopgate/pwa-common-commerce/product'; -import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; - -/** - * @return {Object} The extended component props. - */ -const makeMapStateToProps = () => (state, props) => ({ - subscription: getSubscriptionByCharacteristics(state, props), - availability: getVariantAvailabilityByCharacteristics(state, props), - productVariants: getProductVariants(state, props), - isBackInStockEnabled: getIsBackInStockEnabled(state, props), -}); - -const mapDispatchToProps = { - addBackInStockSubscription, -}; - -export default connect(makeMapStateToProps, mapDispatchToProps); diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx deleted file mode 100644 index 5f3f5d3c2e..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx +++ /dev/null @@ -1,69 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { BackInStockButton } from '@shopgate/engage/back-in-stock'; -import { AVAILABILITY_STATE_OK } from '@shopgate/pwa-common-commerce/product'; -import isEqual from 'lodash/isEqual'; -import connect from './connector'; - -/** - * The BackInStockRow component. - * @param {Object} props The component props. - * @param {boolean} props.isBackInStockEnabled Whether the back in stock feature is enabled - * @param {Array} props.productVariants The product variants - * @param {Object} props.availability The product availability - * @param {Object} props.characteristics The variant characteristics - * @param {Object} props.subscription The subscription - * @param {Function} props.grantPushPermissions Request / Set push permission - * @return {JSX} - */ -const BackInStockRow = ({ - availability, - addBackInStockSubscription, - productVariants, - characteristics, - isBackInStockEnabled, - subscription, - grantPushPermissions, -}) => { - const foundVariant = productVariants?.products.find(product => - isEqual(product.characteristics, characteristics)); - - if (availability?.state === AVAILABILITY_STATE_OK || - availability === null || !foundVariant || !isBackInStockEnabled) return null; - - return ( -
- { - const allowed = await grantPushPermissions(); - if (allowed) { - addBackInStockSubscription({ productCode: foundVariant.id }); - } - }} - /> -
); -}; - -BackInStockRow.propTypes = { - addBackInStockSubscription: PropTypes.func.isRequired, - grantPushPermissions: PropTypes.func.isRequired, - isBackInStockEnabled: PropTypes.bool.isRequired, - availability: PropTypes.shape(), - characteristics: PropTypes.shape(), - productVariants: PropTypes.shape(), - subscription: PropTypes.shape(), -}; - -BackInStockRow.defaultProps = { - availability: null, - productVariants: {}, - characteristics: {}, - subscription: null, -}; - -export default connect(BackInStockRow); diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/Sheet/index.jsx b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/Sheet/index.jsx deleted file mode 100644 index a21f81b597..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/Sheet/index.jsx +++ /dev/null @@ -1,145 +0,0 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import { SheetDrawer, SheetList } from '@shopgate/engage/components'; -import { VariantContext, ProductContext } from '@shopgate/engage/product'; -import { ViewContext } from '@shopgate/engage/components/View'; -import Item from '../SheetItem'; -import VariantAvailability from '../VariantAvailability'; - -/** - * The CharacteristicSheet component. - */ -class CharacteristicSheet extends PureComponent { - static propTypes = { - charId: PropTypes.string.isRequired, - items: PropTypes.arrayOf(PropTypes.shape()).isRequired, - label: PropTypes.string.isRequired, - open: PropTypes.bool.isRequired, - setViewAriaHidden: PropTypes.func.isRequired, - onClose: PropTypes.func, - onSelect: PropTypes.func, - productId: PropTypes.string, - selectedValue: PropTypes.string, - selection: PropTypes.shape(), - }; - - static defaultProps = { - onClose() { }, - onSelect() { }, - productId: null, - selectedValue: null, - selection: null, - }; - - firstSelectableItemRef = React.createRef(); - - /** - * Focuses the first selectable item and hides the view for screen readers. - */ - onDidOpen = () => { - if (this.firstSelectableItemRef.current) { - this.firstSelectableItemRef.current.focus(); - } - - this.props.setViewAriaHidden(true); - }; - - /** - * Shows the view for screen readers. - * @param {Object} e The event payload. - */ - onClose = (e) => { - this.props.onClose(e); - this.props.setViewAriaHidden(false); - } - - /** - * @param {Object} event The event object. - * @param {string} itemId The id that was selected - */ - handleItemClick = (event, itemId) => { - event.stopPropagation(); - this.props.onSelect(itemId); - } - - /** - * Renders the availability text inside the sheet item. - * @param {string} value The value that the sheet item represents. - * @return {React.Component|null} - */ - renderAvailability = (value) => { - const selection = { - ...this.props.selection, - [this.props.charId]: value, - }; - - return ; - } - - /** - * @return {JSX} - */ - render() { - const { - items, label, open, selectedValue, - } = this.props; - - let selectedIndex; - - if (selectedValue) { - selectedIndex = items.findIndex(item => item.id === selectedValue); - } else { - selectedIndex = items.findIndex(item => item.selectable); - } - - return ( - - - {items.map((item, index) => ( - this.renderAvailability(item.id)} - selected={item.id === selectedValue} - ref={index === selectedIndex ? this.firstSelectableItemRef : null} - productId={this.props.productId} - characteristics={{ - ...this.props.selection, - [this.props.charId]: item.id, - }} - /> - ))} - - - ); - } -} - -/** - * @param {Object} props The original component props. - * @returns {JSX} - */ -const SheetComponent = props => ( - - {({ setAriaHidden }) => ( - - {({ productId }) => ( - - {({ characteristics }) => ( - - )} - - )} - - )} - - -); - -export default SheetComponent; diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/index.jsx b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/index.jsx deleted file mode 100644 index 7a79e67c1a..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/index.jsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import { withForwardedRef } from '@shopgate/engage/core'; -import BackInStockRow from '../BackInStockRow'; -import styles from './style'; - -/** - * The SheetItem component. - */ -class SheetItem extends PureComponent { - static propTypes = { - characteristics: PropTypes.shape().isRequired, - item: PropTypes.shape().isRequired, - productId: PropTypes.string.isRequired, - forwardedRef: PropTypes.shape(), - onClick: PropTypes.func, - rightComponent: PropTypes.func, - selected: PropTypes.bool, - }; - - static defaultProps = { - forwardedRef: null, - onClick() { }, - rightComponent: null, - selected: false, - }; - - /** - * @param {boolean} selectable Whether or not the item can be selected. - * @returns {string} - */ - getStyle = (selectable) => { - const { selected } = this.props; - - if (selected) { - return styles.buttonSelected; - } - - if (!selectable) { - return styles.buttonDisabled; - } - - return styles.button; - }; - - /** - * @returns {Object} - */ - buildProps = () => { - const { - item, onClick, forwardedRef, - } = this.props; - - return { - className: `${this.getStyle(item.selectable).toString()} theme__product__characteristic__option`, - key: item.id, - ref: forwardedRef, - value: item.id, - 'aria-hidden': !item.selectable, - ...item.selectable && { onClick: event => onClick(event, item.id) }, - }; - }; - - /** - * @returns {JSX} - */ - render() { - const { - item, - rightComponent: Right, - selected, - productId, - characteristics, - } = this.props; - - return ( - - ); - } -} - -export default withForwardedRef(SheetItem); diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/style.js b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/style.js deleted file mode 100644 index 7e879c531e..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/SheetItem/style.js +++ /dev/null @@ -1,32 +0,0 @@ -import { css } from 'glamor'; -import { themeConfig } from '@shopgate/pwa-common/helpers/config'; - -const { colors, variables } = themeConfig; - -const button = css({ - outline: 0, - padding: '16px 16px 16px 0', - textAlign: 'left', - width: '100%', -}); - -const buttonDisabled = css(button, { - color: colors.shade4, -}); - -const bgColor = colors.darkGray; -const boxShadowOffset = variables.gap.bigger; - -const buttonSelected = css(button, { - background: bgColor, - boxShadow: `-${boxShadowOffset}px 0 0 ${bgColor}, ${boxShadowOffset}px 0 0 ${bgColor}`, - margin: '-1px 0', - paddingTop: 17, - paddingBottom: 17, -}); - -export default { - button, - buttonDisabled, - buttonSelected, -}; diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/connector.js b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/connector.js deleted file mode 100644 index 8cbf5292df..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/connector.js +++ /dev/null @@ -1,27 +0,0 @@ -import { connect } from 'react-redux'; -import isEqual from 'lodash/isEqual'; -import { getVariantAvailabilityByCharacteristics } from '@shopgate/pwa-common-commerce/product/selectors/product'; - -/** - * @param {Object} state The application state. - * @param {Object} props The component props. - * @return {Object} - */ -const mapStateToProps = (state, props) => ({ - availability: getVariantAvailabilityByCharacteristics(state, props), -}); - -/** - * @param {Object} next The next component props. - * @param {Object} prev The previous component props. - * @returns {boolean} - */ -const areStatePropsEqual = (next, prev) => { - if (!isEqual(prev.availability, next.availability)) { - return false; - } - - return true; -}; - -export default connect(mapStateToProps, null, null, { areStatePropsEqual }); diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/index.jsx b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/index.jsx deleted file mode 100644 index a1734e8a89..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/index.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, { PureComponent, Fragment } from 'react'; -import PropTypes from 'prop-types'; -import Availability from '@shopgate/pwa-ui-shared/Availability'; -import Portal from '@shopgate/pwa-common/components/Portal'; -import { - PRODUCT_VARIANT_SELECT_PICKER_AVAILABILITY_BEFORE, - PRODUCT_VARIANT_SELECT_PICKER_AVAILABILITY, - PRODUCT_VARIANT_SELECT_PICKER_AVAILABILITY_AFTER, -} from '@shopgate/pwa-common-commerce/product/constants/Portals'; -import connect from './connector'; -import styles from './style'; - -/** - * The VariantAvailability component. - */ -class VariantAvailability extends PureComponent { - static propTypes = { - availability: PropTypes.shape(), - }; - - static defaultProps = { - availability: null, - }; - - /** - * @returns {JSX} - */ - render() { - if (!this.props.availability) { - return null; - } - - const { availability } = this.props; - const { state, text } = availability; - - return ( - - - - - - - - ); - } -} - -export default connect(VariantAvailability); diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/style.js b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/style.js deleted file mode 100644 index ca7abe4736..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/components/VariantAvailability/style.js +++ /dev/null @@ -1,6 +0,0 @@ -import { css } from 'glamor'; - -export default css({ - float: 'right', - pointerEvents: 'none', -}).toString(); diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/index.jsx b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/index.jsx deleted file mode 100644 index 4ea2051168..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/index.jsx +++ /dev/null @@ -1,169 +0,0 @@ -import React, { PureComponent, Fragment } from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import Transition from 'react-transition-group/Transition'; -import Sheet from './components/Sheet'; -import styles from './style'; -import transition from '../transition'; - -/** - * A single characteristic. - */ -class Characteristic extends PureComponent { - static propTypes = { - charRef: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.shape(), - ]).isRequired, - disabled: PropTypes.bool.isRequired, - highlight: PropTypes.bool.isRequired, - id: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, - select: PropTypes.func.isRequired, - values: PropTypes.arrayOf(PropTypes.shape()).isRequired, - selected: PropTypes.string, - }; - - static contextTypes = { - i18n: PropTypes.func, - }; - - static defaultProps = { - selected: null, - }; - - state = { - highlight: false, - sheet: false, - }; - - /** - * @param {Object} nextProps The next component props. - */ - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState({ highlight: nextProps.highlight }); - } - - /** - * @param {string} defaultLabel The default button label. - * @return {string} - */ - getButtonLabel = (defaultLabel) => { - if (!this.props.selected) { - return defaultLabel; - } - - const value = this.props.values.find(val => (val.id === this.props.selected)); - - return value.label; - } - - /** - * @param {Object} event The event object. - */ - handleButtonClick = (event) => { - event.preventDefault(); - - if (this.props.disabled) { - return; - } - - this.setState({ sheet: true }); - } - - /** - * @param {string} valueId The ID of the selected value. - */ - handleItemSelection = (valueId) => { - this.props.select({ - id: this.props.id, - value: valueId, - }); - - this.closeSheet(); - } - - closeSheet = () => { - this.setState({ sheet: false }); - if (this.props.charRef && this.props.charRef.current) { - this.props.charRef.current.focus(); - } - } - - removeHighlight = () => { - this.setState({ highlight: false }); - } - - /** - * Renders the transition contents. - * @param {string} state The current transition state. - * @returns {JSX} - */ - transitionRenderer = (state) => { - const { __ } = this.context.i18n(); - const { - disabled, selected, charRef, label, - } = this.props; - const translatedLabel = __('product.pick_an_attribute', [label]); - const buttonLabel = this.getButtonLabel(translatedLabel); - const classes = classNames( - styles.button, - { [styles.buttonDisabled]: disabled }, - 'theme__product__characteristic' - ); - - return ( -
{ }} - ref={charRef} - style={transition[state]} - data-test-id={label} - > - {selected &&
{label}
} -
- {buttonLabel} -
-
- ); - } - - /** - * @return {JSX} - */ - render() { - const { __ } = this.context.i18n(); - const { - id, selected, values, - } = this.props; - const displayLabel = this.props.label; - const translatedLabel = __('product.pick_an_attribute', [displayLabel]); - - return ( - - - {this.transitionRenderer} - - - - ); - } -} - -export default Characteristic; diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/style.js b/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/style.js deleted file mode 100644 index 2e2b200b73..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Characteristic/style.js +++ /dev/null @@ -1,36 +0,0 @@ -import { css } from 'glamor'; -import { themeColors } from '@shopgate/pwa-common/helpers/config'; - -const button = css({ - background: themeColors.overlay, - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - minHeight: 56, - outline: 0, - padding: '12px 16px', - marginBottom: 8, - transition: 'background 250ms ease-in, color 250ms ease-in', -}).toString(); - -const buttonDisabled = css({ - color: themeColors.shade4, -}).toString(); - -const label = css({ - fontSize: 12, - marginTop: -2, - marginBottom: 4, -}).toString(); - -const selection = css({ - fontWeight: 500, - lineHeight: 1.125, -}).toString(); - -export default { - button, - buttonDisabled, - label, - selection, -}; diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Swatch/index.jsx b/themes/theme-gmd/pages/Product/components/Characteristics/Swatch/index.jsx deleted file mode 100644 index b0d091b2a3..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Swatch/index.jsx +++ /dev/null @@ -1,105 +0,0 @@ -import React, { PureComponent, Fragment } from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import Transition from 'react-transition-group/Transition'; -import { VariantSwatch } from '@shopgate/engage/product'; -import styles from './style'; -import transition from '../transition'; - -/** - * A single characteristic swatch type. - */ -class Swatch extends PureComponent { - static propTypes = { - charRef: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.shape(), - ]).isRequired, - disabled: PropTypes.bool.isRequired, - // eslint-disable-next-line react/no-unused-prop-types - highlight: PropTypes.bool.isRequired, - id: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, - select: PropTypes.func.isRequired, - values: PropTypes.arrayOf(PropTypes.shape()).isRequired, - selected: PropTypes.string, - }; - - static defaultProps = { - selected: null, - }; - - state = { highlight: false }; - - /** - * @param {Object} nextProps The next component props. - */ - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState({ highlight: nextProps.highlight }); - } - - /** - * @param {string} charLabel The default button label. - * @return {string} - */ - getLabel = (charLabel) => { - if (!this.props.selected) { - return charLabel; - } - - const value = this.props.values.find(val => (val.id === this.props.selected)); - return `${charLabel} - ${value.label}`; - } - - /** - * @param {string} valueId The ID of the selected value. - */ - handleItemSelection = (valueId) => { - this.props.select({ - id: this.props.id, - value: valueId, - }); - } - - removeHighlight = () => { - this.setState({ highlight: false }); - } - - /** - * @return {JSX} - */ - render() { - const { - id, disabled, charRef, label, values, - } = this.props; - - const swatch = { - id, - label, - values, - }; - - return ( - - - {state => ( -
- {this.getLabel(label)} -
- )} -
-
- -
-
- ); - } -} - -export default Swatch; diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/Swatch/style.js b/themes/theme-gmd/pages/Product/components/Characteristics/Swatch/style.js deleted file mode 100644 index 4355c7e54a..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/Swatch/style.js +++ /dev/null @@ -1,31 +0,0 @@ -import { css } from 'glamor'; -import { themeConfig } from '@shopgate/pwa-common/helpers/config'; - -const { colors } = themeConfig; - -const label = css({ - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - minHeight: 56, - outline: 0, - padding: '12px 16px', - transition: 'background 250ms ease-in, color 250ms ease-in', - fontWeight: 500, - lineHeight: 1.125, -}).toString(); - -const labelDisabled = css({ - color: colors.shade4, -}).toString(); - -const items = css({ - padding: '0 16px', - marginBottom: 16, -}).toString(); - -export default { - label, - labelDisabled, - items, -}; diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/index.jsx b/themes/theme-gmd/pages/Product/components/Characteristics/index.jsx deleted file mode 100644 index c5048fd97a..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/index.jsx +++ /dev/null @@ -1,87 +0,0 @@ -import React, { PureComponent, Fragment } from 'react'; -import PropTypes from 'prop-types'; -import { isBeta } from '@shopgate/engage/core'; -import Portal from '@shopgate/pwa-common/components/Portal'; -import { - PRODUCT_VARIANT_SELECT, - PRODUCT_VARIANT_SELECT_AFTER, - PRODUCT_VARIANT_SELECT_BEFORE, -} from '@shopgate/pwa-common-commerce/product/constants/Portals'; -import { ProductCharacteristics, ProductContext } from '@shopgate/engage/product'; -import Characteristic from './Characteristic'; -import Swatch from './Swatch'; - -/** - * The Characteristics component. - */ -class Characteristics extends PureComponent { - static propTypes = { - productId: PropTypes.string, - variantId: PropTypes.string, - }; - - static defaultProps = { - productId: null, - variantId: null, - }; - - /** - * @param {Object} props The consumer props. - * @returns {JSX} - */ - consumeRenderer = ({ conditioner, setCharacteristics }) => { - const { productId, variantId } = this.props; - - return ( - - ); - } - - /** - * @see ProductCharacteristics.render - * @param {Object} props The renderer props. - * @returns {JSX} - */ - renderer = (props) => { - if (isBeta() && !!props.swatch) { - return ; - } - return ; - }; - - /** - * @returns {JSX} - */ - render() { - return ( - - - - - {this.consumeRenderer} - - - - - ); - } -} - -Characteristics.propTypes = { - productId: PropTypes.string, - variantId: PropTypes.string, -}; - -Characteristics.defaultProps = { - productId: null, - variantId: null, -}; - -export default Characteristics; diff --git a/themes/theme-gmd/pages/Product/components/Characteristics/transition.js b/themes/theme-gmd/pages/Product/components/Characteristics/transition.js deleted file mode 100644 index ee44de348e..0000000000 --- a/themes/theme-gmd/pages/Product/components/Characteristics/transition.js +++ /dev/null @@ -1,14 +0,0 @@ -import { themeConfig } from '@shopgate/pwa-common/helpers/config'; - -const { colors } = themeConfig; - -export default { - entering: { - background: colors.primary, - color: colors.primaryContrast, - }, - entered: { - background: colors.primary, - color: colors.primaryContrast, - }, -}; diff --git a/themes/theme-gmd/pages/Product/components/Content/index.jsx b/themes/theme-gmd/pages/Product/components/Content/index.jsx index 2a6bd2a9a7..39eb08495e 100644 --- a/themes/theme-gmd/pages/Product/components/Content/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Content/index.jsx @@ -9,13 +9,13 @@ import { Description, ProductContext, Options, + Characteristics, } from '@shopgate/engage/product'; import { Reviews } from '@shopgate/engage/reviews'; import UnitQuantityPickerWithSection - from '@shopgate/engage/product/components/UnitQuantityPicker/UnitQuantityPickerWithSection'; +from '@shopgate/engage/product/components/UnitQuantityPicker/UnitQuantityPickerWithSection'; import Media from '../Media'; import Header from '../Header'; -import Characteristics from '../Characteristics'; import AppBar from '../AppBar'; import connect from './connector'; diff --git a/themes/theme-ios11/pages/Product/components/Content/index.jsx b/themes/theme-ios11/pages/Product/components/Content/index.jsx index 1d074749d3..e372caa4b0 100644 --- a/themes/theme-ios11/pages/Product/components/Content/index.jsx +++ b/themes/theme-ios11/pages/Product/components/Content/index.jsx @@ -13,7 +13,7 @@ import { } from '@shopgate/engage/product'; import { Reviews } from '@shopgate/engage/reviews'; import UnitQuantityPickerWithSection - from '@shopgate/engage/product/components/UnitQuantityPicker/UnitQuantityPickerWithSection'; +from '@shopgate/engage/product/components/UnitQuantityPicker/UnitQuantityPickerWithSection'; import Media from '../Media'; import Header from '../Header'; import AppBar from '../AppBar'; From 7c3b099ee103a626730ecf977074e3b166ad46f7 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 13 Feb 2024 10:24:52 +0100 Subject: [PATCH 17/55] CURB-3886 Move characteristics button --- .../components/CharacteristicsButton}/connector.js | 0 .../components/CharacteristicsButton}/index.jsx | 10 +++++----- libraries/engage/back-in-stock/index.js | 1 + .../Characteristic/components/SheetItem/index.jsx | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) rename libraries/engage/{product/components/Characteristics/Characteristic/components/BackInStockRow => back-in-stock/components/CharacteristicsButton}/connector.js (100%) rename libraries/engage/{product/components/Characteristics/Characteristic/components/BackInStockRow => back-in-stock/components/CharacteristicsButton}/index.jsx (91%) diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js similarity index 100% rename from libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/connector.js rename to libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx similarity index 91% rename from libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx rename to libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx index 7ff5462338..12a1cfb19c 100644 --- a/libraries/engage/product/components/Characteristics/Characteristic/components/BackInStockRow/index.jsx +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx @@ -6,7 +6,7 @@ import isEqual from 'lodash/isEqual'; import connect from './connector'; /** - * The BackInStockRow component. + * The CharacteristicsButton component. * @param {Object} props The component props. * @param {boolean} props.isBackInStockEnabled Whether the back in stock feature is enabled * @param {Array} props.productVariants The product variants @@ -16,7 +16,7 @@ import connect from './connector'; * @param {Function} props.grantPushPermissions Request / Set push permission * @return {JSX} */ -const BackInStockRow = ({ +const CharacteristicsButton = ({ availability, addBackInStockSubscription, productVariants, @@ -50,7 +50,7 @@ const BackInStockRow = ({ ); }; -BackInStockRow.propTypes = { +CharacteristicsButton.propTypes = { addBackInStockSubscription: PropTypes.func.isRequired, grantPushPermissions: PropTypes.func.isRequired, isBackInStockEnabled: PropTypes.bool.isRequired, @@ -60,11 +60,11 @@ BackInStockRow.propTypes = { subscription: PropTypes.shape(), }; -BackInStockRow.defaultProps = { +CharacteristicsButton.defaultProps = { availability: null, productVariants: {}, characteristics: {}, subscription: null, }; -export default connect(BackInStockRow); +export default connect(CharacteristicsButton); diff --git a/libraries/engage/back-in-stock/index.js b/libraries/engage/back-in-stock/index.js index d1cbdb1e36..0f1ab384dc 100644 --- a/libraries/engage/back-in-stock/index.js +++ b/libraries/engage/back-in-stock/index.js @@ -5,6 +5,7 @@ export * from './constants'; export { default as BackInStockReminders } from './components/Subscriptions'; export { default as BackInStockButton } from './components/BackInStockButton'; export { default as BackInStockButtonPortal } from './components/BackInStockButtonPortal'; +export { default as CharacteristicsButton } from './components/CharacteristicsButton'; // STREAMS export * from './streams'; diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx index 2b43bc5abd..431c7a4946 100644 --- a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx @@ -1,8 +1,8 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { withForwardedRef } from '@shopgate/engage/core'; +import { CharacteristicsButton } from '@shopgate/engage/back-in-stock'; import styles from './style'; -import BackInStockRow from '../BackInStockRow'; /** * The SheetItem component. @@ -80,7 +80,7 @@ class SheetItem extends PureComponent { From 6fdeba79ea091425941e9352d8917f5e02910abf Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 13 Feb 2024 11:27:47 +0100 Subject: [PATCH 18/55] CURB-3886 Refactor Characteristics Button --- .../back-in-stock/components/BackInStockButton/style.js | 2 +- .../components/BackInStockButtonPortal/index.jsx | 2 +- .../back-in-stock/components/CharacteristicsButton/index.jsx | 5 +++-- .../Characteristic/components/Sheet/index.jsx | 1 - .../Characteristic/components/SheetItem/index.jsx | 3 +-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/style.js b/libraries/engage/back-in-stock/components/BackInStockButton/style.js index 0a34b5c787..6dba7da8d2 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/style.js +++ b/libraries/engage/back-in-stock/components/BackInStockButton/style.js @@ -15,6 +15,7 @@ export default { marginTop: '4px', display: 'inline', alignItems: 'center', + textAlign: 'end', }).toString(), backInStockMessage: css({ marginLeft: '4px', @@ -29,5 +30,4 @@ export default { verticalAlign: 'middle', display: 'inline', }).toString(), - }; diff --git a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx index 8fa10b94f0..ab36d8be90 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx +++ b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx @@ -48,7 +48,7 @@ const BackInStockButtonPortal = ({ onClick={async () => { const allowed = await grantPushPermissions(); if (allowed) { - addBackInStockSubscription({ productCode: productId }); + addBackInStockSubscription({ productId }); } }} />} diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx index 12a1cfb19c..0d9b08ee26 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { BackInStockButton } from '@shopgate/engage/back-in-stock'; import { AVAILABILITY_STATE_OK } from '@shopgate/engage/product'; import isEqual from 'lodash/isEqual'; +import { withCurrentProduct } from '@shopgate/engage/core'; import connect from './connector'; /** @@ -43,7 +44,7 @@ const CharacteristicsButton = ({ e.stopPropagation(); const allowed = await grantPushPermissions(); if (allowed) { - addBackInStockSubscription({ productCode: foundVariant.id }); + addBackInStockSubscription({ productId: foundVariant.id }); } }} /> @@ -67,4 +68,4 @@ CharacteristicsButton.defaultProps = { subscription: null, }; -export default connect(CharacteristicsButton); +export default withCurrentProduct(connect(CharacteristicsButton)); diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/Sheet/index.jsx b/libraries/engage/product/components/Characteristics/Characteristic/components/Sheet/index.jsx index a21f81b597..13c44eb1c5 100644 --- a/libraries/engage/product/components/Characteristics/Characteristic/components/Sheet/index.jsx +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/Sheet/index.jsx @@ -103,7 +103,6 @@ class CharacteristicSheet extends PureComponent { rightComponent={() => this.renderAvailability(item.id)} selected={item.id === selectedValue} ref={index === selectedIndex ? this.firstSelectableItemRef : null} - productId={this.props.productId} characteristics={{ ...this.props.selection, [this.props.charId]: item.id, diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx index 431c7a4946..e2b4aac832 100644 --- a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx @@ -70,7 +70,6 @@ class SheetItem extends PureComponent { item, rightComponent: Right, selected, - productId, characteristics, } = this.props; @@ -80,7 +79,7 @@ class SheetItem extends PureComponent { From 92f6d9253445662faf9240719eec9db9f13fe84c Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 13 Feb 2024 11:58:21 +0100 Subject: [PATCH 19/55] CURB-3886 Add fallback icon --- libraries/ui-shared/icons/NotificationIcon.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/ui-shared/icons/NotificationIcon.jsx b/libraries/ui-shared/icons/NotificationIcon.jsx index ad760858fd..5f2991a6a6 100644 --- a/libraries/ui-shared/icons/NotificationIcon.jsx +++ b/libraries/ui-shared/icons/NotificationIcon.jsx @@ -2,11 +2,15 @@ import React from 'react'; import Icon from '@shopgate/pwa-common/components/Icon'; import { themeConfig } from '@shopgate/pwa-common/helpers/config'; +// SVG Content +const content = ''; + /** * The description icon component. * @param {Object} props The icon component properties. * @returns {JSX} */ -const Notification = props => ; +const Notification = props => + ; export default Notification; From b643dcf0bcfc00a7e7b800ece8c2e44881a8f906 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 13 Feb 2024 15:36:41 +0100 Subject: [PATCH 20/55] CURB-3886 Refactor CharacteristicsButton connector --- .../CharacteristicsButton/connector.js | 23 +++++++++++++------ .../CharacteristicsButton/index.jsx | 20 +++++----------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js index ba1f19ba02..a3c52a142d 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js @@ -4,21 +4,30 @@ import { getSubscriptionByCharacteristics, } from '@shopgate/engage/back-in-stock'; import { - getProductVariants, getVariantAvailabilityByCharacteristics, } from '@shopgate/pwa-common-commerce/product'; import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; import grantPushPermissions from '@shopgate/engage/core/actions/grantPushPermissions'; +import { + makeGetProductByCharacteristics, +} from '@shopgate/engage/product'; /** * @return {Object} The extended component props. */ -const makeMapStateToProps = () => (state, props) => ({ - availability: getVariantAvailabilityByCharacteristics(state, props), - subscription: getSubscriptionByCharacteristics(state, props), - productVariants: getProductVariants(state, props), - isBackInStockEnabled: getIsBackInStockEnabled(state, props), -}); +const makeMapStateToProps = () => { + const getProductByCharacteristics = makeGetProductByCharacteristics(); + + return (state, props) => { + const variant = getProductByCharacteristics(state, props) || {}; + return ({ + variant, + availability: getVariantAvailabilityByCharacteristics(state, props), + subscription: getSubscriptionByCharacteristics(state, props), + isBackInStockEnabled: getIsBackInStockEnabled(state, props), + }); + }; +}; const mapDispatchToProps = { addBackInStockSubscription, diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx index 0d9b08ee26..b21233ce6a 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx @@ -2,7 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { BackInStockButton } from '@shopgate/engage/back-in-stock'; import { AVAILABILITY_STATE_OK } from '@shopgate/engage/product'; -import isEqual from 'lodash/isEqual'; import { withCurrentProduct } from '@shopgate/engage/core'; import connect from './connector'; @@ -10,27 +9,22 @@ import connect from './connector'; * The CharacteristicsButton component. * @param {Object} props The component props. * @param {boolean} props.isBackInStockEnabled Whether the back in stock feature is enabled - * @param {Array} props.productVariants The product variants + * @param {Object} props.variant The variant for this entry * @param {Object} props.availability The product availability * @param {Object} props.subscription The subscription - * @param {Object} props.characteristics The variant characteristics * @param {Function} props.grantPushPermissions Request / Set push permission * @return {JSX} */ const CharacteristicsButton = ({ availability, addBackInStockSubscription, - productVariants, - characteristics, isBackInStockEnabled, grantPushPermissions, subscription, + variant, }) => { - const foundVariant = productVariants?.products.find(product => - isEqual(product.characteristics, characteristics)); - if (availability?.state === AVAILABILITY_STATE_OK || - availability === null || !foundVariant || !isBackInStockEnabled) return null; + availability === null || !variant || !isBackInStockEnabled) return null; return (
@@ -56,15 +50,13 @@ CharacteristicsButton.propTypes = { grantPushPermissions: PropTypes.func.isRequired, isBackInStockEnabled: PropTypes.bool.isRequired, availability: PropTypes.shape(), - characteristics: PropTypes.shape(), - productVariants: PropTypes.shape(), subscription: PropTypes.shape(), + variant: PropTypes.shape(), }; CharacteristicsButton.defaultProps = { availability: null, - productVariants: {}, - characteristics: {}, + variant: {}, subscription: null, }; From 24ab274893e06c9096ffa44edd30f3e3bd1061dc Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 13 Feb 2024 15:46:44 +0100 Subject: [PATCH 21/55] CURB-3886 Refactor NavDrawer backInStockButton --- .../{ => components/BackInStockButton}/connector.js | 0 .../Main/components/BackInStockButton/index.jsx | 9 +++++++-- .../components/NavDrawer/components/Main/index.jsx | 13 +++---------- 3 files changed, 10 insertions(+), 12 deletions(-) rename themes/theme-gmd/components/NavDrawer/components/Main/{ => components/BackInStockButton}/connector.js (100%) diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/connector.js b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/connector.js similarity index 100% rename from themes/theme-gmd/components/NavDrawer/components/Main/connector.js rename to themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/connector.js diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx index 5c341d9ab4..20caecfe4a 100644 --- a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx @@ -12,17 +12,20 @@ import { import navDrawerConnect from '../../../../connector'; import portalProps from '../../../../portalProps'; import Badge from './components/Badge'; +import connect from './connector'; const LABEL = 'navigation.back_in_stock'; /** * @param {Function} navigate The navigate action. + * @param {boolean} isBackInStockEnabled Whether the back in stock feature is enabled * @returns {JSX} */ -const BackInStockButton = ({ navigate }) => ( +const BackInStockButton = ({ navigate, isBackInStockEnabled }) => ( + { isBackInStockEnabled && ( onClick={navigate(BACK_IN_STOCK_PATTERN, LABEL)} testId="navDrawerBackInStockButton" /> + } ); BackInStockButton.propTypes = { + isBackInStockEnabled: PropTypes.bool.isRequired, navigate: PropTypes.func.isRequired, }; // Combine two different connectors to reuse the existing functionality. -export default navDrawerConnect(BackInStockButton); +export default navDrawerConnect(connect(BackInStockButton)); diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/index.jsx b/themes/theme-gmd/components/NavDrawer/components/Main/index.jsx index 96dc93993e..703f45623d 100644 --- a/themes/theme-gmd/components/NavDrawer/components/Main/index.jsx +++ b/themes/theme-gmd/components/NavDrawer/components/Main/index.jsx @@ -1,32 +1,25 @@ import React from 'react'; import { NavDrawer } from '@shopgate/pwa-ui-material'; import appConfig from '@shopgate/pwa-common/helpers/config'; -import PropTypes from 'prop-types'; import HomeButton from './components/HomeButton'; import CategoryButton from './components/CategoryButton'; import FavoritesButton from './components/FavoritesButton'; import CartButton from './components/CartButton'; import ScannerButton from './components/ScannerButton'; import BackInStockButton from './components/BackInStockButton'; -import connect from './connector'; /** - * @param {boolean} isBackInStockEnabled Whether the back in stock feature is enabled * @return {JSX} */ -const MainSection = ({ isBackInStockEnabled }) => ( +const MainSection = () => ( {appConfig.hasFavorites && } - {isBackInStockEnabled && } + ); -MainSection.propTypes = { - isBackInStockEnabled: PropTypes.bool.isRequired, -}; - -export default connect(MainSection); +export default MainSection; From d517773c7f235cc0f6dd5bb1e4f13b59840ea96c Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 14 Feb 2024 09:18:52 +0100 Subject: [PATCH 22/55] CURB-3886 Small improvements --- .../components/BackInStockButton/index.jsx | 10 ++++++---- .../components/BackInStockButton/style.js | 3 --- libraries/engage/back-in-stock/index.js | 2 +- .../selectors/{backInStock.js => index.js} | 0 .../Characteristic/components/SheetItem/index.jsx | 13 +++++-------- .../Main/components/BackInStockButton/index.jsx | 4 +--- 6 files changed, 13 insertions(+), 19 deletions(-) rename libraries/engage/back-in-stock/selectors/{backInStock.js => index.js} (100%) diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx b/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx index a045c5add9..56419215f8 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx +++ b/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx @@ -1,9 +1,11 @@ import React from 'react'; -import NotificationIcon from '@shopgate/pwa-ui-shared/icons/NotificationIcon'; -import CheckedIcon from '@shopgate/pwa-ui-shared/icons/CheckedIcon'; import PropTypes from 'prop-types'; -import { themeConfig } from '@shopgate/pwa-common/helpers/config'; -import Link from '@shopgate/pwa-common/components/Link'; +import { themeConfig } from '@shopgate/engage'; +import { + Link, + CheckedIcon, + NotificationIcon, +} from '@shopgate/engage/components'; import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; import { i18n } from '@shopgate/engage/core'; import styles from './style'; diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/style.js b/libraries/engage/back-in-stock/components/BackInStockButton/style.js index 6dba7da8d2..b49370f5fd 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/style.js +++ b/libraries/engage/back-in-stock/components/BackInStockButton/style.js @@ -5,7 +5,6 @@ export default { button: css({ marginTop: '4px', color: themeConfig.colors.primary, - textDecoration: 'underline', }).toString(), buttonContent: css({ display: 'flex', @@ -20,11 +19,9 @@ export default { backInStockMessage: css({ marginLeft: '4px', verticalAlign: 'middle', - textDecoration: 'underline', }).toString(), buttonText: css({ marginLeft: '4px', - textDecoration: 'underline', }).toString(), icon: css({ verticalAlign: 'middle', diff --git a/libraries/engage/back-in-stock/index.js b/libraries/engage/back-in-stock/index.js index 0f1ab384dc..bd1aaf1d78 100644 --- a/libraries/engage/back-in-stock/index.js +++ b/libraries/engage/back-in-stock/index.js @@ -11,4 +11,4 @@ export { default as CharacteristicsButton } from './components/CharacteristicsBu export * from './streams'; // SELECTORS -export * from './selectors/backInStock'; +export * from './selectors'; diff --git a/libraries/engage/back-in-stock/selectors/backInStock.js b/libraries/engage/back-in-stock/selectors/index.js similarity index 100% rename from libraries/engage/back-in-stock/selectors/backInStock.js rename to libraries/engage/back-in-stock/selectors/index.js diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx index e2b4aac832..3c6fcc431a 100644 --- a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx @@ -75,14 +75,11 @@ class SheetItem extends PureComponent { const buildProps = this.buildProps(); return ( -
- - -
+ ); } } diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx index 20caecfe4a..a42dbd948c 100644 --- a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx @@ -1,8 +1,6 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import Portal from '@shopgate/pwa-common/components/Portal'; -import NotificationIcon from '@shopgate/pwa-ui-shared/icons/NotificationIcon'; -import { NavDrawer } from '@shopgate/pwa-ui-material'; +import { NavDrawer, NotificationIcon, Portal } from '@shopgate/engage/components'; import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; import { NAV_MENU_BACK_IN_STOCK, From b12d9037c30566d6a3a4cf46628772a3d5749806 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 14 Feb 2024 09:34:31 +0100 Subject: [PATCH 23/55] CURB-3886 Refactor getProductType --- libraries/commerce/product/selectors/product.js | 11 ----------- .../BackInStockButtonPortal/connector.js | 17 ++++++++++------- libraries/engage/product/index.js | 1 + libraries/engage/product/selectors/product.js | 9 +++++++++ 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/libraries/commerce/product/selectors/product.js b/libraries/commerce/product/selectors/product.js index 0526b30273..5acf3d1d74 100644 --- a/libraries/commerce/product/selectors/product.js +++ b/libraries/commerce/product/selectors/product.js @@ -232,17 +232,6 @@ export const getProductLongName = createSelector( } ); -/** - * Retrieves the product type. - * @param {Object} state The current application state. - * @param {Object} props The component props. - * @return {string|null} - */ -export const getProductType = createSelector( - getProduct, - product => product?.type -); - /** * Retrieves the product rating. * @param {Object} state The current application state. diff --git a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/connector.js b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/connector.js index 1d21706f50..4965a918b5 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/connector.js +++ b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/connector.js @@ -6,19 +6,22 @@ import { import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; import { getProductAvailability, - getProductType, + makeGetProductType, } from '@shopgate/engage/product'; import { grantPushPermissions } from '@shopgate/engage/core'; /** * @return {Object} The extended component props. */ -const makeMapStateToProps = () => (state, props) => ({ - subscription: getSubscriptionByVariant(state, props), - productType: getProductType(state, props), - stock: getProductAvailability(state, props), - isBackInStockEnabled: getIsBackInStockEnabled(state, props), -}); +const makeMapStateToProps = () => { + const getProductType = makeGetProductType(); + return (state, props) => ({ + subscription: getSubscriptionByVariant(state, props), + productType: getProductType(state, props), + stock: getProductAvailability(state, props), + isBackInStockEnabled: getIsBackInStockEnabled(state, props), + }); +}; const mapDispatchToProps = { addBackInStockSubscription, diff --git a/libraries/engage/product/index.js b/libraries/engage/product/index.js index e4429a15c4..7d39612c24 100644 --- a/libraries/engage/product/index.js +++ b/libraries/engage/product/index.js @@ -49,6 +49,7 @@ export { makeGetProductFeaturedMedia, makeIsProductActive, makeIsBaseProductActive, + makeGetProductType, } from './selectors/product'; export * from './selectors/price'; export * from './selectors/variants'; diff --git a/libraries/engage/product/selectors/product.js b/libraries/engage/product/selectors/product.js index a88fb7f57a..e02efc70a8 100644 --- a/libraries/engage/product/selectors/product.js +++ b/libraries/engage/product/selectors/product.js @@ -125,3 +125,12 @@ export const getCurrentProductPropertyByLabel = createSelector( .find(({ label }) => label === widgetSettings.propertyLabel); } ); +/** + * Create a selector to retrieve the product type. + * @returns {Function} + * + */ +export const makeGetProductType = () => createSelector( + getProduct, + product => product?.type +); From 0b2ce6eb3723eb61677be628cc89e2d21bc13bfc Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 14 Feb 2024 09:48:27 +0100 Subject: [PATCH 24/55] CURB-3886 Refactor backInStock index --- .../components/BackInStockButtonPortal/index.jsx | 5 +++-- .../back-in-stock/components/Subscriptions/index.jsx | 2 +- libraries/engage/back-in-stock/hooks/index.js | 4 ++-- libraries/engage/back-in-stock/index.js | 12 ++++++++++++ .../Main/components/BackInStockButton/index.jsx | 4 ++-- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx index ab36d8be90..6571aa650c 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx +++ b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx @@ -2,12 +2,13 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import { Portal } from '@shopgate/engage/components'; import { AVAILABILITY_STATE_OK } from '@shopgate/engage/product'; -import { BackInStockButton } from '@shopgate/engage/back-in-stock'; import { + BackInStockButton, PRODUCT_BACK_IN_STOCK, PRODUCT_BACK_IN_STOCK_AFTER, PRODUCT_BACK_IN_STOCK_BEFORE, -} from '@shopgate/engage/back-in-stock/constants/Portals'; +} from '@shopgate/engage/back-in-stock'; + import { withCurrentProduct } from '@shopgate/engage/core'; import connect from './connector'; diff --git a/libraries/engage/back-in-stock/components/Subscriptions/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/index.jsx index b241658388..f6076726bd 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/index.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import BackInStockSubscriptionsProvider from '@shopgate/engage/back-in-stock/providers/BackInStockSubscriptionsProvider'; +import { BackInStockSubscriptionsProvider } from '@shopgate/engage/back-in-stock'; import List from './components/List'; /** diff --git a/libraries/engage/back-in-stock/hooks/index.js b/libraries/engage/back-in-stock/hooks/index.js index ea23447a8e..84453cc9ef 100644 --- a/libraries/engage/back-in-stock/hooks/index.js +++ b/libraries/engage/back-in-stock/hooks/index.js @@ -1,9 +1,9 @@ import React from 'react'; -import BackInStockSubscriptionsProvider from '@shopgate/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.context'; +import { BackInStockSubscriptionsProviderContext } from '@shopgate/engage/back-in-stock'; /** * Injects the Back in Stock Subscription Context * @returns {JSX} */ export const useBackInStockSubscriptionsContext = () => - React.useContext(BackInStockSubscriptionsProvider); + React.useContext(BackInStockSubscriptionsProviderContext); diff --git a/libraries/engage/back-in-stock/index.js b/libraries/engage/back-in-stock/index.js index bd1aaf1d78..16b051397b 100644 --- a/libraries/engage/back-in-stock/index.js +++ b/libraries/engage/back-in-stock/index.js @@ -1,5 +1,7 @@ // CONSTANTS export * from './constants'; +export * from './constants/Pipelines'; +export * from './constants/Portals'; // Components export { default as BackInStockReminders } from './components/Subscriptions'; @@ -7,8 +9,18 @@ export { default as BackInStockButton } from './components/BackInStockButton'; export { default as BackInStockButtonPortal } from './components/BackInStockButtonPortal'; export { default as CharacteristicsButton } from './components/CharacteristicsButton'; +// ACTIONS +export * from './actions'; + +// HOOKs +export * from './hooks'; + // STREAMS export * from './streams'; // SELECTORS export * from './selectors'; + +// --------------- CONTEXTS / PROVIDERS --------------- // +export { default as BackInStockSubscriptionsProviderContext } from './providers/BackInStockSubscriptionsProvider.context'; +export { default as BackInStockSubscriptionsProvider } from './providers/BackInStockSubscriptionsProvider'; diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx index a42dbd948c..42c6d76c9d 100644 --- a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx @@ -1,12 +1,12 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import { NavDrawer, NotificationIcon, Portal } from '@shopgate/engage/components'; -import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; import { + BACK_IN_STOCK_PATTERN, NAV_MENU_BACK_IN_STOCK, NAV_MENU_BACK_IN_STOCK_AFTER, NAV_MENU_BACK_IN_STOCK_BEFORE, -} from '@shopgate/engage/back-in-stock/constants/Portals'; +} from '@shopgate/engage/back-in-stock'; import navDrawerConnect from '../../../../connector'; import portalProps from '../../../../portalProps'; import Badge from './components/Badge'; From 11708386552b7527ee3b6d1d34efd3ecaf3b65da Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 14 Feb 2024 12:27:09 +0100 Subject: [PATCH 25/55] CURB-3886 Improve useBackInStockSubscriptionsContext documentation --- libraries/engage/back-in-stock/hooks/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/engage/back-in-stock/hooks/index.js b/libraries/engage/back-in-stock/hooks/index.js index 84453cc9ef..11bbee28dc 100644 --- a/libraries/engage/back-in-stock/hooks/index.js +++ b/libraries/engage/back-in-stock/hooks/index.js @@ -2,7 +2,7 @@ import React from 'react'; import { BackInStockSubscriptionsProviderContext } from '@shopgate/engage/back-in-stock'; /** - * Injects the Back in Stock Subscription Context + * Gives access to the values which the context BackInStockSubscriptionsProvider provide * @returns {JSX} */ export const useBackInStockSubscriptionsContext = () => From 39e71f6348a8bd2d72950d6a22e045353fb9ef10 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 14 Feb 2024 12:28:25 +0100 Subject: [PATCH 26/55] CURB-3886 Rename useBackInStockSubscriptions --- .../components/Subscriptions/components/List/index.jsx | 4 ++-- .../Subscriptions/components/Subscription/index.jsx | 4 ++-- libraries/engage/back-in-stock/hooks/index.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx index 16f369f3b5..7ab4f42ad3 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx @@ -3,7 +3,7 @@ import { css } from 'glamor'; import LoadingIndicator from '@shopgate/pwa-ui-shared/LoadingIndicator'; import { Accordion, Card } from '@shopgate/engage/components'; import { i18n } from '@shopgate/engage/core'; -import { useBackInStockSubscriptionsContext } from '../../../../hooks'; +import { useBackInStockSubscriptions } from '../../../../hooks'; import Subscription from '../Subscription'; const styles = { @@ -32,7 +32,7 @@ const List = () => { const { isInitial, groupedSubscriptions, - } = useBackInStockSubscriptionsContext(); + } = useBackInStockSubscriptions(); const renderLabel = useCallback(groupKey =>
diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx index cdd94e0623..64c4eb001e 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx @@ -17,7 +17,7 @@ import { BackInStockButton } from '@shopgate/engage/back-in-stock/'; import { getThemeSettings, i18n, } from '@shopgate/engage/core'; -import { useBackInStockSubscriptionsContext } from '@shopgate/engage/back-in-stock/hooks'; +import { useBackInStockSubscriptions } from '@shopgate/engage/back-in-stock/hooks'; const { variables } = themeConfig; @@ -98,7 +98,7 @@ const Subscription = ({ const { subscriptionCode, product } = subscription; const { removeBackInStockSubscription, - } = useBackInStockSubscriptionsContext(); + } = useBackInStockSubscriptions(); const { ListImage: gridResolutions } = getThemeSettings('AppImages') || {}; const currency = product.price?.currency || 'EUR'; const defaultPrice = product.price?.unitPrice || 0; diff --git a/libraries/engage/back-in-stock/hooks/index.js b/libraries/engage/back-in-stock/hooks/index.js index 11bbee28dc..3cef9f2ee4 100644 --- a/libraries/engage/back-in-stock/hooks/index.js +++ b/libraries/engage/back-in-stock/hooks/index.js @@ -5,5 +5,5 @@ import { BackInStockSubscriptionsProviderContext } from '@shopgate/engage/back-i * Gives access to the values which the context BackInStockSubscriptionsProvider provide * @returns {JSX} */ -export const useBackInStockSubscriptionsContext = () => +export const useBackInStockSubscriptions = () => React.useContext(BackInStockSubscriptionsProviderContext); From 033c1897f543e54eb6e8090c2b10de9a17108d0d Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 14 Feb 2024 12:38:26 +0100 Subject: [PATCH 27/55] CURB-3886 Refactor getSubscriptionByVariant --- .../components/BackInStockButtonPortal/connector.js | 5 +++-- .../components/Subscription/connector.js | 11 +++++++---- libraries/engage/back-in-stock/selectors/index.js | 8 ++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/connector.js b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/connector.js index 4965a918b5..6a6fe7af6e 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/connector.js +++ b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/connector.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { getIsBackInStockEnabled, - getSubscriptionByVariant, + makeGetSubscriptionByProduct, } from '@shopgate/engage/back-in-stock'; import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; import { @@ -15,8 +15,9 @@ import { grantPushPermissions } from '@shopgate/engage/core'; */ const makeMapStateToProps = () => { const getProductType = makeGetProductType(); + const getSubscriptionByProduct = makeGetSubscriptionByProduct(); return (state, props) => ({ - subscription: getSubscriptionByVariant(state, props), + subscription: getSubscriptionByProduct(state, props), productType: getProductType(state, props), stock: getProductAvailability(state, props), isBackInStockEnabled: getIsBackInStockEnabled(state, props), diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js index 2e239542f5..9422a5175d 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js @@ -1,13 +1,16 @@ import { connect } from 'react-redux'; import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; -import { getSubscriptionByVariant } from '@shopgate/engage/back-in-stock'; +import { makeGetSubscriptionByProduct } from '@shopgate/engage/back-in-stock'; /** * @return {Object} The extended component props. */ -const makeMapStateToProps = () => (state, props) => ({ - subscription: getSubscriptionByVariant(state, props), -}); +const makeMapStateToProps = () => { + const getSubscriptionByProduct = makeGetSubscriptionByProduct(); + return (state, props) => ({ + subscription: getSubscriptionByProduct(state, props), + }); +}; const mapDispatchToProps = { addBackInStockSubscription, diff --git a/libraries/engage/back-in-stock/selectors/index.js b/libraries/engage/back-in-stock/selectors/index.js index 1b7a400b0e..72d1b37e2a 100644 --- a/libraries/engage/back-in-stock/selectors/index.js +++ b/libraries/engage/back-in-stock/selectors/index.js @@ -27,16 +27,16 @@ export const getBackInStockSubscriptionsInitial = state => state.backInStock.isI * a product / variant or null by its variantId / productId * @returns {Function} */ -export const getSubscriptionByVariant = createSelector( +export const makeGetSubscriptionByProduct = () => createSelector( (state, props = {}) => (props.variantId ? props.variantId : props.productId), getBackInStockSubscriptions, - (variantId, subscriptions) => { - if (!variantId) { + (requestedProductCode, subscriptions) => { + if (!requestedProductCode) { return false; } return subscriptions.find(({ productCode }) => - productCode === variantId) || null; + productCode === requestedProductCode) || null; } ); From 43088497bae22ec3fe233c9cb9322c5efd9ded45 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 14 Feb 2024 12:42:00 +0100 Subject: [PATCH 28/55] CURB-3886 Refactor getSubscriptionByCharacteristics --- .../components/CharacteristicsButton/connector.js | 3 ++- libraries/engage/back-in-stock/selectors/index.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js index a3c52a142d..4b669785a3 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { getIsBackInStockEnabled, - getSubscriptionByCharacteristics, + makeGetSubscriptionByCharacteristics, } from '@shopgate/engage/back-in-stock'; import { getVariantAvailabilityByCharacteristics, @@ -17,6 +17,7 @@ import { */ const makeMapStateToProps = () => { const getProductByCharacteristics = makeGetProductByCharacteristics(); + const getSubscriptionByCharacteristics = makeGetSubscriptionByCharacteristics(); return (state, props) => { const variant = getProductByCharacteristics(state, props) || {}; diff --git a/libraries/engage/back-in-stock/selectors/index.js b/libraries/engage/back-in-stock/selectors/index.js index 72d1b37e2a..71ac6ee409 100644 --- a/libraries/engage/back-in-stock/selectors/index.js +++ b/libraries/engage/back-in-stock/selectors/index.js @@ -45,7 +45,7 @@ export const makeGetSubscriptionByProduct = () => createSelector( * a product / variant by its characteristics * @returns {Function} */ -export const getSubscriptionByCharacteristics = createSelector( +export const makeGetSubscriptionByCharacteristics = () => createSelector( getProductVariants, (state, props = {}) => props.characteristics, getBackInStockSubscriptions, From 08752d1f251c6b19816b7b63a2304717c85606dd Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 14 Feb 2024 15:00:10 +0100 Subject: [PATCH 29/55] CURB-3886 Refactor grantPermissions and grantPushPermissions --- .../engage/core/actions/grantPermissions.js | 37 +++++++++++++++---- .../core/actions/grantPushPermissions.js | 28 +++++++------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/libraries/engage/core/actions/grantPermissions.js b/libraries/engage/core/actions/grantPermissions.js index 7a07caa889..48e45b66c6 100644 --- a/libraries/engage/core/actions/grantPermissions.js +++ b/libraries/engage/core/actions/grantPermissions.js @@ -1,7 +1,8 @@ import event from '@shopgate/pwa-core/classes/Event'; import { APP_EVENT_APPLICATION_WILL_ENTER_FOREGROUND } from '@shopgate/pwa-core/constants/AppEvents'; import openAppSettings from '@shopgate/pwa-core/commands/openAppSettings'; -import showModal from '@shopgate/pwa-common/actions/modal/showModal'; +// import showModal from '@shopgate/pwa-common/actions/modal/showModal'; +import { showModal } from '@shopgate/engage/core'; import { STATUS_DENIED, STATUS_GRANTED, @@ -23,6 +24,12 @@ import { logger } from '@shopgate/pwa-core/helpers'; * @param {string} options.permissionId The id of the permission to request. * @param {boolean} [options.useSettingsModal=false] Whether in case of declined permissions a modal * shall be presented, which redirects to the app settings. + * @param {Object} [options.requestModal={}] Options for the request permission modal. + * @param {string} options.requestModal.title Modal title. + * @param {string} options.requestModal.message Modal message. + * @param {string} options.requestModal.confirm Label for the confirm button. + * @param {string} options.requestModal.dismiss Label for the dismiss button. + * @param {Object} options.requestModal.params Additional parameters for i18n strings. * @param {Object} [options.modal={}] Options for the settings modal. * @param {string} options.modal.title Modal title. * @param {string} options.modal.message Modal message. @@ -35,6 +42,8 @@ const grantPermissions = (options = {}) => dispatch => new Promise(async (resolv const { permissionId, useSettingsModal = false, + useRequestModal = false, + requestModal: requestModalOptions = {}, modal: modalOptions = {}, } = options; @@ -57,13 +66,27 @@ const grantPermissions = (options = {}) => dispatch => new Promise(async (resolv // The user never seen the permissions dialog yet, or temporary denied the permissions (Android). if (status === STATUS_NOT_DETERMINED) { - // Trigger the native permissions dialog. - [{ status }] = await requestAppPermissions([{ permissionId }]); + if (useRequestModal) { + const requestAllowed = await dispatch(showModal({ + message: requestModalOptions.message, + confirm: requestModalOptions.confirm, + dismiss: requestModalOptions.dismiss, + params: requestModalOptions.params, + })); - // The user denied the permissions within the native dialog. - if ([STATUS_DENIED, STATUS_NOT_DETERMINED].includes(status)) { - resolve(false); - return; + if (requestAllowed === false) { + resolve(false); + return; + } + + // Trigger the native permissions dialog. + [{ status }] = await requestAppPermissions([{ permissionId }]); + + // The user denied the permissions within the native dialog. + if ([STATUS_DENIED, STATUS_NOT_DETERMINED].includes(status)) { + resolve(false); + return; + } } } diff --git a/libraries/engage/core/actions/grantPushPermissions.js b/libraries/engage/core/actions/grantPushPermissions.js index 8eb87f3143..42ae748953 100644 --- a/libraries/engage/core/actions/grantPushPermissions.js +++ b/libraries/engage/core/actions/grantPushPermissions.js @@ -2,7 +2,6 @@ import { PERMISSION_ID_PUSH, STATUS_GRANTED, } from '@shopgate/pwa-core/constants/AppPermissions'; -import showModal from '@shopgate/pwa-common/actions/modal/showModal'; import { getAppPermissions } from '@shopgate/pwa-core'; import grantPermissions from './grantPermissions'; @@ -13,6 +12,12 @@ import grantPermissions from './grantPermissions'; * @param {Object} options Action options. * @param {boolean} [options.useSettingsModal=false] Whether in case of declined permissions a modal * shall be presented, which redirects to the app settings. + * @param {Object} [options.requestModal={}] Options for the request permissions modal. + * @param {string} options.requestModal.title Modal title. + * @param {string} options.requestModal.message Modal message. + * @param {string} options.requestModal.confirm Label for the confirm button. + * @param {string} options.requestModal.dismiss Label for the dismiss button. + * @param {Object} options.requestModal.params Additional parameters for i18n strings. * @param {Object} [options.modal={}] Options for the settings modal. * @param {string} options.modal.title Modal title. * @param {string} options.modal.message Modal message. @@ -22,7 +27,7 @@ import grantPermissions from './grantPermissions'; * @return { Function } A redux thunk. */ const grantPushPermissions = (options = {}) => dispatch => new Promise(async (resolve) => { - const { useSettingsModal = true, modal = {} } = options; + const { useSettingsModal = true, modal = {}, requestModal = {} } = options; const [{ status }] = await getAppPermissions([PERMISSION_ID_PUSH]); if (status === STATUS_GRANTED) { @@ -30,18 +35,6 @@ const grantPushPermissions = (options = {}) => dispatch => new Promise(async (re return; } - const openSettings = await dispatch(showModal({ - message: 'permissions.back_in_stock_push_notifications.message', - confirm: 'permissions.back_in_stock_push_notifications.confirm', - dismiss: 'permissions.back_in_stock_push_notifications.dismiss', - params: {}, - })); - - if (openSettings === false) { - resolve(false); - return; - } - const allowed = await dispatch(grantPermissions({ permissionId: PERMISSION_ID_PUSH, useSettingsModal, @@ -51,6 +44,13 @@ const grantPushPermissions = (options = {}) => dispatch => new Promise(async (re confirm: 'permissions.access_denied.settings_button', ...modal, }, + requestModal: { + message: 'permissions.back_in_stock_push_notifications.message', + confirm: 'permissions.back_in_stock_push_notifications.confirm', + dismiss: 'permissions.back_in_stock_push_notifications.dismiss', + ...requestModal, + }, + })); resolve(allowed); From 2f64985adc4c5e18e0a9313e6cae60a53a24e04d Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 14 Feb 2024 16:02:02 +0100 Subject: [PATCH 30/55] CURB-3886 Update translations --- themes/theme-gmd/locale/de-DE.json | 24 ++++++++++++------------ themes/theme-gmd/locale/en-US.json | 4 ++-- themes/theme-gmd/locale/es-ES.json | 23 ++++++++++++++++++++++- themes/theme-gmd/locale/fr-FR.json | 23 ++++++++++++++++++++++- themes/theme-gmd/locale/it-IT.json | 23 ++++++++++++++++++++++- themes/theme-gmd/locale/nl-NL.json | 23 ++++++++++++++++++++++- themes/theme-gmd/locale/pl-PL.json | 23 ++++++++++++++++++++++- themes/theme-gmd/locale/pt-PT.json | 23 ++++++++++++++++++++++- themes/theme-ios11/locale/de-DE.json | 24 ++++++++++++------------ themes/theme-ios11/locale/es-ES.json | 23 ++++++++++++++++++++++- themes/theme-ios11/locale/fr-FR.json | 23 ++++++++++++++++++++++- themes/theme-ios11/locale/it-IT.json | 23 ++++++++++++++++++++++- themes/theme-ios11/locale/nl-NL.json | 23 ++++++++++++++++++++++- themes/theme-ios11/locale/pl-PL.json | 23 ++++++++++++++++++++++- themes/theme-ios11/locale/pt-PT.json | 23 ++++++++++++++++++++++- 15 files changed, 290 insertions(+), 38 deletions(-) diff --git a/themes/theme-gmd/locale/de-DE.json b/themes/theme-gmd/locale/de-DE.json index cbaf7e5785..46ee1117d4 100644 --- a/themes/theme-gmd/locale/de-DE.json +++ b/themes/theme-gmd/locale/de-DE.json @@ -20,19 +20,19 @@ "reviews": "Bewertungen", "favorites": "Merkliste", "scanner": "Scanner", - "back_in_stock": "Auf Lager Erinnerungen" + "back_in_stock": "Wieder-auf-Lager Benachrichtigungen" }, "back_in_stock": { "list_states": { - "active": "Aktive Erinnerungen", - "past": "Abgelaufene Erinnerungen" + "active": "Aktive Benachrichtigungen", + "past": "Vergangene Benachrichtigungen" }, - "empty_list_reminder": "Sie haben keine Erinnerungen in dieser Liste.", - "get_notified": "Erinnere mich", - "we_will_remind_you": "Sie werden benachrichtigt.", + "empty_list_reminder": "Sie haben keine Benachrichtigungen konfiguriert", + "get_notified": "Benachrichtige mich", + "we_will_remind_you": "Du wirst benachrichtigt", "add_back_in_stock_success_modal": { - "title": "Erinnerung hinzugefügt!", - "message": "Wir werden Ihnen eine Push Nachricht senden wenn das Produkt wieder verfügbar ist. Sie können Ihre Erinnerungen in den Einstellungen verwalten." + "title": "Benachrichtigung hinzugefügt!", + "message": "Wir senden dir eine Push-Benachrichtigung wenn das Produkt wieder verfügbar ist. Du kannst diese Benachrichtigungen in den Einstellungen verwalten." } }, "favorites": { @@ -253,7 +253,7 @@ "more": "Mehr", "about": "Über uns" }, - "back_in_stock": "Auf Lager Erinnerungen", + "back_in_stock": "Wieder-auf-Lager Benachrichtigungen", "back": "Zurück zu {title}", "open_menu": "Menü öffnen" }, @@ -284,14 +284,14 @@ }, "permissions": { "back_in_stock_push_notifications": { - "message": "Bitte erlauben Sie Push Nachrichten im nächsten Schritt damit wir Sie Benachrichtigen können wenn das Produkt wieder auf Lager ist.", - "confirm": "Push Nachrichten erlauben", + "message": "Bitte erlaube Push-Benachrichtigungen im nächsten Schritt, damit wir dir mitteilen können wenn das Produkt wieder verfügbar ist.", + "confirm": "Benachrichtigungen erlauben", "dismiss": "Abbrechen" }, "access_denied": { "settings_button": "Zu den Einstellungen", "camera_message": "Diese Funktion benötigt Zugriff auf die Kamera. Bitte erlauben Sie den Zugriff in den Einstellungen.", - "push_message": "Dieser Service benötigt Ihre Berechtigung für Push Nachrichten. Bitte erlauben Sie den Zugriff in den Einstellungen.", + "push_message": "Du hast Push-Benachrichtigungen für diese App deaktiviert. Bitte gehe in die Einstellungen deines Gerätes um Benachrichtigungen für diese App zu aktivieren.", "geolocation_message": "Wir benötigen Zugriff auf den Standort um Filialen in der Nähe zu zeigen." } }, diff --git a/themes/theme-gmd/locale/en-US.json b/themes/theme-gmd/locale/en-US.json index e139e8ed6c..4fe2fa09ba 100644 --- a/themes/theme-gmd/locale/en-US.json +++ b/themes/theme-gmd/locale/en-US.json @@ -232,8 +232,8 @@ "logout_message": "You have been logged out.", "error": "Your username and password don't match any account" }, - "navigation": { "login_register": "Login / Register", + "navigation": { "your_account": "Your Account", "home": "Home", "categories": "Categories", @@ -281,7 +281,7 @@ "qrCode": "We couldn't find a result for this QR code.", "barCode": "Product not found." } - }, + }, "permissions": { "back_in_stock_push_notifications": { "message": "Please allow push notifications in the next step, so that we can send you a notification when the product is back in stock.", diff --git a/themes/theme-gmd/locale/es-ES.json b/themes/theme-gmd/locale/es-ES.json index a8d38ac3ee..0d00d8b791 100644 --- a/themes/theme-gmd/locale/es-ES.json +++ b/themes/theme-gmd/locale/es-ES.json @@ -19,7 +19,21 @@ "shipping": "Envío", "reviews": "Comentarios", "favorites": "Favoritos", - "scanner": "Escáner" + "scanner": "Escáner", + "back_in_stock": "Recordatorio de existencias" + }, + "back_in_stock": { + "list_states": { + "active": "Recordatorios activos", + "past": "Recordatorios anteriores" + }, + "empty_list_reminder": "No tienes recordatorios en esta lista.", + "get_notified": "Recibir notificaciones", + "we_will_remind_you": "Se lo recordaremos.", + "add_back_in_stock_success_modal": { + "title": "Recordatorio de existencias!", + "message": "Te enviaremos una notificación push cuando el producto vuelva a estar disponible. Puedes gestionar tus notificaciones en los ajustes." + } }, "favorites": { "add": "Agregar a favoritos", @@ -222,6 +236,7 @@ "my_orders": "Mis pedidos", "cart": "Cesta de la compra", "scanner": "Escáner", + "back_in_stock": "Recordatorio de existencias", "shipping": "Métodos de envío", "about": "Sobre nosotros", "payment": "Métodos de pago", @@ -263,9 +278,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "Permita las notificaciones push en el siguiente paso para que podamos enviarle una notificación cuando el producto vuelva a estar disponible.", + "confirm": "Permitir notificaciones push", + "dismiss": "Cancelar" + }, "access_denied": { "settings_button": "Vaya a configuración", "camera_message": "Esta característica requiere acceso a su cámara. Por favor, permita el acceso desde la configuración.", + "push_message": "Esta función requiere acceso a las notificaciones push. Por favor, permita el acceso en la configuración.", "geolocation_message": "Para encontrar tiendas cerca de donde está, vaya a Configuración y habilite los permisos de ubicación." } }, diff --git a/themes/theme-gmd/locale/fr-FR.json b/themes/theme-gmd/locale/fr-FR.json index ea4f2c9637..44644d1674 100644 --- a/themes/theme-gmd/locale/fr-FR.json +++ b/themes/theme-gmd/locale/fr-FR.json @@ -19,7 +19,21 @@ "shipping": "Livraison", "reviews": "Revues", "favorites": "Favorits", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Retour en stock Rappels" + }, + "back_in_stock": { + "list_states": { + "active": "Rappels actifs", + "past": "Rappels du passé" + }, + "empty_list_reminder": "Vous n'avez pas de rappels dans cette liste.", + "get_notified": "Recevoir une notification", + "we_will_remind_you": "Nous vous le rappelons.", + "add_back_in_stock_success_modal": { + "title": "Ajout d'un rappel de stock !", + "message": "Nous vous enverrons une notification push lorsque le produit sera à nouveau en stock. Vous pouvez gérer vos notifications dans les paramètres." + } }, "favorites": { "add": "Ajouter aux Favoris", @@ -222,6 +236,7 @@ "my_orders": "Mes Commandes", "cart": "Panier", "scanner": "Scanner", + "back_in_stock": "Rappel de stock", "shipping": "Méthodes de livraison", "about": "Mentions légales", "payment": "Méthodes de paiement", @@ -263,9 +278,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "Veuillez autoriser les notifications push à l'étape suivante, afin que nous puissions vous envoyer une notification lorsque le produit est de nouveau en stock.", + "confirm": "Autoriser les notifications push", + "dismiss": "Annuler" + }, "access_denied": { "settings_button": "Aller dans paramètres", "camera_message": "Cette fonctionnalité nécessite un accès à votre appareil photo. Veuillez autoriser l'accès dans la fonction paramètres.", + "push_message": "Cette fonctionnalité nécessite l'accès aux notifications push. Veuillez autoriser l'accès dans les paramètres.", "geolocation_message": "Pour trouver des magasins près de chez vous, allez dans Paramètres et activez l’autorisation de géolocalisation." } }, diff --git a/themes/theme-gmd/locale/it-IT.json b/themes/theme-gmd/locale/it-IT.json index 8cbb16c91d..67de119cb9 100644 --- a/themes/theme-gmd/locale/it-IT.json +++ b/themes/theme-gmd/locale/it-IT.json @@ -19,7 +19,21 @@ "shipping": "Spedizione", "reviews": "Recensioni", "favorites": "Favoriti", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Promemoria per il ritorno in magazzino" + }, + "back_in_stock": { + "list_states": { + "active": "Promemoria attivi", + "past": "Promemoria del passato" + }, + "empty_list_reminder": "Non ci sono promemoria in questo elenco.", + "get_notified": "Ricevere una notifica", + "we_will_remind_you": "Ve lo ricordiamo.", + "add_back_in_stock_success_modal": { + "title": "Aggiunto un promemoria sul back-in-stock!", + "message": "Vi invieremo una notifica push quando il prodotto sarà di nuovo disponibile. È possibile gestire le notifiche nelle impostazioni." + } }, "favorites": { "add": "Aggiungi ai favoriti", @@ -222,6 +236,7 @@ "my_orders": "I miei ordini", "cart": "Carrello spesa", "scanner": "Scanner", + "back_in_stock": "Promemoria per il ritorno in magazzino", "shipping": "Modalità di spedizione", "about": "Su di noi", "payment": "Modalità di pagamento", @@ -263,9 +278,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "Nella fase successiva, consentire le notifiche push, in modo da poter inviare una notifica quando il prodotto è di nuovo disponibile.", + "confirm": "Consentire le notifiche push", + "dismiss": "Annullamento" + }, "access_denied": { "settings_button": "Vai alle impostazioni", "camera_message": "Questa funzione richiede l'accesso alla tua fotocamera. Consenti l'accesso nelle impostazioni per favore.", + "push_message": "Questa funzione richiede l'accesso alle notifiche push. Consentire l'accesso nelle impostazioni.", "geolocation_message": "Per trovare negozi vicino a te, vai su Impostazioni e abilita i permessi di accesso alla localizzazione." } }, diff --git a/themes/theme-gmd/locale/nl-NL.json b/themes/theme-gmd/locale/nl-NL.json index fdccc92212..4edc31c474 100644 --- a/themes/theme-gmd/locale/nl-NL.json +++ b/themes/theme-gmd/locale/nl-NL.json @@ -19,7 +19,21 @@ "shipping": "Verzending", "reviews": "Beoordelingen", "favorites": "Favorieten", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Terug in voorraad Herinneringen" + }, + "back_in_stock": { + "list_states": { + "active": "Actieve herinneringen", + "past": "Herinneringen uit het verleden" + }, + "empty_list_reminder": "Je hebt geen herinneringen in deze lijst.", + "get_notified": "Ontvang bericht", + "we_will_remind_you": "We zullen je eraan herinneren.", + "add_back_in_stock_success_modal": { + "title": "Back-in-Stock herinnering toegevoegd!", + "message": "We sturen je een pushmelding wanneer het product weer op voorraad is. Je kunt je meldingen beheren in de instellingen." + } }, "favorites": { "add": "Voeg aan favorieten toe", @@ -222,6 +236,7 @@ "my_orders": "Mijn bestellingen", "cart": "Winkelwagen", "scanner": "Scanner", + "back_in_stock": "Terug in voorraad herinnering", "shipping": "Verzendmethoden", "about": "Over ons", "payment": "Uw betalingswens", @@ -263,9 +278,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "Sta in de volgende stap pushmeldingen toe, zodat we je een melding kunnen sturen wanneer het product weer op voorraad is.", + "confirm": "Pushmeldingen toestaan", + "dismiss": "Annuleren" + }, "access_denied": { "settings_button": "Ga naar instellingen", "camera_message": "Deze functie vereist toegang tot uw camera. Gelieve toegang te verlenen in de instellingen.", + "push_message": "Deze functie vereist toegang tot pushmeldingen. Sta toegang toe in de instellingen.", "geolocation_message": "Ga naar Instellingen en schakel locatiemachtigingen in om winkels bij u in de buurt te vinden." } }, diff --git a/themes/theme-gmd/locale/pl-PL.json b/themes/theme-gmd/locale/pl-PL.json index 312539ebb7..f3c7a1edc6 100644 --- a/themes/theme-gmd/locale/pl-PL.json +++ b/themes/theme-gmd/locale/pl-PL.json @@ -19,7 +19,21 @@ "shipping": "Wysyłka", "reviews": "Recenzje", "favorites": "Lista życzeń", - "scanner": "Skaner" + "scanner": "Skaner", + "back_in_stock": "Przypomnienia o powrocie do magazynu" + }, + "back_in_stock": { + "list_states": { + "active": "Aktywne przypomnienia", + "past": "Przypomnienia z przeszłości" + }, + "empty_list_reminder": "Na tej liście nie ma przypomnień.", + "get_notified": "Otrzymuj powiadomienia", + "we_will_remind_you": "Przypominamy.", + "add_back_in_stock_success_modal": { + "title": "Dodano przypomnienie o dostępności w magazynie!", + "message": "Wyślemy Ci powiadomienie push, gdy produkt będzie ponownie dostępny w magazynie. Powiadomieniami można zarządzać w ustawieniach." + } }, "favorites": { "add": "Dodaj do listy obserwowanych", @@ -227,6 +241,7 @@ "my_orders": "Moje polecenia", "cart": "Koszyk na zakupy", "scanner": "Skaner", + "back_in_stock": "Przypomnienie o powrocie do magazynu", "shipping": "Metody wysyłki", "about": "Nota prawna", "payment": "Metody płatności", @@ -268,9 +283,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "W następnym kroku zezwól na powiadomienia push, abyśmy mogli wysłać Ci powiadomienie, gdy produkt będzie ponownie dostępny w magazynie.", + "confirm": "Zezwalaj na powiadomienia push", + "dismiss": "Anuluj" + }, "access_denied": { "settings_button": "Przejdź do ustawień", "camera_message": "Ta funkcja wymaga dostępu do aparatu. W ustawieniach należy zezwolić na dostęp.", + "push_message": "Ta funkcja wymaga dostępu do powiadomień push. Zezwól na dostęp w ustawieniach.", "geolocation_message": "Potrzebujemy dostępu do lokalizacji, aby pokazać pobliskie sklepy." } }, diff --git a/themes/theme-gmd/locale/pt-PT.json b/themes/theme-gmd/locale/pt-PT.json index 77b849c5bb..48f76a8627 100644 --- a/themes/theme-gmd/locale/pt-PT.json +++ b/themes/theme-gmd/locale/pt-PT.json @@ -19,7 +19,21 @@ "shipping": "Envio", "reviews": "Avaliações", "favorites": "Favoritos", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Lembretes de reposição de stock" + }, + "back_in_stock": { + "list_states": { + "active": "Lembretes activos", + "past": "Lembretes anteriores" + }, + "empty_list_reminder": "Não tem lembretes nesta lista.", + "get_notified": "Ser notificado", + "we_will_remind_you": "Lembrar-lhe-emos.", + "add_back_in_stock_success_modal": { + "title": "Lembrete de stock adicionado!", + "message": "Enviar-lhe-emos uma notificação push quando o produto estiver novamente em stock. Pode gerir as suas notificações nas definições." + } }, "favorites": { "add": "Adicionar aos favoritos", @@ -222,6 +236,7 @@ "my_orders": "Meus Pedidos", "cart": "Carrinho de Compras", "scanner": "Scanner", + "back_in_stock": "Lembrete de regresso ao stock", "shipping": "Métodos de Envio", "about": "Entre em Contato Conosco", "payment": "Métodos de Pagamento", @@ -263,9 +278,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "Autorize as notificações push no passo seguinte, para que possamos enviar-lhe uma notificação quando o produto estiver novamente em stock.", + "confirm": "Permitir notificações push", + "dismiss": "Cancelar" + }, "access_denied": { "settings_button": "Acesse configurações", "camera_message": "Esta funcionalidade requer acesso à sua câmara. Por favor autorize o acesso nas configurações.", + "push_message": "Esta funcionalidade requer acesso a notificações push. Autorize o acesso nas definições.", "geolocation_message": "Para encontrar lojas perto de você, acesse Configurações e ative as permissões de localização." } }, diff --git a/themes/theme-ios11/locale/de-DE.json b/themes/theme-ios11/locale/de-DE.json index 825fab86af..eb22ae1d89 100644 --- a/themes/theme-ios11/locale/de-DE.json +++ b/themes/theme-ios11/locale/de-DE.json @@ -21,19 +21,19 @@ "browse": "Durchsuchen", "favorites": "Merkliste", "scanner": "Scanner", - "back_in_stock": "Auf Lager Erinnerungen" + "back_in_stock": "Wieder-auf-Lager Benachrichtigungen" }, "back_in_stock": { "list_states": { - "active": "Aktive Erinnerungen", - "past": "Abgelaufene Erinnerungen" + "active": "Aktive Benachrichtigungen", + "past": "Vergangene Benachrichtigungen" }, - "empty_list_reminder": "Sie haben keine Erinnerungen in dieser Liste.", - "get_notified": "Erinnere mich", - "we_will_remind_you": "Sie werden benachrichtigt.", + "empty_list_reminder": "Sie haben keine Benachrichtigungen konfiguriert.", + "get_notified": "Benachrichtige mich", + "we_will_remind_you": "Du wirst benachrichtigt.", "add_back_in_stock_success_modal": { - "title": "Erinnerung hinzugefügt!", - "message": "Wir werden Ihnen eine Push Nachricht senden wenn das Produkt wieder verfügbar ist. Sie können Ihre Erinnerungen in den Einstellungen verwalten." + "title": "Benachrichtigung hinzugefügt!", + "message": "Wir senden dir eine Push-Benachrichtigung wenn das Produkt wieder verfügbar ist. Du kannst diese Benachrichtigungen in den Einstellungen verwalten." } }, "favorites": { @@ -254,7 +254,7 @@ "logout": "Abmelden", "store_information": "Über uns", "more_menu": "Mehr", - "back_in_stock": "Auf Lager Erinnerungen", + "back_in_stock": "Wieder-auf-Lager Benachrichtigungen", "back": "Zurück zu {title}" }, "reviews": { @@ -291,14 +291,14 @@ }, "permissions": { "back_in_stock_push_notifications": { - "message": "Bitte erlauben Sie Push Nachrichten im nächsten Schritt damit wir Sie Benachrichtigen können wenn das Produkt wieder auf Lager ist.", - "confirm": "Push Nachrichten erlauben", + "message": "Bitte erlaube Push-Benachrichtigungen im nächsten Schritt, damit wir dir mitteilen können wenn das Produkt wieder verfügbar ist.", + "confirm": "Benachrichtigungen erlauben", "dismiss": "Abbrechen" }, "access_denied": { "settings_button": "Zu den Einstellungen", "camera_message": "Diese Funktion benötigt Zugriff auf die Kamera. Bitte erlauben Sie den Zugriff in den Einstellungen.", - "push_message": "Dieser Service benötigt Ihre Berechtigung für Push Nachrichten. Bitte erlauben Sie den Zugriff in den Einstellungen.", + "push_message": "Du hast Push-Benachrichtigungen für diese App deaktiviert. Bitte gehe in die Einstellungen deines Gerätes um Benachrichtigungen für diese App zu aktivieren.", "geolocation_message": "Wir benötigen Zugriff auf den Standort um Filialen in der Nähe zu zeigen." } }, diff --git a/themes/theme-ios11/locale/es-ES.json b/themes/theme-ios11/locale/es-ES.json index c82ad4c0db..7a4bd02827 100644 --- a/themes/theme-ios11/locale/es-ES.json +++ b/themes/theme-ios11/locale/es-ES.json @@ -20,7 +20,21 @@ "reviews": "Comentarios", "browse": "Buscar", "favorites": "Favoritos", - "scanner": "Escáner" + "scanner": "Escáner", + "back_in_stock": "Recordatorio de existencias" + }, + "back_in_stock": { + "list_states": { + "active": "Recordatorios activos", + "past": "Recordatorios anteriores" + }, + "empty_list_reminder": "No tienes recordatorios en esta lista.", + "get_notified": "Recibir notificaciones", + "we_will_remind_you": "Se lo recordaremos.", + "add_back_in_stock_success_modal": { + "title": "Recordatorio de existencias!", + "message": "Te enviaremos una notificación push cuando el producto vuelva a estar disponible. Puedes gestionar tus notificaciones en los ajustes." + } }, "favorites": { "add": "Agregar a favoritos", @@ -223,6 +237,7 @@ "categories": "Categorías", "my_orders": "Mis pedidos", "cart": "Cesta de la compra", + "back_in_stock": "Recordatorio de existencias", "shipping": "Métodos de envío", "about": "Sobre", "contact": "Contacto", @@ -269,9 +284,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "Permita las notificaciones push en el siguiente paso para que podamos enviarle una notificación cuando el producto vuelva a estar disponible.", + "confirm": "Permitir notificaciones push", + "dismiss": "Cancelar" + }, "access_denied": { "settings_button": "Vaya a configuración", "camera_message": "Esta característica requiere acceso a su cámara. Por favor, permita el acceso desde la configuración.", + "push_message": "Esta función requiere acceso a las notificaciones push. Por favor, permita el acceso en la configuración.", "geolocation_message": "Para encontrar tiendas cerca de donde está, vaya a Configuración y habilite los permisos de ubicación." } }, diff --git a/themes/theme-ios11/locale/fr-FR.json b/themes/theme-ios11/locale/fr-FR.json index 4c6b6af412..f433936897 100644 --- a/themes/theme-ios11/locale/fr-FR.json +++ b/themes/theme-ios11/locale/fr-FR.json @@ -20,7 +20,21 @@ "reviews": "Revues", "browse": "Naviguer", "favorites": "Favorits", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Retour en stock Rappels" + }, + "back_in_stock": { + "list_states": { + "active": "Rappels actifs", + "past": "Rappels du passé" + }, + "empty_list_reminder": "Vous n'avez pas de rappels dans cette liste.", + "get_notified": "Recevoir une notification", + "we_will_remind_you": "Nous vous le rappelons.", + "add_back_in_stock_success_modal": { + "title": "Ajout d'un rappel de stock !", + "message": "Nous vous enverrons une notification push lorsque le produit sera à nouveau en stock. Vous pouvez gérer vos notifications dans les paramètres." + } }, "favorites": { "add": "Ajouter aux Favoris", @@ -225,6 +239,7 @@ "favorites": "Favorits", "my_orders": "Mes Commandes", "cart": "Panier", + "back_in_stock": "Rappel de stock", "shipping": "Méthodes de livraison", "about": "Mentions légales", "payment": "Méthodes de paiement", @@ -270,9 +285,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "Veuillez autoriser les notifications push à l'étape suivante, afin que nous puissions vous envoyer une notification lorsque le produit est de nouveau en stock.", + "confirm": "Autoriser les notifications push", + "dismiss": "Annuler" + }, "access_denied": { "settings_button": "Aller dans paramètres", "camera_message": "Cette fonctionnalité nécessite un accès à votre appareil photo. Veuillez autoriser l'accès dans la fonction paramètres.", + "push_message": "Cette fonctionnalité nécessite l'accès aux notifications push. Veuillez autoriser l'accès dans les paramètres.", "geolocation_message": "Pour trouver des magasins près de chez vous, allez dans Paramètres et activez l’autorisation de géolocalisation." } }, diff --git a/themes/theme-ios11/locale/it-IT.json b/themes/theme-ios11/locale/it-IT.json index 6b7f4b8022..bdfd74605e 100644 --- a/themes/theme-ios11/locale/it-IT.json +++ b/themes/theme-ios11/locale/it-IT.json @@ -20,7 +20,21 @@ "reviews": "Recensioni", "browse": "Sfoglia", "favorites": "Favoriti", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Promemoria per il ritorno in magazzino" + }, + "back_in_stock": { + "list_states": { + "active": "Promemoria attivi", + "past": "Promemoria del passato" + }, + "empty_list_reminder": "Non ci sono promemoria in questo elenco.", + "get_notified": "Ricevere una notifica", + "we_will_remind_you": "Ve lo ricordiamo.", + "add_back_in_stock_success_modal": { + "title": "Aggiunto un promemoria sul back-in-stock!", + "message": "Vi invieremo una notifica push quando il prodotto sarà di nuovo disponibile. È possibile gestire le notifiche nelle impostazioni." + } }, "favorites": { "add": "Aggiungi ai favoriti", @@ -223,6 +237,7 @@ "categories": "Categorie", "my_orders": "I miei ordini", "cart": "Carrello spesa", + "back_in_stock": "Promemoria per il ritorno in magazzino", "shipping": "Modalità di spedizione", "about": "A riguardo", "contact": "Contatta", @@ -269,9 +284,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "Nella fase successiva, consentire le notifiche push, in modo da poter inviare una notifica quando il prodotto è di nuovo disponibile.", + "confirm": "Consentire le notifiche push", + "dismiss": "Annullamento" + }, "access_denied": { "settings_button": "Vai alle impostazioni", "camera_message": "Questa funzione richiede l'accesso alla tua fotocamera. Consenti l'accesso nelle impostazioni per favore.", + "push_message": "Questa funzione richiede l'accesso alle notifiche push. Consentire l'accesso nelle impostazioni.", "geolocation_message": "Per trovare negozi vicino a te, vai su Impostazioni e abilita i permessi di accesso alla localizzazione." } }, diff --git a/themes/theme-ios11/locale/nl-NL.json b/themes/theme-ios11/locale/nl-NL.json index 938ef68744..e7abf4c6a1 100644 --- a/themes/theme-ios11/locale/nl-NL.json +++ b/themes/theme-ios11/locale/nl-NL.json @@ -20,7 +20,21 @@ "reviews": "Reviews", "browse": "Bladeren", "favorites": "Favorieten", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Terug in voorraad Herinneringen" + }, + "back_in_stock": { + "list_states": { + "active": "Actieve herinneringen", + "past": "Herinneringen uit het verleden" + }, + "empty_list_reminder": "Je hebt geen herinneringen in deze lijst.", + "get_notified": "Ontvang bericht", + "we_will_remind_you": "We zullen je eraan herinneren.", + "add_back_in_stock_success_modal": { + "title": "Back-in-Stock herinnering toegevoegd!", + "message": "We sturen je een pushmelding wanneer het product weer op voorraad is. Je kunt je meldingen beheren in de instellingen." + } }, "favorites": { "add": "Voeg aan favorieten toe", @@ -223,6 +237,7 @@ "categories": "Categorieën", "my_orders": "Mijn bestellingen", "cart": "Winkelwagen", + "back_in_stock": "Terug in voorraad herinnering", "shipping": "Verzendmethoden", "about": "Impressum", "contact": "Contact", @@ -269,9 +284,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "Sta in de volgende stap pushmeldingen toe, zodat we je een melding kunnen sturen wanneer het product weer op voorraad is.", + "confirm": "Pushmeldingen toestaan", + "dismiss": "Annuleren" + }, "access_denied": { "settings_button": "Ga naar instellingen", "camera_message": "Deze functie vereist toegang tot uw camera. Gelieve toegang te verlenen in de instellingen.", + "push_message": "Deze functie vereist toegang tot pushmeldingen. Sta toegang toe in de instellingen.", "geolocation_message": "Ga naar Instellingen en schakel locatiemachtigingen in om winkels bij u in de buurt te vinden." } }, diff --git a/themes/theme-ios11/locale/pl-PL.json b/themes/theme-ios11/locale/pl-PL.json index 05248eba07..65beef2848 100644 --- a/themes/theme-ios11/locale/pl-PL.json +++ b/themes/theme-ios11/locale/pl-PL.json @@ -20,7 +20,21 @@ "reviews": "Recenzje", "browse": "Przeglądaj stronę", "favorites": "Lista życzeń", - "scanner": "Skaner" + "scanner": "Skaner", + "back_in_stock": "Przypomnienia o powrocie do magazynu" + }, + "back_in_stock": { + "list_states": { + "active": "Aktywne przypomnienia", + "past": "Przypomnienia z przeszłości" + }, + "empty_list_reminder": "Na tej liście nie ma przypomnień.", + "get_notified": "Otrzymuj powiadomienia", + "we_will_remind_you": "Przypominamy.", + "add_back_in_stock_success_modal": { + "title": "Dodano przypomnienie o dostępności w magazynie!", + "message": "Wyślemy Ci powiadomienie push, gdy produkt będzie ponownie dostępny w magazynie. Powiadomieniami można zarządzać w ustawieniach." + } }, "favorites": { "add": "Dodaj do listy obserwowanych", @@ -229,6 +243,7 @@ "favorites": "Lista życzeń", "my_orders": "Moje polecenia", "cart": "Koszyk na zakupy", + "back_in_stock": "Przypomnienie o powrocie do magazynu", "shipping": "Metody wysyłki", "about": "Nota prawna", "contact": "Kontakt", @@ -275,9 +290,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "W następnym kroku zezwól na powiadomienia push, abyśmy mogli wysłać Ci powiadomienie, gdy produkt będzie ponownie dostępny w magazynie.", + "confirm": "Zezwalaj na powiadomienia push", + "dismiss": "Anuluj" + }, "access_denied": { "settings_button": "Przejdź do ustawień", "camera_message": "Ta funkcja wymaga dostępu do aparatu. W ustawieniach należy zezwolić na dostęp.", + "push_message": "Ta funkcja wymaga dostępu do powiadomień push. Zezwól na dostęp w ustawieniach.", "geolocation_message": "Potrzebujemy dostępu do lokalizacji, aby pokazać pobliskie sklepy." } }, diff --git a/themes/theme-ios11/locale/pt-PT.json b/themes/theme-ios11/locale/pt-PT.json index 4726ba4a21..3289538218 100644 --- a/themes/theme-ios11/locale/pt-PT.json +++ b/themes/theme-ios11/locale/pt-PT.json @@ -20,7 +20,21 @@ "reviews": "Avaliações", "browse": "Navegar", "favorites": "Favoritos", - "scanner": "Scanner" + "scanner": "Scanner", + "back_in_stock": "Lembretes de reposição de stock" + }, + "back_in_stock": { + "list_states": { + "active": "Lembretes activos", + "past": "Lembretes anteriores" + }, + "empty_list_reminder": "Não tem lembretes nesta lista.", + "get_notified": "Ser notificado", + "we_will_remind_you": "Lembrar-lhe-emos.", + "add_back_in_stock_success_modal": { + "title": "Lembrete de stock adicionado!", + "message": "Enviar-lhe-emos uma notificação push quando o produto estiver novamente em stock. Pode gerir as suas notificações nas definições." + } }, "favorites": { "add": "Adicionar aos favoritos", @@ -223,6 +237,7 @@ "categories": "Categorias", "my_orders": "Meus Pedidos", "cart": "Carrinho de Compras", + "back_in_stock": "Lembrete de regresso ao stock", "shipping": "Métodos de Envio", "about": "Contact", "contact": "Contato", @@ -269,9 +284,15 @@ } }, "permissions": { + "back_in_stock_push_notifications": { + "message": "Autorize as notificações push no passo seguinte, para que possamos enviar-lhe uma notificação quando o produto estiver novamente em stock.", + "confirm": "Permitir notificações push", + "dismiss": "Cancelar" + }, "access_denied": { "settings_button": "Acesse configurações", "camera_message": "Esta funcionalidade requer acesso à sua câmara. Por favor autorize o acesso nas configurações.", + "push_message": "Esta funcionalidade requer acesso a notificações push. Autorize o acesso nas definições.", "geolocation_message": "Para encontrar lojas perto de você, acesse Configurações e ative as permissões de localização." } }, From 0248e8c55f0dc7080d191a0550789f65b44bb069 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Fri, 16 Feb 2024 08:23:44 +0100 Subject: [PATCH 31/55] CURB-3886 Update SheetItem propTypes --- .../Characteristic/components/SheetItem/index.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx index 3c6fcc431a..958a151c4c 100644 --- a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx @@ -11,10 +11,8 @@ class SheetItem extends PureComponent { static propTypes = { characteristics: PropTypes.shape().isRequired, item: PropTypes.shape().isRequired, - productId: PropTypes.string.isRequired, forwardedRef: PropTypes.shape(), onClick: PropTypes.func, - rightComponent: PropTypes.func, selected: PropTypes.bool, }; From 153f5804b8ac28bf8c31262a9adca44583ba969a Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Fri, 16 Feb 2024 14:57:07 +0100 Subject: [PATCH 32/55] CURB-3886 GetIsBackInStockEnabled based on theme setting --- libraries/engage/back-in-stock/selectors/index.js | 3 ++- themes/theme-gmd/extension-config.json | 9 +++++++++ themes/theme-ios11/extension-config.json | 9 +++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/libraries/engage/back-in-stock/selectors/index.js b/libraries/engage/back-in-stock/selectors/index.js index 71ac6ee409..0db1b0818b 100644 --- a/libraries/engage/back-in-stock/selectors/index.js +++ b/libraries/engage/back-in-stock/selectors/index.js @@ -1,6 +1,7 @@ import { createSelector } from 'reselect'; // import { getProductVariants } from '@shopgate/engage/product'; import isEqual from 'lodash/isEqual'; +import { appConfig } from '@shopgate/engage'; import { getProductVariants } from '@shopgate/pwa-common-commerce/product'; @@ -70,7 +71,7 @@ export const makeGetSubscriptionByCharacteristics = () => createSelector( * Returns if the back in stock feature is enabled * @returns {Function} */ -export const getIsBackInStockEnabled = () => true; +export const getIsBackInStockEnabled = () => appConfig?.showBackInStock; /** * Returns if subscription list is in use diff --git a/themes/theme-gmd/extension-config.json b/themes/theme-gmd/extension-config.json index bf5b04885a..3780c8d35e 100644 --- a/themes/theme-gmd/extension-config.json +++ b/themes/theme-gmd/extension-config.json @@ -202,6 +202,15 @@ "label": "Use sentry.io for error (debug, info) logging" } }, + "showBackInStock": { + "type": "admin", + "destination": "frontend", + "default": false, + "params": { + "type": "json", + "label": "If the Back-in-Stock feature is enable / disable." + } + }, "theme": { "type": "admin", "destination": "frontend", diff --git a/themes/theme-ios11/extension-config.json b/themes/theme-ios11/extension-config.json index 06c5340b97..9e82ef3c52 100644 --- a/themes/theme-ios11/extension-config.json +++ b/themes/theme-ios11/extension-config.json @@ -193,6 +193,15 @@ "label": "Use sentry.io for error (debug, info) logging" } }, + "showBackInStock": { + "type": "admin", + "destination": "frontend", + "default": false, + "params": { + "type": "json", + "label": "If the Back-in-Stock feature is enable / disable." + } + }, "theme": { "type": "admin", "destination": "frontend", From 5b244b44b207b9bcbde69df924dcabd5ad357b23 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Mon, 26 Feb 2024 10:10:50 +0100 Subject: [PATCH 33/55] CURB-3886 Review Feedback --- .../engage/back-in-stock/actions/index.js | 1 - .../components/BackInStockButton/style.js | 3 +- .../components/Subscription/index.jsx | 35 +++++++------------ 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index feb5b749c7..f5ac7d1357 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -28,7 +28,6 @@ export const fetchBackInStockSubscriptions = () => async (dispatch) => { await new PipelineRequest(SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS) .setInput({ limit: 100, - offset: 0, }) .dispatch(); diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/style.js b/libraries/engage/back-in-stock/components/BackInStockButton/style.js index b49370f5fd..8d5fdd45cd 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/style.js +++ b/libraries/engage/back-in-stock/components/BackInStockButton/style.js @@ -3,7 +3,6 @@ import { themeConfig } from '@shopgate/engage'; export default { button: css({ - marginTop: '4px', color: themeConfig.colors.primary, }).toString(), buttonContent: css({ @@ -19,9 +18,11 @@ export default { backInStockMessage: css({ marginLeft: '4px', verticalAlign: 'middle', + fontSize: '0.875rem', }).toString(), buttonText: css({ marginLeft: '4px', + fontSize: '0.875rem', }).toString(), icon: css({ verticalAlign: 'middle', diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx index 64c4eb001e..aa7d9129d9 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx @@ -29,30 +29,26 @@ const styles = { }).toString(), imageContainer: css({ flex: 0.4, - marginRight: 18, maxWidth: 170, - minWidth: 126, + minWidth: 70, }).toString(), infoContainer: css({ flex: 1, - display: 'flex', - flexDirection: 'column', - flexWrap: 'wrap', - gap: 8, }).toString(), infoContainerRow: css({ - flexDirection: 'row', display: 'flex', justifyContent: 'space-between', }).toString(), baseContainerRow: css({ flexDirection: 'column', display: 'flex', + marginTop: '8px', }).toString(), priceContainerRow: css({ flexDirection: 'column', display: 'flex', alignItems: 'end', + marginTop: '8px', }).toString(), priceContainer: css({ minWidth: 100, @@ -65,25 +61,20 @@ const styles = { padding: `${variables.gap.xsmall}px 0`, textAlign: 'right', }).toString(), - titleWrapper: css({ - display: 'flex', - flexDirection: 'column', - gap: 8, - }).toString(), titleContainer: css({ - marginRight: 10, - flex: 1, }).toString(), title: css({ fontSize: 17, - fontWeight: 600, + flexWrap: 'wrap', + overflowWrap: 'anywhere', }).toString(), removeContainer: css({ - display: 'flex', - flexShrink: 0, - alignItems: 'flex-start', - }), + minWidth: '30px', + }).toString(), + availabilityText: css({ + fontSize: '0.875rem', + }).toString(), }; /** @@ -118,8 +109,8 @@ const Subscription = ({
-
-
+
+
)}
-
); From 676e335d059bf61591267c9af01907156b3ef983 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Mon, 26 Feb 2024 10:10:50 +0100 Subject: [PATCH 34/55] CURB-3886 Review Feedback --- .../engage/back-in-stock/actions/index.js | 1 - .../components/BackInStockButton/style.js | 5 +-- .../BackInStockButtonPortal/index.jsx | 6 +++- .../components/Subscription/index.jsx | 35 +++++++------------ 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index feb5b749c7..f5ac7d1357 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -28,7 +28,6 @@ export const fetchBackInStockSubscriptions = () => async (dispatch) => { await new PipelineRequest(SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS) .setInput({ limit: 100, - offset: 0, }) .dispatch(); diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/style.js b/libraries/engage/back-in-stock/components/BackInStockButton/style.js index b49370f5fd..b9078aa788 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/style.js +++ b/libraries/engage/back-in-stock/components/BackInStockButton/style.js @@ -3,7 +3,6 @@ import { themeConfig } from '@shopgate/engage'; export default { button: css({ - marginTop: '4px', color: themeConfig.colors.primary, }).toString(), buttonContent: css({ @@ -11,17 +10,19 @@ export default { alignItems: 'center', }).toString(), backInStockMessageContainer: css({ - marginTop: '4px', display: 'inline', alignItems: 'center', textAlign: 'end', + lineHeight: '20px', }).toString(), backInStockMessage: css({ marginLeft: '4px', verticalAlign: 'middle', + fontSize: '0.875rem', }).toString(), buttonText: css({ marginLeft: '4px', + fontSize: '0.875rem', }).toString(), icon: css({ verticalAlign: 'middle', diff --git a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx index 6571aa650c..130ec2279a 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx +++ b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx @@ -17,6 +17,7 @@ import connect from './connector'; * @param {Object} props The component props. * @param {boolean} props.isBackInStockEnabled Whether the back in stock feature is enabled * @param {string} props.productId The product id + * @param {string} props.variantId The variant id * @param {string} props.productType The product type * @param {Object} props.stock The product stock info * @param {Function} props.addBackInStockSubscription Add product to back in stock list @@ -28,6 +29,7 @@ const BackInStockButtonPortal = ({ productType, stock, productId, + variantId, addBackInStockSubscription, isBackInStockEnabled, grantPushPermissions, @@ -49,7 +51,7 @@ const BackInStockButtonPortal = ({ onClick={async () => { const allowed = await grantPushPermissions(); if (allowed) { - addBackInStockSubscription({ productId }); + addBackInStockSubscription({ productId: variantId ?? productId }); } }} />} @@ -67,11 +69,13 @@ BackInStockButtonPortal.propTypes = { productType: PropTypes.string, stock: PropTypes.shape(), subscription: PropTypes.shape(), + variantId: PropTypes.string, }; BackInStockButtonPortal.defaultProps = { subscription: null, productType: null, + variantId: null, stock: null, }; diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx index 64c4eb001e..aa7d9129d9 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx @@ -29,30 +29,26 @@ const styles = { }).toString(), imageContainer: css({ flex: 0.4, - marginRight: 18, maxWidth: 170, - minWidth: 126, + minWidth: 70, }).toString(), infoContainer: css({ flex: 1, - display: 'flex', - flexDirection: 'column', - flexWrap: 'wrap', - gap: 8, }).toString(), infoContainerRow: css({ - flexDirection: 'row', display: 'flex', justifyContent: 'space-between', }).toString(), baseContainerRow: css({ flexDirection: 'column', display: 'flex', + marginTop: '8px', }).toString(), priceContainerRow: css({ flexDirection: 'column', display: 'flex', alignItems: 'end', + marginTop: '8px', }).toString(), priceContainer: css({ minWidth: 100, @@ -65,25 +61,20 @@ const styles = { padding: `${variables.gap.xsmall}px 0`, textAlign: 'right', }).toString(), - titleWrapper: css({ - display: 'flex', - flexDirection: 'column', - gap: 8, - }).toString(), titleContainer: css({ - marginRight: 10, - flex: 1, }).toString(), title: css({ fontSize: 17, - fontWeight: 600, + flexWrap: 'wrap', + overflowWrap: 'anywhere', }).toString(), removeContainer: css({ - display: 'flex', - flexShrink: 0, - alignItems: 'flex-start', - }), + minWidth: '30px', + }).toString(), + availabilityText: css({ + fontSize: '0.875rem', + }).toString(), }; /** @@ -118,8 +109,8 @@ const Subscription = ({
-
-
+
+
)}
-
); From 2390f1fb54f2c0c7c45229eaf0b971d5ae7dac39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frithjof=20Klo=CC=88s?= Date: Mon, 26 Feb 2024 12:24:50 +0100 Subject: [PATCH 35/55] CURB-3886 Improved NavDrawer Item styling for long labels - improved text alignment and icon spacing --- libraries/ui-material/NavDrawer/components/Item/index.jsx | 2 +- libraries/ui-material/NavDrawer/components/Item/style.js | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/ui-material/NavDrawer/components/Item/index.jsx b/libraries/ui-material/NavDrawer/components/Item/index.jsx index d926f2b135..05577aa524 100644 --- a/libraries/ui-material/NavDrawer/components/Item/index.jsx +++ b/libraries/ui-material/NavDrawer/components/Item/index.jsx @@ -28,7 +28,7 @@ class NavDrawerItem extends Component { badge: null, forwardedRef: null, icon: null, - onClick: () => {}, + onClick: () => { }, srOnly: false, style: {}, testId: null, diff --git a/libraries/ui-material/NavDrawer/components/Item/style.js b/libraries/ui-material/NavDrawer/components/Item/style.js index aa9d4aa1e4..40892d5239 100644 --- a/libraries/ui-material/NavDrawer/components/Item/style.js +++ b/libraries/ui-material/NavDrawer/components/Item/style.js @@ -22,7 +22,7 @@ const button = css({ display: 'flex', fontWeight: 500, outline: 0, - padding: '16px 0', + padding: '16px 8px 16px 0', position: 'relative', width: '100%', ':first-child': { @@ -32,10 +32,12 @@ const button = css({ const label = css({ marginTop: 2, + textAlign: 'left', }).toString(); const iconWrapper = css({ - width: 72, + width: 56, + flexShrink: 0, }).toString(); const icon = css({ From 5b06edad728edf1b82dfa34fa3d9e296d9b27e74 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Mon, 26 Feb 2024 15:48:28 +0100 Subject: [PATCH 36/55] CURB-3886 Refactor backInStock actions --- .../engage/back-in-stock/actions/index.js | 120 +++++++++--------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index f5ac7d1357..d8094e3c28 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -20,31 +20,31 @@ import { * Fetch Back in Stock Subscriptions * @returns {Function} */ -export const fetchBackInStockSubscriptions = () => async (dispatch) => { +export const fetchBackInStockSubscriptions = () => (dispatch) => { dispatch({ type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS }); - try { - const { subscriptions } = - await new PipelineRequest(SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS) - .setInput({ - limit: 100, - }) - .dispatch(); + const request = new PipelineRequest(SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS) + .setInput({ + limit: 100, + }) + .setRetries(0) + .dispatch(); - dispatch({ - type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, - subscriptions, + request + .then(({ subscriptions }) => { + dispatch({ + type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, + subscriptions, + }); + }) + .catch((error) => { + dispatch({ + type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, + error, + }); }); - return subscriptions; - } catch (error) { - dispatch({ - type: FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, - error, - }); - - return null; - } + return request; }; /** @@ -53,30 +53,30 @@ export const fetchBackInStockSubscriptions = () => async (dispatch) => { * @param {string} props.productId The product for which the subscription should be added * @returns {Function} */ -export const addBackInStockSubscription = ({ productId }) => async (dispatch) => { +export const addBackInStockSubscription = ({ productId }) => (dispatch) => { dispatch({ type: ADD_BACK_IN_STOCK_SUBSCRIPTION }); + const request = new PipelineRequest(SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION) + .setInput({ + productCode: productId, + }) + .setRetries(0) + .dispatch(); - try { - const { subscriptions } = - await new PipelineRequest(SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION) - .setInput({ - productCode: productId, - }) - .dispatch(); - - dispatch({ - type: ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, - subscriptions, - }); - return subscriptions; - } catch (error) { - dispatch({ - type: ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, - error, + request + .then(({ subscriptions }) => { + dispatch({ + type: ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + subscriptions, + }); + }) + .catch((error) => { + dispatch({ + type: ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, + error, + }); }); - return null; - } + return request; }; /** @@ -85,29 +85,29 @@ export const addBackInStockSubscription = ({ productId }) => async (dispatch) => * @param {string} props.subscriptionCode The subscription which should be deleted * @returns {Function} */ -export const removeBackInStockSubscription = ({ subscriptionCode }) => async (dispatch) => { +export const removeBackInStockSubscription = ({ subscriptionCode }) => (dispatch) => { dispatch({ type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION }); + const request = new PipelineRequest(SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION) + .setInput({ + subscriptionCode, + }) + .setRetries(0) + .dispatch(); - try { - const { subscriptions } = - await new PipelineRequest(SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION) - .setInput({ - subscriptionCode, - }) - .dispatch(); - - dispatch({ - type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, - subscriptions, - }); - return subscriptions; - } catch (error) { - dispatch({ - type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR, - error, + request + .then(({ subscriptions }) => { + dispatch({ + type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + subscriptions, + }); + }) + .catch((error) => { + dispatch({ + type: REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR, + error, + }); }); - return null; - } + return request; }; From eb37479a47f4bf72ba6ea3d4b37ac6dccd053fd6 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 09:18:05 +0100 Subject: [PATCH 37/55] CURB-3886 Typo in extension-config.json --- themes/theme-gmd/extension-config.json | 2 +- themes/theme-ios11/extension-config.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/themes/theme-gmd/extension-config.json b/themes/theme-gmd/extension-config.json index 3780c8d35e..78bb64c7d2 100644 --- a/themes/theme-gmd/extension-config.json +++ b/themes/theme-gmd/extension-config.json @@ -208,7 +208,7 @@ "default": false, "params": { "type": "json", - "label": "If the Back-in-Stock feature is enable / disable." + "label": "If the Back-in-Stock feature is enabled / disabled." } }, "theme": { diff --git a/themes/theme-ios11/extension-config.json b/themes/theme-ios11/extension-config.json index 9e82ef3c52..268c266b81 100644 --- a/themes/theme-ios11/extension-config.json +++ b/themes/theme-ios11/extension-config.json @@ -199,7 +199,7 @@ "default": false, "params": { "type": "json", - "label": "If the Back-in-Stock feature is enable / disable." + "label": "If the Back-in-Stock feature is enabled / disabled." } }, "theme": { From 06a25d02dcda869c30155ea2d361640d9798d697 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 09:18:39 +0100 Subject: [PATCH 38/55] CURB-3886 Adjust some imports --- .../components/BackInStockButtonPortal/index.jsx | 3 +-- .../components/CharacteristicsButton/index.jsx | 2 +- .../components/Subscriptions/components/List/index.jsx | 3 +-- .../Subscriptions/components/Subscription/index.jsx | 10 +++++----- libraries/engage/back-in-stock/components/index.js | 1 + libraries/engage/back-in-stock/index.js | 1 - themes/theme-gmd/pages/index.jsx | 1 - 7 files changed, 9 insertions(+), 12 deletions(-) create mode 100644 libraries/engage/back-in-stock/components/index.js diff --git a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx index 130ec2279a..566ebe81c2 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx +++ b/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx @@ -3,12 +3,11 @@ import PropTypes from 'prop-types'; import { Portal } from '@shopgate/engage/components'; import { AVAILABILITY_STATE_OK } from '@shopgate/engage/product'; import { - BackInStockButton, PRODUCT_BACK_IN_STOCK, PRODUCT_BACK_IN_STOCK_AFTER, PRODUCT_BACK_IN_STOCK_BEFORE, } from '@shopgate/engage/back-in-stock'; - +import { BackInStockButton } from '@shopgate/engage/back-in-stock/components'; import { withCurrentProduct } from '@shopgate/engage/core'; import connect from './connector'; diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx index b21233ce6a..34780dacc5 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { BackInStockButton } from '@shopgate/engage/back-in-stock'; +import { BackInStockButton } from '@shopgate/engage/back-in-stock/components'; import { AVAILABILITY_STATE_OK } from '@shopgate/engage/product'; import { withCurrentProduct } from '@shopgate/engage/core'; import connect from './connector'; diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx index 7ab4f42ad3..31d28d502b 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx @@ -1,7 +1,6 @@ import React, { useCallback } from 'react'; import { css } from 'glamor'; -import LoadingIndicator from '@shopgate/pwa-ui-shared/LoadingIndicator'; -import { Accordion, Card } from '@shopgate/engage/components'; +import { LoadingIndicator, Accordion, Card } from '@shopgate/engage/components'; import { i18n } from '@shopgate/engage/core'; import { useBackInStockSubscriptions } from '../../../../hooks'; import Subscription from '../Subscription'; diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx index aa7d9129d9..cf227511dd 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx @@ -5,15 +5,15 @@ import { Ripple, PriceInfo, CrossIcon, + PriceStriked, + Price, + Availability, } from '@shopgate/engage/components'; import { getProductRoute, ProductImage } from '@shopgate/engage/product'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { themeConfig } from '@shopgate/engage'; -import PriceStriked from '@shopgate/pwa-ui-shared/PriceStriked'; -import Price from '@shopgate/pwa-ui-shared/Price'; -import AvailableText from '@shopgate/pwa-ui-shared/Availability'; -import { BackInStockButton } from '@shopgate/engage/back-in-stock/'; +import { BackInStockButton } from '@shopgate/engage/back-in-stock/components'; import { getThemeSettings, i18n, } from '@shopgate/engage/core'; @@ -137,7 +137,7 @@ const Subscription = ({
- ( Date: Tue, 27 Feb 2024 09:19:01 +0100 Subject: [PATCH 39/55] CURB-3886 Adjust translations --- themes/theme-ios11/locale/de-DE.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/themes/theme-ios11/locale/de-DE.json b/themes/theme-ios11/locale/de-DE.json index eb22ae1d89..d0dc13d6a6 100644 --- a/themes/theme-ios11/locale/de-DE.json +++ b/themes/theme-ios11/locale/de-DE.json @@ -28,9 +28,9 @@ "active": "Aktive Benachrichtigungen", "past": "Vergangene Benachrichtigungen" }, - "empty_list_reminder": "Sie haben keine Benachrichtigungen konfiguriert.", + "empty_list_reminder": "Sie haben keine Benachrichtigungen konfiguriert", "get_notified": "Benachrichtige mich", - "we_will_remind_you": "Du wirst benachrichtigt.", + "we_will_remind_you": "Du wirst benachrichtigt", "add_back_in_stock_success_modal": { "title": "Benachrichtigung hinzugefügt!", "message": "Wir senden dir eine Push-Benachrichtigung wenn das Produkt wieder verfügbar ist. Du kannst diese Benachrichtigungen in den Einstellungen verwalten." From 387c2ef9d169f26d3f2921852dc0c5a1eeceebca Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 10:07:49 +0100 Subject: [PATCH 40/55] CURB-3886 Review Feedback. Rename BackInStockButtonPortal --- .../connector.js | 0 .../index.jsx | 10 +++++----- libraries/engage/back-in-stock/index.js | 2 +- .../components/Header/components/ProductInfo/index.jsx | 4 ++-- .../components/Header/components/ProductInfo/index.jsx | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) rename libraries/engage/back-in-stock/components/{BackInStockButtonPortal => ProductInfoBackInStockButton}/connector.js (100%) rename libraries/engage/back-in-stock/components/{BackInStockButtonPortal => ProductInfoBackInStockButton}/index.jsx (90%) diff --git a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/connector.js b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/connector.js similarity index 100% rename from libraries/engage/back-in-stock/components/BackInStockButtonPortal/connector.js rename to libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/connector.js diff --git a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx similarity index 90% rename from libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx rename to libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx index 566ebe81c2..1908deb1aa 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButtonPortal/index.jsx +++ b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx @@ -12,7 +12,7 @@ import { withCurrentProduct } from '@shopgate/engage/core'; import connect from './connector'; /** - * The BackInStockButtonPortal component. + * The ProductInfoBackInStockButton component. * @param {Object} props The component props. * @param {boolean} props.isBackInStockEnabled Whether the back in stock feature is enabled * @param {string} props.productId The product id @@ -24,7 +24,7 @@ import connect from './connector'; * @param {Object} props.subscription The subscription * @return {JSX} */ -const BackInStockButtonPortal = ({ +const ProductInfoBackInStockButton = ({ productType, stock, productId, @@ -60,7 +60,7 @@ const BackInStockButtonPortal = ({ ); }; -BackInStockButtonPortal.propTypes = { +ProductInfoBackInStockButton.propTypes = { addBackInStockSubscription: PropTypes.func.isRequired, grantPushPermissions: PropTypes.func.isRequired, isBackInStockEnabled: PropTypes.bool.isRequired, @@ -71,11 +71,11 @@ BackInStockButtonPortal.propTypes = { variantId: PropTypes.string, }; -BackInStockButtonPortal.defaultProps = { +ProductInfoBackInStockButton.defaultProps = { subscription: null, productType: null, variantId: null, stock: null, }; -export default withCurrentProduct(connect(BackInStockButtonPortal)); +export default withCurrentProduct(connect(ProductInfoBackInStockButton)); diff --git a/libraries/engage/back-in-stock/index.js b/libraries/engage/back-in-stock/index.js index a725294743..d32deb1e01 100644 --- a/libraries/engage/back-in-stock/index.js +++ b/libraries/engage/back-in-stock/index.js @@ -5,7 +5,7 @@ export * from './constants/Portals'; // Components export { default as BackInStockReminders } from './components/Subscriptions'; -export { default as BackInStockButtonPortal } from './components/BackInStockButtonPortal'; +export { default as ProductInfoBackInStockButton } from './components/ProductInfoBackInStockButton'; export { default as CharacteristicsButton } from './components/CharacteristicsButton'; // ACTIONS diff --git a/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx b/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx index 074e7964b3..98e23a738f 100644 --- a/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx @@ -13,7 +13,7 @@ import { import Shipping from '@shopgate/engage/product/components/Header/Shipping'; import Tiers from '@shopgate/engage/product/components/Header/Tiers'; import PriceStriked from '@shopgate/engage/product/components/Header/PriceStriked'; -import { BackInStockButtonPortal } from '@shopgate/engage/back-in-stock'; +import { ProductInfoBackInStockButton } from '@shopgate/engage/back-in-stock'; import Manufacturer from '../Manufacturer'; import Availability from '../Availability'; import Price from '../Price'; @@ -60,7 +60,7 @@ const ProductInfo = ({ productId, options }) => (
- +
diff --git a/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx b/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx index 074e7964b3..98e23a738f 100644 --- a/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx +++ b/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx @@ -13,7 +13,7 @@ import { import Shipping from '@shopgate/engage/product/components/Header/Shipping'; import Tiers from '@shopgate/engage/product/components/Header/Tiers'; import PriceStriked from '@shopgate/engage/product/components/Header/PriceStriked'; -import { BackInStockButtonPortal } from '@shopgate/engage/back-in-stock'; +import { ProductInfoBackInStockButton } from '@shopgate/engage/back-in-stock'; import Manufacturer from '../Manufacturer'; import Availability from '../Availability'; import Price from '../Price'; @@ -60,7 +60,7 @@ const ProductInfo = ({ productId, options }) => (
- +
From dc58d5d100e583c890ad42b59d9742ac86986de1 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 11:58:10 +0100 Subject: [PATCH 41/55] CURB-3886 Review Feedback. --- .../CharacteristicsButton/connector.js | 4 -- .../CharacteristicsButton/index.jsx | 13 +++-- .../ProductInfoBackInStockButton/connector.js | 7 +-- .../ProductInfoBackInStockButton/index.jsx | 47 ++++++++++--------- .../engage/back-in-stock/selectors/index.js | 35 ++++++-------- .../engage/core/actions/grantPermissions.js | 1 - 6 files changed, 47 insertions(+), 60 deletions(-) diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js index 4b669785a3..f05e3a14e2 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js @@ -3,9 +3,6 @@ import { getIsBackInStockEnabled, makeGetSubscriptionByCharacteristics, } from '@shopgate/engage/back-in-stock'; -import { - getVariantAvailabilityByCharacteristics, -} from '@shopgate/pwa-common-commerce/product'; import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; import grantPushPermissions from '@shopgate/engage/core/actions/grantPushPermissions'; import { @@ -23,7 +20,6 @@ const makeMapStateToProps = () => { const variant = getProductByCharacteristics(state, props) || {}; return ({ variant, - availability: getVariantAvailabilityByCharacteristics(state, props), subscription: getSubscriptionByCharacteristics(state, props), isBackInStockEnabled: getIsBackInStockEnabled(state, props), }); diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx index 34780dacc5..07a1a53db8 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx @@ -1,7 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { BackInStockButton } from '@shopgate/engage/back-in-stock/components'; -import { AVAILABILITY_STATE_OK } from '@shopgate/engage/product'; import { withCurrentProduct } from '@shopgate/engage/core'; import connect from './connector'; @@ -10,21 +9,23 @@ import connect from './connector'; * @param {Object} props The component props. * @param {boolean} props.isBackInStockEnabled Whether the back in stock feature is enabled * @param {Object} props.variant The variant for this entry - * @param {Object} props.availability The product availability * @param {Object} props.subscription The subscription * @param {Function} props.grantPushPermissions Request / Set push permission * @return {JSX} */ const CharacteristicsButton = ({ - availability, addBackInStockSubscription, isBackInStockEnabled, grantPushPermissions, subscription, variant, }) => { - if (availability?.state === AVAILABILITY_STATE_OK || - availability === null || !variant || !isBackInStockEnabled) return null; + const productIsNotAVariant = !variant; + const featureIsNotEnabled = !isBackInStockEnabled; + const productIsNotAvailable = variant?.stock?.quantity === 0 && + variant?.stock?.ignoreQuantity === false; + + if (productIsNotAVariant || featureIsNotEnabled || !productIsNotAvailable) return null; return (
{ - const getProductType = makeGetProductType(); const getSubscriptionByProduct = makeGetSubscriptionByProduct(); return (state, props) => ({ subscription: getSubscriptionByProduct(state, props), - productType: getProductType(state, props), - stock: getProductAvailability(state, props), isBackInStockEnabled: getIsBackInStockEnabled(state, props), + product: getProduct(state, props), }); }; diff --git a/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx index 1908deb1aa..51eba35329 100644 --- a/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx +++ b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx @@ -1,11 +1,8 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import { Portal } from '@shopgate/engage/components'; -import { AVAILABILITY_STATE_OK } from '@shopgate/engage/product'; +import { SurroundPortals } from '@shopgate/engage/components'; import { PRODUCT_BACK_IN_STOCK, - PRODUCT_BACK_IN_STOCK_AFTER, - PRODUCT_BACK_IN_STOCK_BEFORE, } from '@shopgate/engage/back-in-stock'; import { BackInStockButton } from '@shopgate/engage/back-in-stock/components'; import { withCurrentProduct } from '@shopgate/engage/core'; @@ -17,33 +14,36 @@ import connect from './connector'; * @param {boolean} props.isBackInStockEnabled Whether the back in stock feature is enabled * @param {string} props.productId The product id * @param {string} props.variantId The variant id - * @param {string} props.productType The product type - * @param {Object} props.stock The product stock info + * @param {Object} props.product The product * @param {Function} props.addBackInStockSubscription Add product to back in stock list * @param {Function} props.grantPushPermissions Request / Set push permission * @param {Object} props.subscription The subscription * @return {JSX} */ const ProductInfoBackInStockButton = ({ - productType, - stock, productId, variantId, addBackInStockSubscription, isBackInStockEnabled, grantPushPermissions, subscription, + product, }) => { - const showBackInStock = productType !== 'parent' && - productType !== null && - stock?.state !== AVAILABILITY_STATE_OK && - isBackInStockEnabled; + const productIsAVariant = product?.type !== 'parent' && + product?.type !== null; + + const productIsNotAvailable = product?.stock?.quantity === 0 && + product?.stock?.ignoreQuantity === false; + + const showBackInStockButton = productIsAVariant && productIsNotAvailable && isBackInStockEnabled; return ( - - - {showBackInStock && + + {showBackInStockButton && } - - + ); }; @@ -65,17 +64,21 @@ ProductInfoBackInStockButton.propTypes = { grantPushPermissions: PropTypes.func.isRequired, isBackInStockEnabled: PropTypes.bool.isRequired, productId: PropTypes.string.isRequired, - productType: PropTypes.string, - stock: PropTypes.shape(), - subscription: PropTypes.shape(), + product: PropTypes.shape({ + type: PropTypes.string, + stock: PropTypes.shape({ + ignoreQuantity: PropTypes.bool, + quantity: PropTypes.number, + }), + }), + subscription: PropTypes.shape({}), variantId: PropTypes.string, }; ProductInfoBackInStockButton.defaultProps = { subscription: null, - productType: null, variantId: null, - stock: null, + product: null, }; export default withCurrentProduct(connect(ProductInfoBackInStockButton)); diff --git a/libraries/engage/back-in-stock/selectors/index.js b/libraries/engage/back-in-stock/selectors/index.js index 0db1b0818b..db7cfdab8b 100644 --- a/libraries/engage/back-in-stock/selectors/index.js +++ b/libraries/engage/back-in-stock/selectors/index.js @@ -1,10 +1,7 @@ import { createSelector } from 'reselect'; -// import { getProductVariants } from '@shopgate/engage/product'; -import isEqual from 'lodash/isEqual'; +import { makeGetProductByCharacteristics } from '@shopgate/engage/product'; import { appConfig } from '@shopgate/engage'; -import { getProductVariants } from '@shopgate/pwa-common-commerce/product'; - /** * @param {Object} state The application state. * @returns {Object} @@ -46,26 +43,22 @@ export const makeGetSubscriptionByProduct = () => createSelector( * a product / variant by its characteristics * @returns {Function} */ -export const makeGetSubscriptionByCharacteristics = () => createSelector( - getProductVariants, - (state, props = {}) => props.characteristics, - getBackInStockSubscriptions, - (variants, characteristics, subscriptions) => { - if (!variants) { - return false; - } +export const makeGetSubscriptionByCharacteristics = () => { + const getProductByCharacteristics = makeGetProductByCharacteristics(); - const found = variants.products.find(product => - isEqual(product.characteristics, characteristics)); + return createSelector( + getProductByCharacteristics, + getBackInStockSubscriptions, + (product, subscriptions) => { + if (!product) { + return null; + } - if (!found) { - return null; + return subscriptions.find(({ productCode }) => + productCode === product.id) || null; } - - return subscriptions.find(({ productCode }) => - productCode === found.id) || null; - } -); + ); +}; /** * Returns if the back in stock feature is enabled diff --git a/libraries/engage/core/actions/grantPermissions.js b/libraries/engage/core/actions/grantPermissions.js index 48e45b66c6..1a6c812b14 100644 --- a/libraries/engage/core/actions/grantPermissions.js +++ b/libraries/engage/core/actions/grantPermissions.js @@ -1,7 +1,6 @@ import event from '@shopgate/pwa-core/classes/Event'; import { APP_EVENT_APPLICATION_WILL_ENTER_FOREGROUND } from '@shopgate/pwa-core/constants/AppEvents'; import openAppSettings from '@shopgate/pwa-core/commands/openAppSettings'; -// import showModal from '@shopgate/pwa-common/actions/modal/showModal'; import { showModal } from '@shopgate/engage/core'; import { STATUS_DENIED, From 8deb0bf129d66af432c5cd77d063286f14b2aad2 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 13:31:16 +0100 Subject: [PATCH 42/55] CURB-3886 Review Feedback. Move onclick action in BackInStockButton --- .../components/BackInStockButton/connector.js | 11 +++++++ .../components/BackInStockButton/index.jsx | 33 +++++++++++++++---- .../CharacteristicsButton/connector.js | 10 +----- .../CharacteristicsButton/index.jsx | 14 ++------ .../ProductInfoBackInStockButton/connector.js | 9 +---- .../ProductInfoBackInStockButton/index.jsx | 13 +------- 6 files changed, 43 insertions(+), 47 deletions(-) create mode 100644 libraries/engage/back-in-stock/components/BackInStockButton/connector.js diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/connector.js b/libraries/engage/back-in-stock/components/BackInStockButton/connector.js new file mode 100644 index 0000000000..de7f4214d6 --- /dev/null +++ b/libraries/engage/back-in-stock/components/BackInStockButton/connector.js @@ -0,0 +1,11 @@ +import { connect } from 'react-redux'; +import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; +import grantPushPermissions from '@shopgate/engage/core/actions/grantPushPermissions'; + +const mapDispatchToProps = { + addBackInStockSubscription, + grantPushPermissions, + +}; + +export default connect(null, mapDispatchToProps); diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx b/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx index 56419215f8..abbb730bb9 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx +++ b/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import PropTypes from 'prop-types'; import { themeConfig } from '@shopgate/engage'; import { @@ -9,6 +9,7 @@ import { import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; import { i18n } from '@shopgate/engage/core'; import styles from './style'; +import connect from './connector'; const { colors } = themeConfig; /** @@ -17,15 +18,31 @@ const { colors } = themeConfig; * @param {Object} props The component props * @param {boolean} props.isLinkToBackInStockEnabled Whether the link to the back in * stock page is active + * @param {boolean} props.stopPropagation Stop event propagation + * @param {string} props.productId The product id * @param {Object} props.subscription The subscription - * @param {Function} props.onClick Action to subscribe the product + * @param {Function} props.addBackInStockSubscription Add product to back in stock list + * @param {Function} props.grantPushPermissions Request / Set push permission * @return {JSX} */ const BackInStockButton = ({ - onClick, + productId, isLinkToBackInStockEnabled = false, subscription, + stopPropagation = false, + addBackInStockSubscription, + grantPushPermissions, }) => { + const handleClick = useCallback(async (event) => { + if (stopPropagation) { + event.stopPropagation(); + } + const allowed = await grantPushPermissions(); + if (allowed) { + addBackInStockSubscription({ productId }); + } + }, [addBackInStockSubscription, grantPushPermissions, productId, stopPropagation]); + if (subscription?.status === 'active') { return ( {/* eslint-disable-next-line max-len */} {/* eslint-disable-next-line jsx-a11y/anchor-is-valid,jsx-a11y/interactive-supports-focus,jsx-a11y/click-events-have-key-events */} - +
{i18n.text('back_in_stock.get_notified')} @@ -54,14 +71,18 @@ const BackInStockButton = ({ }; BackInStockButton.propTypes = { - onClick: PropTypes.func.isRequired, + addBackInStockSubscription: PropTypes.func.isRequired, + grantPushPermissions: PropTypes.func.isRequired, + productId: PropTypes.string.isRequired, isLinkToBackInStockEnabled: PropTypes.bool, + stopPropagation: PropTypes.bool, subscription: PropTypes.shape(), }; BackInStockButton.defaultProps = { + stopPropagation: false, isLinkToBackInStockEnabled: false, subscription: null, }; -export default BackInStockButton; +export default connect(BackInStockButton); diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js index f05e3a14e2..64435288fa 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js @@ -3,8 +3,6 @@ import { getIsBackInStockEnabled, makeGetSubscriptionByCharacteristics, } from '@shopgate/engage/back-in-stock'; -import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; -import grantPushPermissions from '@shopgate/engage/core/actions/grantPushPermissions'; import { makeGetProductByCharacteristics, } from '@shopgate/engage/product'; @@ -26,10 +24,4 @@ const makeMapStateToProps = () => { }; }; -const mapDispatchToProps = { - addBackInStockSubscription, - grantPushPermissions, - -}; - -export default connect(makeMapStateToProps, mapDispatchToProps); +export default connect(makeMapStateToProps); diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx index 07a1a53db8..e723419281 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/index.jsx @@ -10,13 +10,10 @@ import connect from './connector'; * @param {boolean} props.isBackInStockEnabled Whether the back in stock feature is enabled * @param {Object} props.variant The variant for this entry * @param {Object} props.subscription The subscription - * @param {Function} props.grantPushPermissions Request / Set push permission * @return {JSX} */ const CharacteristicsButton = ({ - addBackInStockSubscription, isBackInStockEnabled, - grantPushPermissions, subscription, variant, }) => { @@ -35,20 +32,13 @@ const CharacteristicsButton = ({ > { - e.stopPropagation(); - const allowed = await grantPushPermissions(); - if (allowed) { - addBackInStockSubscription({ productId: variant.id }); - } - }} + stopPropagation + productId={variant.id} />
); }; CharacteristicsButton.propTypes = { - addBackInStockSubscription: PropTypes.func.isRequired, - grantPushPermissions: PropTypes.func.isRequired, isBackInStockEnabled: PropTypes.bool.isRequired, subscription: PropTypes.shape(), variant: PropTypes.shape(), diff --git a/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/connector.js b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/connector.js index bfb89acec3..7168adb4c8 100644 --- a/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/connector.js +++ b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/connector.js @@ -3,11 +3,9 @@ import { getIsBackInStockEnabled, makeGetSubscriptionByProduct, } from '@shopgate/engage/back-in-stock'; -import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; import { getProduct, } from '@shopgate/engage/product'; -import { grantPushPermissions } from '@shopgate/engage/core'; /** * @return {Object} The extended component props. @@ -21,9 +19,4 @@ const makeMapStateToProps = () => { }); }; -const mapDispatchToProps = { - addBackInStockSubscription, - grantPushPermissions, -}; - -export default connect(makeMapStateToProps, mapDispatchToProps); +export default connect(makeMapStateToProps); diff --git a/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx index 51eba35329..fea6c7bb4a 100644 --- a/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx +++ b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx @@ -15,17 +15,13 @@ import connect from './connector'; * @param {string} props.productId The product id * @param {string} props.variantId The variant id * @param {Object} props.product The product - * @param {Function} props.addBackInStockSubscription Add product to back in stock list - * @param {Function} props.grantPushPermissions Request / Set push permission * @param {Object} props.subscription The subscription * @return {JSX} */ const ProductInfoBackInStockButton = ({ productId, variantId, - addBackInStockSubscription, isBackInStockEnabled, - grantPushPermissions, subscription, product, }) => { @@ -47,12 +43,7 @@ const ProductInfoBackInStockButton = ({ { - const allowed = await grantPushPermissions(); - if (allowed) { - addBackInStockSubscription({ productId: variantId ?? productId }); - } - }} + productId={variantId ?? productId} />} @@ -60,8 +51,6 @@ const ProductInfoBackInStockButton = ({ }; ProductInfoBackInStockButton.propTypes = { - addBackInStockSubscription: PropTypes.func.isRequired, - grantPushPermissions: PropTypes.func.isRequired, isBackInStockEnabled: PropTypes.bool.isRequired, productId: PropTypes.string.isRequired, product: PropTypes.shape({ From 29feed17688d01af7bef142c7892f2edc4524bbf Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 13:43:42 +0100 Subject: [PATCH 43/55] CURB-3886 Review Feedback. Adjust constants --- libraries/engage/back-in-stock/actions/index.js | 13 +++++-------- .../engage/back-in-stock/constants/Actions.js | 11 +++++++++++ .../engage/back-in-stock/constants/Common.js | 1 + .../engage/back-in-stock/constants/index.js | 16 ++++------------ libraries/engage/back-in-stock/index.js | 5 ----- libraries/engage/back-in-stock/reducers/index.js | 5 ++--- libraries/engage/back-in-stock/streams/index.js | 4 ++-- themes/theme-gmd/pages/index.jsx | 2 +- 8 files changed, 26 insertions(+), 31 deletions(-) create mode 100644 libraries/engage/back-in-stock/constants/Actions.js create mode 100644 libraries/engage/back-in-stock/constants/Common.js diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index d8094e3c28..78dcbbcc65 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -1,20 +1,17 @@ import { PipelineRequest } from '@shopgate/engage/core'; import { + SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION, + SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION, + SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS, ADD_BACK_IN_STOCK_SUBSCRIPTION, ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, - ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, - FETCH_BACK_IN_STOCK_SUBSCRIPTIONS, + ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, REMOVE_BACK_IN_STOCK_SUBSCRIPTION, REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR, REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, -} from '../constants'; -import { - SHOPGATE_USER_ADD_BACK_IN_STOCK_SUBSCRIPTION, - SHOPGATE_USER_DELETE_BACK_IN_STOCK_SUBSCRIPTION, - SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS, -} from '../constants/Pipelines'; +} from '@shopgate/engage/back-in-stock/constants'; /** * Fetch Back in Stock Subscriptions diff --git a/libraries/engage/back-in-stock/constants/Actions.js b/libraries/engage/back-in-stock/constants/Actions.js new file mode 100644 index 0000000000..443aee6aa8 --- /dev/null +++ b/libraries/engage/back-in-stock/constants/Actions.js @@ -0,0 +1,11 @@ +export const FETCH_BACK_IN_STOCK_SUBSCRIPTIONS = 'FETCH_BACK_IN_STOCK_SUBSCRIPTIONS'; +export const FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS = 'FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS'; +export const FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR = 'FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR'; + +export const ADD_BACK_IN_STOCK_SUBSCRIPTION = 'ADD_BACK_IN_STOCK_SUBSCRIPTION'; +export const ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS = 'ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS'; +export const ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR = 'ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR'; + +export const REMOVE_BACK_IN_STOCK_SUBSCRIPTION = 'REMOVE_BACK_IN_STOCK_SUBSCRIPTION'; +export const REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS = 'REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS'; +export const REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR = 'REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR'; diff --git a/libraries/engage/back-in-stock/constants/Common.js b/libraries/engage/back-in-stock/constants/Common.js new file mode 100644 index 0000000000..71595b8051 --- /dev/null +++ b/libraries/engage/back-in-stock/constants/Common.js @@ -0,0 +1 @@ +export const BACK_IN_STOCK_PATTERN = '/back-in-stock'; diff --git a/libraries/engage/back-in-stock/constants/index.js b/libraries/engage/back-in-stock/constants/index.js index d081952de2..1fe474a7e3 100644 --- a/libraries/engage/back-in-stock/constants/index.js +++ b/libraries/engage/back-in-stock/constants/index.js @@ -1,13 +1,5 @@ -export const BACK_IN_STOCK_PATTERN = '/back-in-stock'; +export * from './Actions'; +export * from './Common'; +export * from './Pipelines'; +export * from './Portals'; -export const FETCH_BACK_IN_STOCK_SUBSCRIPTIONS = 'FETCH_BACK_IN_STOCK_SUBSCRIPTIONS'; -export const FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS = 'FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS'; -export const FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR = 'FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR'; - -export const ADD_BACK_IN_STOCK_SUBSCRIPTION = 'ADD_BACK_IN_STOCK_SUBSCRIPTION'; -export const ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS = 'ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS'; -export const ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR = 'ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR'; - -export const REMOVE_BACK_IN_STOCK_SUBSCRIPTION = 'REMOVE_BACK_IN_STOCK_SUBSCRIPTION'; -export const REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS = 'REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS'; -export const REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR = 'REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR'; diff --git a/libraries/engage/back-in-stock/index.js b/libraries/engage/back-in-stock/index.js index d32deb1e01..51c75c92cd 100644 --- a/libraries/engage/back-in-stock/index.js +++ b/libraries/engage/back-in-stock/index.js @@ -1,8 +1,3 @@ -// CONSTANTS -export * from './constants'; -export * from './constants/Pipelines'; -export * from './constants/Portals'; - // Components export { default as BackInStockReminders } from './components/Subscriptions'; export { default as ProductInfoBackInStockButton } from './components/ProductInfoBackInStockButton'; diff --git a/libraries/engage/back-in-stock/reducers/index.js b/libraries/engage/back-in-stock/reducers/index.js index 29186e016d..40d5260de2 100644 --- a/libraries/engage/back-in-stock/reducers/index.js +++ b/libraries/engage/back-in-stock/reducers/index.js @@ -1,14 +1,13 @@ import { ADD_BACK_IN_STOCK_SUBSCRIPTION, ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, - ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, - FETCH_BACK_IN_STOCK_SUBSCRIPTIONS, + ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, REMOVE_BACK_IN_STOCK_SUBSCRIPTION, REMOVE_BACK_IN_STOCK_SUBSCRIPTION_ERROR, REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, -} from '../constants'; +} from '@shopgate/engage/back-in-stock/constants'; const initialState = { isFetching: false, diff --git a/libraries/engage/back-in-stock/streams/index.js b/libraries/engage/back-in-stock/streams/index.js index a25b77f46f..5b8917293f 100644 --- a/libraries/engage/back-in-stock/streams/index.js +++ b/libraries/engage/back-in-stock/streams/index.js @@ -2,9 +2,9 @@ import { appDidStart$, main$, routeDidEnter$ } from '@shopgate/pwa-common/stream import { productWillEnter$ } from '@shopgate/pwa-common-commerce/product'; import { ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, - BACK_IN_STOCK_PATTERN, REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, -} from '../constants'; + BACK_IN_STOCK_PATTERN, +} from '@shopgate/engage/back-in-stock/constants'; export const backInStockRemindersDidEnter$ = routeDidEnter$ .filter(({ action }) => action.route.pattern === BACK_IN_STOCK_PATTERN); diff --git a/themes/theme-gmd/pages/index.jsx b/themes/theme-gmd/pages/index.jsx index 70d41ca97c..57f97d6ebc 100644 --- a/themes/theme-gmd/pages/index.jsx +++ b/themes/theme-gmd/pages/index.jsx @@ -41,7 +41,7 @@ import { ThemeContext } from '@shopgate/pwa-common/context'; import { APP_GLOBALS } from '@shopgate/pwa-common/constants/Portals'; import Viewport from 'Components/Viewport'; import Dialog from '@shopgate/pwa-ui-shared/Dialog'; -import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; +import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock/constants'; import * as routes from './routes'; import { routesTransforms } from './routesTransforms'; import themeApi from '../themeApi'; From c4ea41df42321279fcaf2b0aa182d4a59c80a9c6 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 14:01:52 +0100 Subject: [PATCH 44/55] CURB-3886 Fetch only active / triggered subscriptions --- libraries/engage/back-in-stock/actions/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index 78dcbbcc65..2ab501f358 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -23,6 +23,9 @@ export const fetchBackInStockSubscriptions = () => (dispatch) => { const request = new PipelineRequest(SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS) .setInput({ limit: 100, + filters: { + status: { $in: ['active', 'triggered'] }, + }, }) .setRetries(0) .dispatch(); From 058e92573d1ccee1e4a102c527e14ed0434221f8 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 14:46:07 +0100 Subject: [PATCH 45/55] CURB-3886 Even more review feedback --- .../components/BackInStockButton/index.jsx | 10 ++++- .../components/BackInStockButton/style.js | 1 - .../components/Subscription/index.jsx | 2 + .../engage/core/actions/grantPermissions.js | 41 ++++++++++--------- .../core/actions/grantPushPermissions.js | 29 ++++++------- 5 files changed, 46 insertions(+), 37 deletions(-) diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx b/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx index abbb730bb9..bc03382b7e 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx +++ b/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx @@ -6,7 +6,7 @@ import { CheckedIcon, NotificationIcon, } from '@shopgate/engage/components'; -import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; +import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock/constants'; import { i18n } from '@shopgate/engage/core'; import styles from './style'; import connect from './connector'; @@ -37,7 +37,13 @@ const BackInStockButton = ({ if (stopPropagation) { event.stopPropagation(); } - const allowed = await grantPushPermissions(); + const allowed = await grantPushPermissions({ + rationaleModal: { + message: 'permissions.back_in_stock_push_notifications.message', + confirm: 'permissions.back_in_stock_push_notifications.confirm', + dismiss: 'permissions.back_in_stock_push_notifications.dismiss', + }, + }); if (allowed) { addBackInStockSubscription({ productId }); } diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/style.js b/libraries/engage/back-in-stock/components/BackInStockButton/style.js index b9078aa788..0253a27a5b 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/style.js +++ b/libraries/engage/back-in-stock/components/BackInStockButton/style.js @@ -12,7 +12,6 @@ export default { backInStockMessageContainer: css({ display: 'inline', alignItems: 'center', - textAlign: 'end', lineHeight: '20px', }).toString(), backInStockMessage: css({ diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx index cf227511dd..e78e59be8b 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx @@ -31,6 +31,7 @@ const styles = { flex: 0.4, maxWidth: 170, minWidth: 70, + paddingRight: '8px', }).toString(), infoContainer: css({ flex: 1, @@ -74,6 +75,7 @@ const styles = { }).toString(), availabilityText: css({ fontSize: '0.875rem', + marginBottom: '4px', }).toString(), }; diff --git a/libraries/engage/core/actions/grantPermissions.js b/libraries/engage/core/actions/grantPermissions.js index 1a6c812b14..c70a922400 100644 --- a/libraries/engage/core/actions/grantPermissions.js +++ b/libraries/engage/core/actions/grantPermissions.js @@ -23,12 +23,13 @@ import { logger } from '@shopgate/pwa-core/helpers'; * @param {string} options.permissionId The id of the permission to request. * @param {boolean} [options.useSettingsModal=false] Whether in case of declined permissions a modal * shall be presented, which redirects to the app settings. - * @param {Object} [options.requestModal={}] Options for the request permission modal. - * @param {string} options.requestModal.title Modal title. - * @param {string} options.requestModal.message Modal message. - * @param {string} options.requestModal.confirm Label for the confirm button. - * @param {string} options.requestModal.dismiss Label for the dismiss button. - * @param {Object} options.requestModal.params Additional parameters for i18n strings. + * @param {boolean} [options.useRationaleModal=false] Whether a rational modal should be shown + * @param {Object} [options.rationaleModal={}] Options for the rationale modal. + * @param {string} options.rationaleModal.title Modal title. + * @param {string} options.rationaleModal.message Modal message. + * @param {string} options.rationaleModal.confirm Label for the confirm button. + * @param {string} options.rationaleModal.dismiss Label for the dismiss button. + * @param {Object} options.rationaleModal.params Additional parameters for i18n strings. * @param {Object} [options.modal={}] Options for the settings modal. * @param {string} options.modal.title Modal title. * @param {string} options.modal.message Modal message. @@ -41,8 +42,8 @@ const grantPermissions = (options = {}) => dispatch => new Promise(async (resolv const { permissionId, useSettingsModal = false, - useRequestModal = false, - requestModal: requestModalOptions = {}, + useRationaleModal = false, + rationaleModal: rationaleModalOptions = {}, modal: modalOptions = {}, } = options; @@ -65,27 +66,27 @@ const grantPermissions = (options = {}) => dispatch => new Promise(async (resolv // The user never seen the permissions dialog yet, or temporary denied the permissions (Android). if (status === STATUS_NOT_DETERMINED) { - if (useRequestModal) { + if (useRationaleModal) { const requestAllowed = await dispatch(showModal({ - message: requestModalOptions.message, - confirm: requestModalOptions.confirm, - dismiss: requestModalOptions.dismiss, - params: requestModalOptions.params, + message: rationaleModalOptions.message || '', + confirm: rationaleModalOptions.confirm || '', + dismiss: rationaleModalOptions.dismiss || '', + params: rationaleModalOptions.params || '', })); if (requestAllowed === false) { resolve(false); return; } + } - // Trigger the native permissions dialog. - [{ status }] = await requestAppPermissions([{ permissionId }]); + // Trigger the native permissions dialog. + [{ status }] = await requestAppPermissions([{ permissionId }]); - // The user denied the permissions within the native dialog. - if ([STATUS_DENIED, STATUS_NOT_DETERMINED].includes(status)) { - resolve(false); - return; - } + // The user denied the permissions within the native dialog. + if ([STATUS_DENIED, STATUS_NOT_DETERMINED].includes(status)) { + resolve(false); + return; } } diff --git a/libraries/engage/core/actions/grantPushPermissions.js b/libraries/engage/core/actions/grantPushPermissions.js index 42ae748953..a69cbeaa1f 100644 --- a/libraries/engage/core/actions/grantPushPermissions.js +++ b/libraries/engage/core/actions/grantPushPermissions.js @@ -12,12 +12,13 @@ import grantPermissions from './grantPermissions'; * @param {Object} options Action options. * @param {boolean} [options.useSettingsModal=false] Whether in case of declined permissions a modal * shall be presented, which redirects to the app settings. - * @param {Object} [options.requestModal={}] Options for the request permissions modal. - * @param {string} options.requestModal.title Modal title. - * @param {string} options.requestModal.message Modal message. - * @param {string} options.requestModal.confirm Label for the confirm button. - * @param {string} options.requestModal.dismiss Label for the dismiss button. - * @param {Object} options.requestModal.params Additional parameters for i18n strings. + * @param {boolean} [options.useRationaleModal=true] Whether a rational modal should be shown + * @param {Object} [options.rationaleModal={}] Options for the rationale modal. + * @param {string} options.rationaleModal.title Modal title. + * @param {string} options.rationaleModal.message Modal message. + * @param {string} options.rationaleModal.confirm Label for the confirm button. + * @param {string} options.rationaleModal.dismiss Label for the dismiss button. + * @param {Object} options.rationaleModal.params Additional parameters for i18n strings. * @param {Object} [options.modal={}] Options for the settings modal. * @param {string} options.modal.title Modal title. * @param {string} options.modal.message Modal message. @@ -27,7 +28,12 @@ import grantPermissions from './grantPermissions'; * @return { Function } A redux thunk. */ const grantPushPermissions = (options = {}) => dispatch => new Promise(async (resolve) => { - const { useSettingsModal = true, modal = {}, requestModal = {} } = options; + const { + useSettingsModal = true, + useRationaleModal = true, + modal = {}, + rationaleModal = {}, + } = options; const [{ status }] = await getAppPermissions([PERMISSION_ID_PUSH]); if (status === STATUS_GRANTED) { @@ -38,19 +44,14 @@ const grantPushPermissions = (options = {}) => dispatch => new Promise(async (re const allowed = await dispatch(grantPermissions({ permissionId: PERMISSION_ID_PUSH, useSettingsModal, + useRationaleModal, modal: { title: null, message: 'permissions.access_denied.push_message', confirm: 'permissions.access_denied.settings_button', ...modal, }, - requestModal: { - message: 'permissions.back_in_stock_push_notifications.message', - confirm: 'permissions.back_in_stock_push_notifications.confirm', - dismiss: 'permissions.back_in_stock_push_notifications.dismiss', - ...requestModal, - }, - + rationaleModal, })); resolve(allowed); From 9ed45f741d9a0cd07bac867e2cb46f6cb9030bfa Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 14:51:06 +0100 Subject: [PATCH 46/55] CURB-3886 Adjust translations --- themes/theme-gmd/locale/de-DE.json | 6 +++--- themes/theme-ios11/locale/de-DE.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/themes/theme-gmd/locale/de-DE.json b/themes/theme-gmd/locale/de-DE.json index 46ee1117d4..9065729a5a 100644 --- a/themes/theme-gmd/locale/de-DE.json +++ b/themes/theme-gmd/locale/de-DE.json @@ -20,14 +20,14 @@ "reviews": "Bewertungen", "favorites": "Merkliste", "scanner": "Scanner", - "back_in_stock": "Wieder-auf-Lager Benachrichtigungen" + "back_in_stock": "Benachrichtigungen" }, "back_in_stock": { "list_states": { "active": "Aktive Benachrichtigungen", "past": "Vergangene Benachrichtigungen" }, - "empty_list_reminder": "Sie haben keine Benachrichtigungen konfiguriert", + "empty_list_reminder": "Du hast keine Benachrichtigungen konfiguriert", "get_notified": "Benachrichtige mich", "we_will_remind_you": "Du wirst benachrichtigt", "add_back_in_stock_success_modal": { @@ -253,7 +253,7 @@ "more": "Mehr", "about": "Über uns" }, - "back_in_stock": "Wieder-auf-Lager Benachrichtigungen", + "back_in_stock": "Benachrichtigungen", "back": "Zurück zu {title}", "open_menu": "Menü öffnen" }, diff --git a/themes/theme-ios11/locale/de-DE.json b/themes/theme-ios11/locale/de-DE.json index d0dc13d6a6..25122e704c 100644 --- a/themes/theme-ios11/locale/de-DE.json +++ b/themes/theme-ios11/locale/de-DE.json @@ -21,14 +21,14 @@ "browse": "Durchsuchen", "favorites": "Merkliste", "scanner": "Scanner", - "back_in_stock": "Wieder-auf-Lager Benachrichtigungen" + "back_in_stock": "Benachrichtigungen" }, "back_in_stock": { "list_states": { "active": "Aktive Benachrichtigungen", "past": "Vergangene Benachrichtigungen" }, - "empty_list_reminder": "Sie haben keine Benachrichtigungen konfiguriert", + "empty_list_reminder": "Du hast keine Benachrichtigungen konfiguriert", "get_notified": "Benachrichtige mich", "we_will_remind_you": "Du wirst benachrichtigt", "add_back_in_stock_success_modal": { @@ -254,7 +254,7 @@ "logout": "Abmelden", "store_information": "Über uns", "more_menu": "Mehr", - "back_in_stock": "Wieder-auf-Lager Benachrichtigungen", + "back_in_stock": "Benachrichtigungen", "back": "Zurück zu {title}" }, "reviews": { From ca8935f10464b909d3a1652af62f4c822a565a94 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 15:00:25 +0100 Subject: [PATCH 47/55] CURB-3886 Some fixes --- .../back-in-stock/components/BackInStockButton/index.jsx | 3 ++- themes/theme-ios11/pages/More/components/Quicklinks/index.jsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx b/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx index bc03382b7e..a9e572d3b2 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx +++ b/libraries/engage/back-in-stock/components/BackInStockButton/index.jsx @@ -79,8 +79,8 @@ const BackInStockButton = ({ BackInStockButton.propTypes = { addBackInStockSubscription: PropTypes.func.isRequired, grantPushPermissions: PropTypes.func.isRequired, - productId: PropTypes.string.isRequired, isLinkToBackInStockEnabled: PropTypes.bool, + productId: PropTypes.string, stopPropagation: PropTypes.bool, subscription: PropTypes.shape(), }; @@ -89,6 +89,7 @@ BackInStockButton.defaultProps = { stopPropagation: false, isLinkToBackInStockEnabled: false, subscription: null, + productId: null, }; export default connect(BackInStockButton); diff --git a/themes/theme-ios11/pages/More/components/Quicklinks/index.jsx b/themes/theme-ios11/pages/More/components/Quicklinks/index.jsx index c6e735dfe6..aae8736367 100644 --- a/themes/theme-ios11/pages/More/components/Quicklinks/index.jsx +++ b/themes/theme-ios11/pages/More/components/Quicklinks/index.jsx @@ -6,7 +6,7 @@ import { import { NAV_MENU_QUICK_LINKS, } from '@shopgate/pwa-common/constants/Portals'; -import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock'; +import { BACK_IN_STOCK_PATTERN } from '@shopgate/engage/back-in-stock/constants'; import portalProps from '../../portalProps'; import Section from '../Section'; From 9377dac95b6508dc58db69872ef9e98a2b781306 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Tue, 27 Feb 2024 15:41:45 +0100 Subject: [PATCH 48/55] CURB-3886 Back in Stock feature index --- .../engage/back-in-stock/actions/index.js | 3 ++- .../components/BackInStockButton/connector.js | 1 - .../CharacteristicsButton/connector.js | 2 +- .../ProductInfoBackInStockButton/connector.js | 2 +- .../ProductInfoBackInStockButton/index.jsx | 2 +- .../Subscriptions/components/List/index.jsx | 2 +- .../components/Subscription/connector.js | 2 +- .../components/Subscriptions/index.jsx | 2 +- .../engage/back-in-stock/components/index.js | 3 +++ libraries/engage/back-in-stock/hooks/index.js | 2 +- libraries/engage/back-in-stock/index.js | 20 ------------------- ...kInStockSubscriptionsProvider.connector.js | 2 +- .../engage/back-in-stock/providers/index.js | 2 ++ .../engage/back-in-stock/reducers/index.js | 3 ++- .../engage/back-in-stock/streams/index.js | 4 ++-- .../back-in-stock/subscriptions/index.js | 4 ++-- .../components/SheetItem/index.jsx | 2 +- .../components/Badge/connector.js | 2 +- .../components/BackInStockButton/connector.js | 2 +- .../components/BackInStockButton/index.jsx | 2 +- themes/theme-gmd/pages/BackInStock/index.jsx | 2 +- .../Header/components/ProductInfo/index.jsx | 2 +- .../theme-ios11/pages/BackInStock/index.jsx | 2 +- .../More/components/Quicklinks/connector.js | 2 +- .../Header/components/ProductInfo/index.jsx | 2 +- 25 files changed, 30 insertions(+), 44 deletions(-) delete mode 100644 libraries/engage/back-in-stock/index.js create mode 100644 libraries/engage/back-in-stock/providers/index.js diff --git a/libraries/engage/back-in-stock/actions/index.js b/libraries/engage/back-in-stock/actions/index.js index 2ab501f358..07574d55f4 100644 --- a/libraries/engage/back-in-stock/actions/index.js +++ b/libraries/engage/back-in-stock/actions/index.js @@ -5,7 +5,8 @@ import { SHOPGATE_USER_GET_BACK_IN_STOCK_SUBSCRIPTIONS, ADD_BACK_IN_STOCK_SUBSCRIPTION, ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, - ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS, + ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + FETCH_BACK_IN_STOCK_SUBSCRIPTIONS, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, REMOVE_BACK_IN_STOCK_SUBSCRIPTION, diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/connector.js b/libraries/engage/back-in-stock/components/BackInStockButton/connector.js index de7f4214d6..9cfa990018 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/connector.js +++ b/libraries/engage/back-in-stock/components/BackInStockButton/connector.js @@ -5,7 +5,6 @@ import grantPushPermissions from '@shopgate/engage/core/actions/grantPushPermiss const mapDispatchToProps = { addBackInStockSubscription, grantPushPermissions, - }; export default connect(null, mapDispatchToProps); diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js index 64435288fa..bdcc5a9d38 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js @@ -2,7 +2,7 @@ import { connect } from 'react-redux'; import { getIsBackInStockEnabled, makeGetSubscriptionByCharacteristics, -} from '@shopgate/engage/back-in-stock'; +} from '@shopgate/engage/back-in-stock/selectors'; import { makeGetProductByCharacteristics, } from '@shopgate/engage/product'; diff --git a/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/connector.js b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/connector.js index 7168adb4c8..b888dca995 100644 --- a/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/connector.js +++ b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/connector.js @@ -2,7 +2,7 @@ import { connect } from 'react-redux'; import { getIsBackInStockEnabled, makeGetSubscriptionByProduct, -} from '@shopgate/engage/back-in-stock'; +} from '@shopgate/engage/back-in-stock/selectors'; import { getProduct, } from '@shopgate/engage/product'; diff --git a/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx index fea6c7bb4a..71cec3cf90 100644 --- a/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx +++ b/libraries/engage/back-in-stock/components/ProductInfoBackInStockButton/index.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { SurroundPortals } from '@shopgate/engage/components'; import { PRODUCT_BACK_IN_STOCK, -} from '@shopgate/engage/back-in-stock'; +} from '@shopgate/engage/back-in-stock/constants'; import { BackInStockButton } from '@shopgate/engage/back-in-stock/components'; import { withCurrentProduct } from '@shopgate/engage/core'; import connect from './connector'; diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx index 31d28d502b..6cec51dd08 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/List/index.jsx @@ -2,7 +2,7 @@ import React, { useCallback } from 'react'; import { css } from 'glamor'; import { LoadingIndicator, Accordion, Card } from '@shopgate/engage/components'; import { i18n } from '@shopgate/engage/core'; -import { useBackInStockSubscriptions } from '../../../../hooks'; +import { useBackInStockSubscriptions } from '@shopgate/engage/back-in-stock/hooks'; import Subscription from '../Subscription'; const styles = { diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js index 9422a5175d..b4f0464de5 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/connector.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { addBackInStockSubscription } from '@shopgate/engage/back-in-stock/actions'; -import { makeGetSubscriptionByProduct } from '@shopgate/engage/back-in-stock'; +import { makeGetSubscriptionByProduct } from '@shopgate/engage/back-in-stock/selectors'; /** * @return {Object} The extended component props. diff --git a/libraries/engage/back-in-stock/components/Subscriptions/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/index.jsx index f6076726bd..8299df7d04 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/index.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { BackInStockSubscriptionsProvider } from '@shopgate/engage/back-in-stock'; +import { BackInStockSubscriptionsProvider } from '@shopgate/engage/back-in-stock/providers'; import List from './components/List'; /** diff --git a/libraries/engage/back-in-stock/components/index.js b/libraries/engage/back-in-stock/components/index.js index a63c545cdc..38a791d578 100644 --- a/libraries/engage/back-in-stock/components/index.js +++ b/libraries/engage/back-in-stock/components/index.js @@ -1 +1,4 @@ export { default as BackInStockButton } from './BackInStockButton'; +export { default as BackInStockReminders } from './Subscriptions'; +export { default as ProductInfoBackInStockButton } from './ProductInfoBackInStockButton'; +export { default as CharacteristicsButton } from './CharacteristicsButton'; diff --git a/libraries/engage/back-in-stock/hooks/index.js b/libraries/engage/back-in-stock/hooks/index.js index 3cef9f2ee4..68b3e38581 100644 --- a/libraries/engage/back-in-stock/hooks/index.js +++ b/libraries/engage/back-in-stock/hooks/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import { BackInStockSubscriptionsProviderContext } from '@shopgate/engage/back-in-stock'; +import { BackInStockSubscriptionsProviderContext } from '@shopgate/engage/back-in-stock/providers'; /** * Gives access to the values which the context BackInStockSubscriptionsProvider provide diff --git a/libraries/engage/back-in-stock/index.js b/libraries/engage/back-in-stock/index.js deleted file mode 100644 index 51c75c92cd..0000000000 --- a/libraries/engage/back-in-stock/index.js +++ /dev/null @@ -1,20 +0,0 @@ -// Components -export { default as BackInStockReminders } from './components/Subscriptions'; -export { default as ProductInfoBackInStockButton } from './components/ProductInfoBackInStockButton'; -export { default as CharacteristicsButton } from './components/CharacteristicsButton'; - -// ACTIONS -export * from './actions'; - -// HOOKs -export * from './hooks'; - -// STREAMS -export * from './streams'; - -// SELECTORS -export * from './selectors'; - -// --------------- CONTEXTS / PROVIDERS --------------- // -export { default as BackInStockSubscriptionsProviderContext } from './providers/BackInStockSubscriptionsProvider.context'; -export { default as BackInStockSubscriptionsProvider } from './providers/BackInStockSubscriptionsProvider'; diff --git a/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js index 0ecd2fc954..a15a22ce4d 100644 --- a/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js +++ b/libraries/engage/back-in-stock/providers/BackInStockSubscriptionsProvider.connector.js @@ -3,7 +3,7 @@ import { getBackInStockSubscriptions, getBackInStockSubscriptionsFetching, getBackInStockSubscriptionsInitial, -} from '@shopgate/engage/back-in-stock'; +} from '@shopgate/engage/back-in-stock/selectors'; import { addBackInStockSubscription, removeBackInStockSubscription, diff --git a/libraries/engage/back-in-stock/providers/index.js b/libraries/engage/back-in-stock/providers/index.js new file mode 100644 index 0000000000..275cf11069 --- /dev/null +++ b/libraries/engage/back-in-stock/providers/index.js @@ -0,0 +1,2 @@ +export { default as BackInStockSubscriptionsProviderContext } from './BackInStockSubscriptionsProvider.context'; +export { default as BackInStockSubscriptionsProvider } from './BackInStockSubscriptionsProvider'; diff --git a/libraries/engage/back-in-stock/reducers/index.js b/libraries/engage/back-in-stock/reducers/index.js index 40d5260de2..a9e0499962 100644 --- a/libraries/engage/back-in-stock/reducers/index.js +++ b/libraries/engage/back-in-stock/reducers/index.js @@ -1,7 +1,8 @@ import { ADD_BACK_IN_STOCK_SUBSCRIPTION, ADD_BACK_IN_STOCK_SUBSCRIPTION_ERROR, - ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS, + ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, + FETCH_BACK_IN_STOCK_SUBSCRIPTIONS, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_ERROR, FETCH_BACK_IN_STOCK_SUBSCRIPTIONS_SUCCESS, REMOVE_BACK_IN_STOCK_SUBSCRIPTION, diff --git a/libraries/engage/back-in-stock/streams/index.js b/libraries/engage/back-in-stock/streams/index.js index 5b8917293f..074bcdc549 100644 --- a/libraries/engage/back-in-stock/streams/index.js +++ b/libraries/engage/back-in-stock/streams/index.js @@ -1,5 +1,5 @@ -import { appDidStart$, main$, routeDidEnter$ } from '@shopgate/pwa-common/streams'; -import { productWillEnter$ } from '@shopgate/pwa-common-commerce/product'; +import { appDidStart$, main$, routeDidEnter$ } from '@shopgate/engage/core'; +import { productWillEnter$ } from '@shopgate/engage/product'; import { ADD_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, REMOVE_BACK_IN_STOCK_SUBSCRIPTION_SUCCESS, diff --git a/libraries/engage/back-in-stock/subscriptions/index.js b/libraries/engage/back-in-stock/subscriptions/index.js index be3125a6ce..fa62e4085a 100644 --- a/libraries/engage/back-in-stock/subscriptions/index.js +++ b/libraries/engage/back-in-stock/subscriptions/index.js @@ -1,9 +1,9 @@ import showModal from '@shopgate/pwa-common/actions/modal/showModal'; +import { fetchBackInStockSubscriptions } from '@shopgate/engage/back-in-stock/actions'; import { addBackInStockReminderSuccess$, backInStockReminderNeedsFetch$, -} from '../streams'; -import { fetchBackInStockSubscriptions } from '../actions'; +} from '@shopgate/engage/back-in-stock/streams'; /** * @param {Function} subscribe The subscribe function. diff --git a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx index 958a151c4c..ceeebf57af 100644 --- a/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx +++ b/libraries/engage/product/components/Characteristics/Characteristic/components/SheetItem/index.jsx @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { withForwardedRef } from '@shopgate/engage/core'; -import { CharacteristicsButton } from '@shopgate/engage/back-in-stock'; +import { CharacteristicsButton } from '@shopgate/engage/back-in-stock/components'; import styles from './style'; /** diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/connector.js b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/connector.js index 73dec248cc..2129e7ba2b 100644 --- a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/connector.js +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/components/Badge/connector.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { getHasBackInStockSubscriptions } from '@shopgate/engage/back-in-stock'; +import { getHasBackInStockSubscriptions } from '@shopgate/engage/back-in-stock/selectors'; /** * Maps the contents of the state to the component props. diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/connector.js b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/connector.js index 5ae6868224..e540a879b5 100644 --- a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/connector.js +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/connector.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { getIsBackInStockEnabled } from '@shopgate/engage/back-in-stock'; +import { getIsBackInStockEnabled } from '@shopgate/engage/back-in-stock/selectors'; /** * @param {Object} state The application state. diff --git a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx index 42c6d76c9d..9b54e7025b 100644 --- a/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx +++ b/themes/theme-gmd/components/NavDrawer/components/Main/components/BackInStockButton/index.jsx @@ -6,7 +6,7 @@ import { NAV_MENU_BACK_IN_STOCK, NAV_MENU_BACK_IN_STOCK_AFTER, NAV_MENU_BACK_IN_STOCK_BEFORE, -} from '@shopgate/engage/back-in-stock'; +} from '@shopgate/engage/back-in-stock/constants'; import navDrawerConnect from '../../../../connector'; import portalProps from '../../../../portalProps'; import Badge from './components/Badge'; diff --git a/themes/theme-gmd/pages/BackInStock/index.jsx b/themes/theme-gmd/pages/BackInStock/index.jsx index a9823b9d31..56dedeb561 100644 --- a/themes/theme-gmd/pages/BackInStock/index.jsx +++ b/themes/theme-gmd/pages/BackInStock/index.jsx @@ -2,7 +2,7 @@ import { View } from '@shopgate/engage/components'; import React from 'react'; import { i18n } from '@shopgate/engage/core'; import { BackBar } from 'Components/AppBar/presets'; -import { BackInStockReminders } from '@shopgate/engage/back-in-stock'; +import { BackInStockReminders } from '@shopgate/engage/back-in-stock/components'; /** * The BackInStockPage component. diff --git a/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx b/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx index 98e23a738f..67d52744a7 100644 --- a/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Header/components/ProductInfo/index.jsx @@ -13,7 +13,7 @@ import { import Shipping from '@shopgate/engage/product/components/Header/Shipping'; import Tiers from '@shopgate/engage/product/components/Header/Tiers'; import PriceStriked from '@shopgate/engage/product/components/Header/PriceStriked'; -import { ProductInfoBackInStockButton } from '@shopgate/engage/back-in-stock'; +import { ProductInfoBackInStockButton } from '@shopgate/engage/back-in-stock/components'; import Manufacturer from '../Manufacturer'; import Availability from '../Availability'; import Price from '../Price'; diff --git a/themes/theme-ios11/pages/BackInStock/index.jsx b/themes/theme-ios11/pages/BackInStock/index.jsx index a9823b9d31..56dedeb561 100644 --- a/themes/theme-ios11/pages/BackInStock/index.jsx +++ b/themes/theme-ios11/pages/BackInStock/index.jsx @@ -2,7 +2,7 @@ import { View } from '@shopgate/engage/components'; import React from 'react'; import { i18n } from '@shopgate/engage/core'; import { BackBar } from 'Components/AppBar/presets'; -import { BackInStockReminders } from '@shopgate/engage/back-in-stock'; +import { BackInStockReminders } from '@shopgate/engage/back-in-stock/components'; /** * The BackInStockPage component. diff --git a/themes/theme-ios11/pages/More/components/Quicklinks/connector.js b/themes/theme-ios11/pages/More/components/Quicklinks/connector.js index 34521ad608..842ee8b137 100644 --- a/themes/theme-ios11/pages/More/components/Quicklinks/connector.js +++ b/themes/theme-ios11/pages/More/components/Quicklinks/connector.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { QUICKLINKS_MENU } from '@shopgate/pwa-common/constants/MenuIDs'; import { getMenuById } from '@shopgate/pwa-common/selectors/menu'; -import { getIsBackInStockEnabled } from '@shopgate/engage/back-in-stock'; +import { getIsBackInStockEnabled } from '@shopgate/engage/back-in-stock/selectors'; const props = { id: QUICKLINKS_MENU, diff --git a/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx b/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx index 98e23a738f..67d52744a7 100644 --- a/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx +++ b/themes/theme-ios11/pages/Product/components/Header/components/ProductInfo/index.jsx @@ -13,7 +13,7 @@ import { import Shipping from '@shopgate/engage/product/components/Header/Shipping'; import Tiers from '@shopgate/engage/product/components/Header/Tiers'; import PriceStriked from '@shopgate/engage/product/components/Header/PriceStriked'; -import { ProductInfoBackInStockButton } from '@shopgate/engage/back-in-stock'; +import { ProductInfoBackInStockButton } from '@shopgate/engage/back-in-stock/components'; import Manufacturer from '../Manufacturer'; import Availability from '../Availability'; import Price from '../Price'; From c6c6f095d1b96f9214e6b9e8423ae8273b14b592 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 28 Feb 2024 08:45:48 +0100 Subject: [PATCH 49/55] CURB-3886 Adjust translations --- themes/theme-gmd/locale/en-US.json | 4 ++-- themes/theme-ios11/locale/en-US.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/themes/theme-gmd/locale/en-US.json b/themes/theme-gmd/locale/en-US.json index 4fe2fa09ba..ec302727aa 100644 --- a/themes/theme-gmd/locale/en-US.json +++ b/themes/theme-gmd/locale/en-US.json @@ -20,7 +20,7 @@ "reviews": "Reviews", "favorites": "Favorites", "scanner": "Scanner", - "back_in_stock": "Back in Stock Reminders" + "back_in_stock": "Notifications" }, "back_in_stock": { "list_states": { @@ -241,7 +241,7 @@ "my_orders": "My orders", "cart": "Shopping cart", "scanner": "Scanner", - "back_in_stock": "Back in Stock reminder", + "back_in_stock": "Notifications", "shipping": "Shipping methods", "about": "Contact us", "payment": "Payment methods", diff --git a/themes/theme-ios11/locale/en-US.json b/themes/theme-ios11/locale/en-US.json index ef5c65b6a7..773775bcfe 100644 --- a/themes/theme-ios11/locale/en-US.json +++ b/themes/theme-ios11/locale/en-US.json @@ -21,7 +21,7 @@ "browse": "Browse", "favorites": "Favorites", "scanner": "Scanner", - "back_in_stock": "Back in Stock Reminders" + "back_in_stock": "Notifications" }, "back_in_stock": { "list_states": { @@ -253,7 +253,7 @@ "logout": "Logout", "store_information": "Store Information", "more_menu": "More", - "back_in_stock": "Back in Stock reminder", + "back_in_stock": "Notifications", "back": "Back to {title}" }, "reviews": { From fb2ac459e91f600e915d1d1a8a1fe9b0894f4cc1 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Wed, 28 Feb 2024 10:19:15 +0100 Subject: [PATCH 50/55] CURB-3886 Clear console errors --- .../Header/components/Availability/index.jsx | 2 +- .../components/Header/components/PriceInfo/index.jsx | 2 +- .../Header/components/Availability/index.jsx | 12 ++++++------ .../components/Header/components/PriceInfo/index.jsx | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/themes/theme-gmd/pages/Product/components/Header/components/Availability/index.jsx b/themes/theme-gmd/pages/Product/components/Header/components/Availability/index.jsx index c269e3d07f..ac0d1fcf01 100644 --- a/themes/theme-gmd/pages/Product/components/Header/components/Availability/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Header/components/Availability/index.jsx @@ -26,7 +26,7 @@ const Availability = ({ availability }) => ( )} diff --git a/themes/theme-gmd/pages/Product/components/Header/components/PriceInfo/index.jsx b/themes/theme-gmd/pages/Product/components/Header/components/PriceInfo/index.jsx index 4361223511..69b6d7722c 100644 --- a/themes/theme-gmd/pages/Product/components/Header/components/PriceInfo/index.jsx +++ b/themes/theme-gmd/pages/Product/components/Header/components/PriceInfo/index.jsx @@ -35,7 +35,7 @@ PriceInfo.propTypes = { }; PriceInfo.defaultProps = { - price: '', + price: null, }; export default connect(memo(PriceInfo)); diff --git a/themes/theme-ios11/pages/Product/components/Header/components/Availability/index.jsx b/themes/theme-ios11/pages/Product/components/Header/components/Availability/index.jsx index 7e01c4d565..25a064f9cc 100644 --- a/themes/theme-ios11/pages/Product/components/Header/components/Availability/index.jsx +++ b/themes/theme-ios11/pages/Product/components/Header/components/Availability/index.jsx @@ -22,12 +22,12 @@ const Availability = ({ availability }) => ( {availability && ( - + )} diff --git a/themes/theme-ios11/pages/Product/components/Header/components/PriceInfo/index.jsx b/themes/theme-ios11/pages/Product/components/Header/components/PriceInfo/index.jsx index 4361223511..97d27aefbd 100644 --- a/themes/theme-ios11/pages/Product/components/Header/components/PriceInfo/index.jsx +++ b/themes/theme-ios11/pages/Product/components/Header/components/PriceInfo/index.jsx @@ -22,7 +22,7 @@ const PriceInfo = ({ price }) => ( {(price && price.info !== '') && ( - + )} @@ -35,7 +35,7 @@ PriceInfo.propTypes = { }; PriceInfo.defaultProps = { - price: '', + price: null, }; export default connect(memo(PriceInfo)); From c589d38d75b78186d96355990b1f7d2e777760c6 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Thu, 29 Feb 2024 13:37:07 +0100 Subject: [PATCH 51/55] CURB-3886 More styling --- .../back-in-stock/components/BackInStockButton/style.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/engage/back-in-stock/components/BackInStockButton/style.js b/libraries/engage/back-in-stock/components/BackInStockButton/style.js index 0253a27a5b..35ad84dad3 100644 --- a/libraries/engage/back-in-stock/components/BackInStockButton/style.js +++ b/libraries/engage/back-in-stock/components/BackInStockButton/style.js @@ -10,9 +10,11 @@ export default { alignItems: 'center', }).toString(), backInStockMessageContainer: css({ - display: 'inline', - alignItems: 'center', lineHeight: '20px', + display: 'flex', + alignItems: 'center', + textAlign: 'end', + width: 'auto', }).toString(), backInStockMessage: css({ marginLeft: '4px', @@ -22,6 +24,7 @@ export default { buttonText: css({ marginLeft: '4px', fontSize: '0.875rem', + lineHeight: '16.5px', }).toString(), icon: css({ verticalAlign: 'middle', From 78083ebdc2c46a77ce82a3eb82847653157a22c8 Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Fri, 1 Mar 2024 09:09:52 +0100 Subject: [PATCH 52/55] CURB-3886 Fix makeGetProductByCharacteristics --- .../components/CharacteristicsButton/connector.js | 2 +- libraries/engage/product/selectors/variants.js | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js index bdcc5a9d38..df78fff532 100644 --- a/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js +++ b/libraries/engage/back-in-stock/components/CharacteristicsButton/connector.js @@ -11,7 +11,7 @@ import { * @return {Object} The extended component props. */ const makeMapStateToProps = () => { - const getProductByCharacteristics = makeGetProductByCharacteristics(); + const getProductByCharacteristics = makeGetProductByCharacteristics({ strict: true }); const getSubscriptionByCharacteristics = makeGetSubscriptionByCharacteristics(); return (state, props) => { diff --git a/libraries/engage/product/selectors/variants.js b/libraries/engage/product/selectors/variants.js index 1c6430cae3..9f942c85d4 100644 --- a/libraries/engage/product/selectors/variants.js +++ b/libraries/engage/product/selectors/variants.js @@ -1,12 +1,13 @@ import { createSelector } from 'reselect'; import find from 'lodash/find'; import { getProductVariants } from '@shopgate/pwa-common-commerce/product'; +import isEqual from 'lodash/isEqual'; /** * Creates a selector that retrieves a product by a characteristic. * @returns {Function} */ -export function makeGetProductByCharacteristics() { +export function makeGetProductByCharacteristics({ strict } = {}) { return createSelector( (_, props) => props.characteristics, getProductVariants, @@ -15,7 +16,14 @@ export function makeGetProductByCharacteristics() { return null; } - const product = find(variants.products, { characteristics }); + let product; + + if (strict) { + product = variants.products.find(_product => + isEqual(_product.characteristics, characteristics)); + } else { + product = find(variants.products, { characteristics }); + } if (!product) { return null; From e6374bb1c8bfe6294a4d2e5d35489f513f42a13e Mon Sep 17 00:00:00 2001 From: Sascha Krist Date: Fri, 1 Mar 2024 11:15:50 +0100 Subject: [PATCH 53/55] CURB-3886 Fix close icon on subscription list --- .../components/Subscription/index.jsx | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx index e78e59be8b..6d81a7333f 100644 --- a/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx +++ b/libraries/engage/back-in-stock/components/Subscriptions/components/Subscription/index.jsx @@ -77,6 +77,9 @@ const styles = { fontSize: '0.875rem', marginBottom: '4px', }).toString(), + ripple: css({ + minWidth: '17px', + }).toString(), }; /** @@ -112,22 +115,19 @@ const Subscription = ({
-
- - + - -
+ dangerouslySetInnerHTML={{ __html: `${product.name}` }} + /> +
); } From d88cb861c93848f2163d09ec0036bcfefa371f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frithjof=20Klo=CC=88s?= Date: Fri, 1 Mar 2024 16:39:23 +0100 Subject: [PATCH 55/55] CURB-3886 Fixed some unit tests --- libraries/common/helpers/config/__mocks__/index.js | 1 + libraries/common/helpers/config/mock.js | 3 ++- libraries/engage/back-in-stock/selectors/index.js | 2 +- themes/theme-gmd/components/NavDrawer/spec.jsx | 7 ++++++- themes/theme-gmd/pages/Product/components/Content/spec.jsx | 2 +- .../Quicklinks/__snapshots__/index.spec.jsx.snap | 2 ++ 6 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libraries/common/helpers/config/__mocks__/index.js b/libraries/common/helpers/config/__mocks__/index.js index 02bfade15f..43f237ea1e 100644 --- a/libraries/common/helpers/config/__mocks__/index.js +++ b/libraries/common/helpers/config/__mocks__/index.js @@ -5,6 +5,7 @@ export const themeColors = themeConfig.colors; export const themeShadows = themeConfig.shadows; export const themeVariables = themeConfig.variables; export const themeIcons = themeConfig.icons; +export const themeName = 'theme'; const appConfig = { get hideProductImageShadow() { return true; }, diff --git a/libraries/common/helpers/config/mock.js b/libraries/common/helpers/config/mock.js index 01d5b12bb0..4ae12c4592 100644 --- a/libraries/common/helpers/config/mock.js +++ b/libraries/common/helpers/config/mock.js @@ -99,6 +99,7 @@ const variables = { loadingIndicator: { size: 32, strokeWidth: 3, + imgSrc: null, }, paymentBar: { height: 78, @@ -207,4 +208,4 @@ export const themeConfig = { // Alias for jest hoisting export const mockThemeConfig = themeConfig; - +export const themeName = 'theme'; diff --git a/libraries/engage/back-in-stock/selectors/index.js b/libraries/engage/back-in-stock/selectors/index.js index db7cfdab8b..9525eb0eda 100644 --- a/libraries/engage/back-in-stock/selectors/index.js +++ b/libraries/engage/back-in-stock/selectors/index.js @@ -64,7 +64,7 @@ export const makeGetSubscriptionByCharacteristics = () => { * Returns if the back in stock feature is enabled * @returns {Function} */ -export const getIsBackInStockEnabled = () => appConfig?.showBackInStock; +export const getIsBackInStockEnabled = () => appConfig?.showBackInStock || false; /** * Returns if subscription list is in use diff --git a/themes/theme-gmd/components/NavDrawer/spec.jsx b/themes/theme-gmd/components/NavDrawer/spec.jsx index 65e456ab02..f85dfb5ec5 100644 --- a/themes/theme-gmd/components/NavDrawer/spec.jsx +++ b/themes/theme-gmd/components/NavDrawer/spec.jsx @@ -5,6 +5,8 @@ import Backdrop from '@shopgate/pwa-common/components/Backdrop'; import ConnectedNavDrawer, { Unwrapped as NavDrawer } from './index'; import headerStyles from './components/Header/style'; +jest.mock('@shopgate/pwa-common/helpers/config'); + // Mock the portal jest.mock('react-portal', () => ( ({ isOpened, children }) => ( @@ -15,6 +17,10 @@ jest.mock('@shopgate/engage', () => ({ themeConfig: {}, })); +jest.mock('@shopgate/engage/back-in-stock/selectors', () => ({ + isBackInStockEnabled: () => false, +})); + jest.mock('@shopgate/engage/components', () => ({ NavDrawer: jest.fn(), DescriptionIcon: jest.fn(), @@ -35,7 +41,6 @@ jest.mock('@shopgate/pwa-ui-shared/ClientInformation/connector', () => (obj) => return newObj; }); -jest.mock('@shopgate/pwa-common/helpers/config'); /* let mockedHasFavorites = true; jest.mock('@shopgate/pwa-common/helpers/config', () => ({ diff --git a/themes/theme-gmd/pages/Product/components/Content/spec.jsx b/themes/theme-gmd/pages/Product/components/Content/spec.jsx index 65d83c4994..4e525022ee 100644 --- a/themes/theme-gmd/pages/Product/components/Content/spec.jsx +++ b/themes/theme-gmd/pages/Product/components/Content/spec.jsx @@ -11,6 +11,7 @@ jest.mock('@shopgate/engage/product', () => ({ RelationsSlider: () => null, Description: () => null, Options: () => null, + Characteristics: () => null, ProductContext: { Provider: () => 'Provider', }, @@ -24,7 +25,6 @@ jest.mock('@shopgate/pwa-ui-shared/TaxDisclaimer', () => () => null); jest.mock('../Media', () => () => null); jest.mock('../Header', () => () => null); -jest.mock('../Characteristics', () => () => null); jest.mock('../AppBar', () => () => null); jest.mock('./connector', () => Component => Component); diff --git a/themes/theme-ios11/pages/More/components/Quicklinks/__snapshots__/index.spec.jsx.snap b/themes/theme-ios11/pages/More/components/Quicklinks/__snapshots__/index.spec.jsx.snap index 5991fbf8d7..1bc41f7312 100644 --- a/themes/theme-ios11/pages/More/components/Quicklinks/__snapshots__/index.spec.jsx.snap +++ b/themes/theme-ios11/pages/More/components/Quicklinks/__snapshots__/index.spec.jsx.snap @@ -16,6 +16,7 @@ exports[` should not render when no quicklinks are there 1`] = ` @@ -48,6 +49,7 @@ exports[` should render quicklinks 1`] = ` }, ] } + isBackInStockEnabled={false} >