@salesforce/retail-react-app 2.3.1 → 2.4.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/app/components/_app-config/index.jsx +12 -0
  3. package/app/components/confirmation-modal/index.jsx +11 -4
  4. package/app/components/item-variant/item-image.jsx +18 -0
  5. package/app/components/product-item/index.test.js +1 -1
  6. package/app/components/promo-code/index.jsx +25 -28
  7. package/app/components/unavailable-product-confirmation-modal/index.jsx +72 -0
  8. package/app/components/unavailable-product-confirmation-modal/index.test.js +362 -0
  9. package/app/constants.js +18 -0
  10. package/app/hooks/einstein-mock-data.js +157 -0
  11. package/app/hooks/use-einstein.js +3 -4
  12. package/app/hooks/use-einstein.test.js +19 -1
  13. package/app/pages/account/index.jsx +1 -1
  14. package/app/pages/account/order-detail.jsx +16 -14
  15. package/app/pages/account/profile.jsx +21 -30
  16. package/app/pages/account/wishlist/index.jsx +25 -1
  17. package/app/pages/cart/index.jsx +24 -6
  18. package/app/pages/checkout/index.jsx +55 -6
  19. package/app/pages/checkout/index.test.js +23 -7
  20. package/app/pages/checkout/partials/payment.jsx +2 -2
  21. package/app/pages/checkout/partials/shipping-options.jsx +1 -1
  22. package/app/pages/product-detail/index.jsx +1 -1
  23. package/app/pages/product-list/index.jsx +5 -2
  24. package/app/ssr.js +18 -1
  25. package/app/static/translations/compiled/en-GB.json +24 -0
  26. package/app/static/translations/compiled/en-US.json +24 -0
  27. package/app/static/translations/compiled/en-XA.json +56 -0
  28. package/app/utils/test-utils.js +1 -0
  29. package/app/utils/url.js +1 -4
  30. package/package.json +6 -6
  31. package/translations/en-GB.json +13 -0
  32. package/translations/en-US.json +13 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## v2.4.0-dev (Jan 22, 2024)
2
+
3
+ ### Bug Fixes
4
+
5
+ - Add Support for SLAS private flow [#1722](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1722)
6
+ - Fix promo codes not being properly applied in cart [#1692](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1692)
7
+ - Fix checkout shipping method fetching [#1693](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1693)
8
+ - Fix invalid query params warnings [#1655](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1655)
9
+ - Fix internal server error on account pages [#1675](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1675)
10
+ - Fix `product-item` component imports to ensure that it is overridable. [#1672](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1672)
11
+ - Fix locale selector navigating back to default locale [#1670](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1670)
12
+ - Fix handling of offline products on Cart, Checkout, Order History, and Wishlist pages [#1691](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1691)
13
+ - Fix tracking of `viewSearch` event for Einstein analytics, in the case of no-search-results [#1702](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1702)
14
+ - Remove invalid header `_sfdc_customer_id` due to recent MRT HTTP3 upgrade [#1731](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1731)
15
+
1
16
  ## v2.3.1 (Jan 23, 2024)
2
17
 
3
18
  ### Bug Fixes
@@ -4,6 +4,15 @@
4
4
  * SPDX-License-Identifier: BSD-3-Clause
5
5
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
6
  */
7
+
8
+ /*
9
+ * Developer note! When updating this file, make sure to also update the
10
+ * _app-config template files in pwa-kit-create-app.
11
+ *
12
+ * In the pwa-kit-create-app, the templates are found under:
13
+ * - assets/bootstrap/js/overrides/app/components/_app-config
14
+ * - assets/templates/@salesforce/retail-react-app/app/components/_app-config
15
+ */
7
16
  import React from 'react'
8
17
  import PropTypes from 'prop-types'
9
18
  import {ChakraProvider} from '@salesforce/retail-react-app/app/components/shared/ui'
@@ -55,6 +64,9 @@ const AppConfig = ({children, locals = {}}) => {
55
64
  redirectURI={`${appOrigin}/callback`}
56
65
  proxy={`${appOrigin}${commerceApiConfig.proxyPath}`}
57
66
  headers={headers}
67
+ // Uncomment 'enablePWAKitPrivateClient' to use SLAS private client login flows.
68
+ // Make sure to also enable useSLASPrivateClient in ssr.js when enabling this setting.
69
+ // enablePWAKitPrivateClient={true}
58
70
  OCAPISessionsURL={`${appOrigin}/mobify/proxy/ocapi/s/${locals.site?.id}/dw/shop/v22_8/sessions`}
59
71
  >
60
72
  <MultiSiteProvider site={locals.site} locale={locals.locale} buildUrl={locals.buildUrl}>
@@ -26,6 +26,7 @@ const ConfirmationModal = ({
26
26
  confirmationMessage = CONFIRMATION_DIALOG_DEFAULT_CONFIG.confirmationMessage,
27
27
  primaryActionLabel = CONFIRMATION_DIALOG_DEFAULT_CONFIG.primaryActionLabel,
28
28
  alternateActionLabel = CONFIRMATION_DIALOG_DEFAULT_CONFIG.alternateActionLabel,
29
+ hideAlternateAction = false,
29
30
  onPrimaryAction = noop,
30
31
  onAlternateAction = noop,
31
32
  ...props
@@ -57,9 +58,11 @@ const ConfirmationModal = ({
57
58
  </AlertDialogBody>
58
59
 
59
60
  <AlertDialogFooter>
60
- <Button variant="ghost" mr={3} onClick={handleAlternateActionClick}>
61
- {formatMessage(alternateActionLabel)}
62
- </Button>
61
+ {!hideAlternateAction ? (
62
+ <Button variant="ghost" mr={3} onClick={handleAlternateActionClick}>
63
+ {formatMessage(alternateActionLabel)}
64
+ </Button>
65
+ ) : null}
63
66
  <Button variant="solid" onClick={handleConfirmClick}>
64
67
  {formatMessage(primaryActionLabel)}
65
68
  </Button>
@@ -105,7 +108,11 @@ ConfirmationModal.propTypes = {
105
108
  /**
106
109
  * Action to execute if user selects alternate or secondary action
107
110
  */
108
- onAlternateAction: PropTypes.func
111
+ onAlternateAction: PropTypes.func,
112
+ /**
113
+ * Flag to hide of show alternative button
114
+ */
115
+ hideAlternateAction: PropTypes.bool
109
116
  }
110
117
 
111
118
  export default ConfirmationModal
@@ -50,6 +50,24 @@ const ItemImage = ({imageProps, ratio = 1, ...props}) => {
50
50
  />
51
51
  </Badge>
52
52
  )}
53
+ {variant.isProductUnavailable && (
54
+ <Badge
55
+ position="absolute"
56
+ top={0}
57
+ left={0}
58
+ marginLeft={2}
59
+ marginTop={2}
60
+ fontSize="10px"
61
+ variant="solid"
62
+ colorScheme="red"
63
+ >
64
+ <FormattedMessage
65
+ defaultMessage="Unavailable"
66
+ id="item_image.label.unavailable"
67
+ description="A unavailable badge placed on top of a product image"
68
+ />
69
+ </Badge>
70
+ )}
53
71
 
54
72
  {image && (
55
73
  <Image
@@ -5,7 +5,7 @@
5
5
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
6
  */
7
7
  import React from 'react'
8
- import ProductItem from '@salesforce/retail-react-app/app/components/product-item/index'
8
+ import ProductItem from '@salesforce/retail-react-app/app/components/product-item'
9
9
  import {mockedCustomerProductListsDetails} from '@salesforce/retail-react-app/app/mocks/mock-data'
10
10
  import {renderWithProviders} from '@salesforce/retail-react-app/app/utils/test-utils'
11
11
  import {screen} from '@testing-library/react'
@@ -33,38 +33,35 @@ export const usePromoCode = () => {
33
33
  const removePromoCodeMutation = useShopperBasketsMutation('removeCouponFromBasket')
34
34
 
35
35
  const submitPromoCode = async ({code}) => {
36
- applyPromoCodeMutation.mutate(
37
- {
36
+ try {
37
+ await applyPromoCodeMutation.mutateAsync({
38
38
  parameters: {basketId: basket?.basketId},
39
39
  body: {
40
40
  code
41
41
  }
42
- },
43
- {
44
- onSuccess: () => {
45
- form.reset({code: ''})
46
- toast({
47
- title: formatMessage({
48
- defaultMessage: 'Promotion applied',
49
- id: 'use_promocode.info.promo_applied'
50
- }),
51
- status: 'success',
52
- position: 'top-right',
53
- isClosable: true
54
- })
55
- },
56
- onError: () => {
57
- form.setError('code', {
58
- type: 'manual',
59
- message: formatMessage({
60
- defaultMessage:
61
- 'Check the code and try again, it may already be applied or the promo has expired.',
62
- id: 'use_promocode.error.check_the_code'
63
- })
64
- })
65
- }
66
- }
67
- )
42
+ })
43
+
44
+ form.reset({code: ''})
45
+
46
+ toast({
47
+ title: formatMessage({
48
+ defaultMessage: 'Promotion applied',
49
+ id: 'use_promocode.info.promo_applied'
50
+ }),
51
+ status: 'success',
52
+ position: 'top-right',
53
+ isClosable: true
54
+ })
55
+ } catch (e) {
56
+ form.setError('code', {
57
+ type: 'manual',
58
+ message: formatMessage({
59
+ defaultMessage:
60
+ 'Check the code and try again, it may already be applied or the promo has expired.',
61
+ id: 'use_promocode.error.check_the_code'
62
+ })
63
+ })
64
+ }
68
65
  }
69
66
 
70
67
  const removePromoCode = async (couponItemId) => {
@@ -0,0 +1,72 @@
1
+ /*
2
+ * Copyright (c) 2024, Salesforce, Inc.
3
+ * All rights reserved.
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
+ */
7
+
8
+ import React, {useEffect, useRef} from 'react'
9
+ import PropTypes from 'prop-types'
10
+ import {useProducts} from '@salesforce/commerce-sdk-react'
11
+ import {REMOVE_UNAVAILABLE_CART_ITEM_DIALOG_CONFIG} from '@salesforce/retail-react-app/app/constants'
12
+ import ConfirmationModal from '@salesforce/retail-react-app/app/components/confirmation-modal'
13
+ import {useDisclosure} from '@salesforce/retail-react-app/app/components/shared/ui'
14
+ import {noop} from '@salesforce/retail-react-app/app/utils/utils'
15
+
16
+ /**
17
+ * This Component will responsible to determine of a given product ids has become unavailable
18
+ * and will prompt the users to remove them before proceeding any further
19
+ *
20
+ * @param productIds - list of product ids to check for availability
21
+ * @param handleUnavailableProducts - callback function to handle what to do with unavailable products
22
+ * @returns {JSX.Element} - Conformation Modal Component
23
+ *
24
+ */
25
+ const UnavailableProductConfirmationModal = ({
26
+ productIds = [],
27
+ handleUnavailableProducts = noop
28
+ }) => {
29
+ const unavailableProductIdsRef = useRef(null)
30
+ useProducts(
31
+ {parameters: {ids: productIds?.join(','), allImages: true}},
32
+ {
33
+ enabled: productIds?.length > 0,
34
+ onSuccess: (result) => {
35
+ // when a product is unavailable, the getProducts will not return its product detail.
36
+ // we compare the response ids with the ones in basket to figure which product has become unavailable
37
+ const resProductIds = result.data?.map((i) => i.id) || []
38
+ const unavailableProductIds = productIds.filter((id) => !resProductIds.includes(id))
39
+ unavailableProductIdsRef.current = unavailableProductIds
40
+ }
41
+ }
42
+ )
43
+ const unavailableProductsModalProps = useDisclosure()
44
+ useEffect(() => {
45
+ if (unavailableProductIdsRef.current?.length > 0) {
46
+ unavailableProductsModalProps.onOpen()
47
+ }
48
+ }, [unavailableProductIdsRef.current])
49
+
50
+ return (
51
+ <ConfirmationModal
52
+ closeOnEsc={false}
53
+ closeOnOverlayClick={false}
54
+ {...REMOVE_UNAVAILABLE_CART_ITEM_DIALOG_CONFIG}
55
+ hideAlternateAction={true}
56
+ onPrimaryAction={async () => {
57
+ await handleUnavailableProducts(unavailableProductIdsRef.current)
58
+ unavailableProductIdsRef.current = null
59
+ unavailableProductsModalProps.onClose()
60
+ }}
61
+ onAlternateAction={() => {}}
62
+ {...unavailableProductsModalProps}
63
+ />
64
+ )
65
+ }
66
+
67
+ UnavailableProductConfirmationModal.propTypes = {
68
+ productIds: PropTypes.array,
69
+ handleUnavailableProducts: PropTypes.func
70
+ }
71
+
72
+ export default UnavailableProductConfirmationModal
@@ -0,0 +1,362 @@
1
+ /*
2
+ * Copyright (c) 2021, salesforce.com, inc.
3
+ * All rights reserved.
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
+ */
7
+
8
+ import React from 'react'
9
+ import UnavailableProductConfirmationModal from '@salesforce/retail-react-app/app/components/unavailable-product-confirmation-modal/index'
10
+ import {renderWithProviders} from '@salesforce/retail-react-app/app/utils/test-utils'
11
+ import {waitFor} from '@testing-library/react'
12
+ import {prependHandlersToServer} from '@salesforce/retail-react-app/jest-setup'
13
+ const mockProducts = {
14
+ limit: 0,
15
+ total: 1,
16
+ data: [
17
+ {
18
+ currency: 'GBP',
19
+ id: '701642889830M',
20
+ imageGroups: [
21
+ {
22
+ images: [
23
+ {
24
+ alt: 'Belted Cardigan With Studs, , large',
25
+ disBaseLink:
26
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw1c2304f9/images/large/PG.10215179.JJ0NLD0.PZ.jpg',
27
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw1c2304f9/images/large/PG.10215179.JJ0NLD0.PZ.jpg',
28
+ title: 'Belted Cardigan With Studs, '
29
+ },
30
+ {
31
+ alt: 'Belted Cardigan With Studs, , large',
32
+ disBaseLink:
33
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw23cbdec5/images/large/PG.10215179.JJ0NLD0.BZ.jpg',
34
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw23cbdec5/images/large/PG.10215179.JJ0NLD0.BZ.jpg',
35
+ title: 'Belted Cardigan With Studs, '
36
+ }
37
+ ],
38
+ viewType: 'large'
39
+ },
40
+ {
41
+ images: [
42
+ {
43
+ alt: 'Belted Cardigan With Studs, Laurel, large',
44
+ disBaseLink:
45
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw1c2304f9/images/large/PG.10215179.JJ0NLD0.PZ.jpg',
46
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw1c2304f9/images/large/PG.10215179.JJ0NLD0.PZ.jpg',
47
+ title: 'Belted Cardigan With Studs, Laurel'
48
+ },
49
+ {
50
+ alt: 'Belted Cardigan With Studs, Laurel, large',
51
+ disBaseLink:
52
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw23cbdec5/images/large/PG.10215179.JJ0NLD0.BZ.jpg',
53
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw23cbdec5/images/large/PG.10215179.JJ0NLD0.BZ.jpg',
54
+ title: 'Belted Cardigan With Studs, Laurel'
55
+ }
56
+ ],
57
+ variationAttributes: [
58
+ {
59
+ id: 'color',
60
+ values: [
61
+ {
62
+ value: 'JJ0NLD0'
63
+ }
64
+ ]
65
+ }
66
+ ],
67
+ viewType: 'large'
68
+ },
69
+ {
70
+ images: [
71
+ {
72
+ alt: 'Belted Cardigan With Studs, , medium',
73
+ disBaseLink:
74
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw521c09a6/images/medium/PG.10215179.JJ0NLD0.PZ.jpg',
75
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw521c09a6/images/medium/PG.10215179.JJ0NLD0.PZ.jpg',
76
+ title: 'Belted Cardigan With Studs, '
77
+ },
78
+ {
79
+ alt: 'Belted Cardigan With Studs, , medium',
80
+ disBaseLink:
81
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwb147ee45/images/medium/PG.10215179.JJ0NLD0.BZ.jpg',
82
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dwb147ee45/images/medium/PG.10215179.JJ0NLD0.BZ.jpg',
83
+ title: 'Belted Cardigan With Studs, '
84
+ }
85
+ ],
86
+ viewType: 'medium'
87
+ },
88
+ {
89
+ images: [
90
+ {
91
+ alt: 'Belted Cardigan With Studs, Laurel, medium',
92
+ disBaseLink:
93
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw521c09a6/images/medium/PG.10215179.JJ0NLD0.PZ.jpg',
94
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw521c09a6/images/medium/PG.10215179.JJ0NLD0.PZ.jpg',
95
+ title: 'Belted Cardigan With Studs, Laurel'
96
+ },
97
+ {
98
+ alt: 'Belted Cardigan With Studs, Laurel, medium',
99
+ disBaseLink:
100
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwb147ee45/images/medium/PG.10215179.JJ0NLD0.BZ.jpg',
101
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dwb147ee45/images/medium/PG.10215179.JJ0NLD0.BZ.jpg',
102
+ title: 'Belted Cardigan With Studs, Laurel'
103
+ }
104
+ ],
105
+ variationAttributes: [
106
+ {
107
+ id: 'color',
108
+ values: [
109
+ {
110
+ value: 'JJ0NLD0'
111
+ }
112
+ ]
113
+ }
114
+ ],
115
+ viewType: 'medium'
116
+ },
117
+ {
118
+ images: [
119
+ {
120
+ alt: 'Belted Cardigan With Studs, , small',
121
+ disBaseLink:
122
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwa5ed67ee/images/small/PG.10215179.JJ0NLD0.PZ.jpg',
123
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dwa5ed67ee/images/small/PG.10215179.JJ0NLD0.PZ.jpg',
124
+ title: 'Belted Cardigan With Studs, '
125
+ },
126
+ {
127
+ alt: 'Belted Cardigan With Studs, , small',
128
+ disBaseLink:
129
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw2baf85f2/images/small/PG.10215179.JJ0NLD0.BZ.jpg',
130
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw2baf85f2/images/small/PG.10215179.JJ0NLD0.BZ.jpg',
131
+ title: 'Belted Cardigan With Studs, '
132
+ }
133
+ ],
134
+ viewType: 'small'
135
+ },
136
+ {
137
+ images: [
138
+ {
139
+ alt: 'Belted Cardigan With Studs, Laurel, small',
140
+ disBaseLink:
141
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwa5ed67ee/images/small/PG.10215179.JJ0NLD0.PZ.jpg',
142
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dwa5ed67ee/images/small/PG.10215179.JJ0NLD0.PZ.jpg',
143
+ title: 'Belted Cardigan With Studs, Laurel'
144
+ },
145
+ {
146
+ alt: 'Belted Cardigan With Studs, Laurel, small',
147
+ disBaseLink:
148
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw2baf85f2/images/small/PG.10215179.JJ0NLD0.BZ.jpg',
149
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw2baf85f2/images/small/PG.10215179.JJ0NLD0.BZ.jpg',
150
+ title: 'Belted Cardigan With Studs, Laurel'
151
+ }
152
+ ],
153
+ variationAttributes: [
154
+ {
155
+ id: 'color',
156
+ values: [
157
+ {
158
+ value: 'JJ0NLD0'
159
+ }
160
+ ]
161
+ }
162
+ ],
163
+ viewType: 'small'
164
+ },
165
+ {
166
+ images: [
167
+ {
168
+ alt: 'Belted Cardigan With Studs, Laurel, swatch',
169
+ disBaseLink:
170
+ 'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw024437d3/images/swatch/PG.10215179.JJ0NLD0.CP.jpg',
171
+ link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw024437d3/images/swatch/PG.10215179.JJ0NLD0.CP.jpg',
172
+ title: 'Belted Cardigan With Studs, Laurel'
173
+ }
174
+ ],
175
+ variationAttributes: [
176
+ {
177
+ id: 'color',
178
+ values: [
179
+ {
180
+ value: 'JJ0NLD0'
181
+ }
182
+ ]
183
+ }
184
+ ],
185
+ viewType: 'swatch'
186
+ }
187
+ ],
188
+ inventory: {
189
+ ats: 68,
190
+ backorderable: false,
191
+ id: 'inventory_m',
192
+ orderable: true,
193
+ preorderable: false,
194
+ stockLevel: 68
195
+ },
196
+ longDescription:
197
+ 'Our best selling cardigan is now updated with a detachable belt and studs. Pair it with a Commerce Cloud Store shell and it is great for nine-to-five and beyond.',
198
+ master: {
199
+ masterId: '25502228M',
200
+ orderable: true,
201
+ price: 61.43
202
+ },
203
+ minOrderQuantity: 1,
204
+ name: 'Belted Cardigan With Studs',
205
+ pageDescription:
206
+ 'Our best selling cardigan is now updated with a detachable belt and studs. Pair it with a Commerce Cloud Store shell and it is great for nine-to-five and beyond.',
207
+ pageTitle: 'Belted Cardigan With Studs',
208
+ price: 61.43,
209
+ pricePerUnit: 61.43,
210
+ productPromotions: [
211
+ {
212
+ calloutMsg: 'Buy one Long Center Seam Skirt and get 2 tops',
213
+ promotionId: 'ChoiceOfBonusProdect-ProductLevel-ruleBased'
214
+ },
215
+ {
216
+ calloutMsg: '$50 Fixed Products Amount Above 100',
217
+ promotionId: '$50FixedProductsAmountAbove100'
218
+ },
219
+ {
220
+ calloutMsg: 'Bonus Product for Order Amounts Above 250',
221
+ promotionId: 'BonusProductOnOrderOfAmountABove250'
222
+ }
223
+ ],
224
+ shortDescription:
225
+ 'Our best selling cardigan is now updated with a detachable belt and studs. Pair it with a Commerce Cloud Store shell and it is great for nine-to-five and beyond.',
226
+ slugUrl:
227
+ 'https://zzrf-001.dx.commercecloud.salesforce.com/s/RefArchGlobal/belted-cardigan-with-studs/701642889830M.html?lang=en_GB',
228
+ stepQuantity: 1,
229
+ type: {
230
+ variant: true
231
+ },
232
+ unitMeasure: '',
233
+ unitQuantity: 0,
234
+ upc: '701642889830',
235
+ validFrom: {
236
+ default: '2010-11-18T05:00:00.000Z'
237
+ },
238
+ variants: [
239
+ {
240
+ orderable: true,
241
+ price: 61.43,
242
+ productId: '701642889823M',
243
+ variationValues: {
244
+ color: 'JJ0NLD0',
245
+ size: '9LG'
246
+ }
247
+ },
248
+ {
249
+ orderable: true,
250
+ price: 61.43,
251
+ productId: '701642889847M',
252
+ variationValues: {
253
+ color: 'JJ0NLD0',
254
+ size: '9SM'
255
+ }
256
+ },
257
+ {
258
+ orderable: true,
259
+ price: 61.43,
260
+ productId: '701642889830M',
261
+ variationValues: {
262
+ color: 'JJ0NLD0',
263
+ size: '9MD'
264
+ }
265
+ },
266
+ {
267
+ orderable: true,
268
+ price: 61.43,
269
+ productId: '701642889854M',
270
+ variationValues: {
271
+ color: 'JJ0NLD0',
272
+ size: '9XL'
273
+ }
274
+ }
275
+ ],
276
+ variationAttributes: [
277
+ {
278
+ id: 'color',
279
+ name: 'Colour',
280
+ values: [
281
+ {
282
+ name: 'Laurel',
283
+ orderable: true,
284
+ value: 'JJ0NLD0'
285
+ }
286
+ ]
287
+ },
288
+ {
289
+ id: 'size',
290
+ name: 'Size',
291
+ values: [
292
+ {
293
+ name: 'S',
294
+ orderable: true,
295
+ value: '9SM'
296
+ },
297
+ {
298
+ name: 'M',
299
+ orderable: true,
300
+ value: '9MD'
301
+ },
302
+ {
303
+ name: 'L',
304
+ orderable: true,
305
+ value: '9LG'
306
+ },
307
+ {
308
+ name: 'XL',
309
+ orderable: true,
310
+ value: '9XL'
311
+ }
312
+ ]
313
+ }
314
+ ],
315
+ variationValues: {
316
+ color: 'JJ0NLD0',
317
+ size: '9MD'
318
+ },
319
+ c_color: 'JJ0NLD0',
320
+ c_refinementColor: 'black',
321
+ c_size: '9MD',
322
+ c_width: 'Z'
323
+ }
324
+ ]
325
+ }
326
+
327
+ describe('UnavailableProductConfirmationModal', () => {
328
+ beforeEach(() => {
329
+ prependHandlersToServer([
330
+ {
331
+ path: '*/products',
332
+ res: () => {
333
+ return mockProducts
334
+ }
335
+ }
336
+ ])
337
+ })
338
+ test('renders without crashing', () => {
339
+ expect(() => {
340
+ renderWithProviders(<UnavailableProductConfirmationModal />)
341
+ }).not.toThrow()
342
+ })
343
+
344
+ test('opens confirmation modal when unavailable products are found', async () => {
345
+ const mockProductIds = ['701642889899M', '701642889830M']
346
+ const mockFunc = jest.fn()
347
+ const {getByRole, user} = renderWithProviders(
348
+ <UnavailableProductConfirmationModal
349
+ productIds={mockProductIds}
350
+ handleUnavailableProducts={mockFunc}
351
+ />
352
+ )
353
+
354
+ await waitFor(async () => {
355
+ const removeBtn = getByRole('button')
356
+ expect(removeBtn).toBeInTheDocument()
357
+ await user.click(removeBtn)
358
+ expect(mockFunc).toHaveBeenCalled()
359
+ expect(removeBtn).not.toBeInTheDocument()
360
+ })
361
+ })
362
+ })
package/app/constants.js CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import {defineMessage} from 'react-intl'
9
+ import {noop} from '@salesforce/retail-react-app/app/utils/utils'
9
10
 
10
11
  // Global app defaults
11
12
  export const DEFAULT_LOCALE = 'en-US'
@@ -120,3 +121,20 @@ export const SHIPPING_COUNTRY_CODES = [
120
121
 
121
122
  // Constant to Enable Active Data
122
123
  export const ACTIVE_DATA_ENABLED = false
124
+
125
+ export const REMOVE_UNAVAILABLE_CART_ITEM_DIALOG_CONFIG = {
126
+ dialogTitle: defineMessage({
127
+ defaultMessage: 'Items Unavailable',
128
+ id: 'confirmation_modal.remove_cart_item.title.items_unavailable'
129
+ }),
130
+ confirmationMessage: defineMessage({
131
+ defaultMessage:
132
+ 'Some items are no longer available online and will be removed from your cart.',
133
+ id: 'confirmation_modal.remove_cart_item.message.need_to_remove_due_to_unavailability'
134
+ }),
135
+ primaryActionLabel: defineMessage({
136
+ defaultMessage: 'Remove',
137
+ id: 'confirmation_modal.remove_cart_item.action.remove'
138
+ }),
139
+ onPrimaryAction: noop
140
+ }