@salesforce/retail-react-app 7.1.0-preview.1 → 8.0.0-dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -2
- package/app/components/_app/index.jsx +9 -7
- package/app/components/_app/index.test.js +2 -2
- package/app/components/_app-config/index.jsx +9 -3
- package/app/components/drawer-menu/drawer-menu.jsx +3 -1
- package/app/components/footer/index.jsx +3 -1
- package/app/components/header/index.jsx +3 -1
- package/app/components/header/index.test.js +2 -2
- package/app/components/island/README.md +1 -1
- package/app/components/island/index.jsx +3 -1
- package/app/components/island/index.test.js +94 -5
- package/app/components/item-variant/item-attributes.jsx +12 -3
- package/app/components/multiship/multiship-order-summary.jsx +137 -0
- package/app/components/multiship/multiship-order-summary.test.js +121 -0
- package/app/components/order-summary/index.jsx +2 -4
- package/app/components/pickup-or-delivery/index.jsx +80 -0
- package/app/components/pickup-or-delivery/index.test.jsx +182 -0
- package/app/components/product-item/index.jsx +26 -16
- package/app/components/product-item/index.test.js +29 -2
- package/app/components/product-item-list/index.jsx +10 -0
- package/app/components/product-item-list/index.test.jsx +14 -0
- package/app/components/product-view/index.jsx +9 -6
- package/app/components/product-view/index.test.js +25 -21
- package/app/components/quantity-picker/index.test.jsx +12 -12
- package/app/components/reset-password/index.test.js +1 -1
- package/app/components/shared/ui/AlertDescription/index.jsx +8 -0
- package/app/components/shared/ui/index.jsx +1 -0
- package/app/components/store-display/index.jsx +28 -4
- package/app/components/store-display/index.test.js +71 -0
- package/app/components/store-locator/form.test.jsx +16 -4
- package/app/components/store-locator/list.jsx +9 -4
- package/app/components/toggle-card/index.jsx +14 -0
- package/app/components/unavailable-product-confirmation-modal/index.jsx +19 -5
- package/app/components/unavailable-product-confirmation-modal/index.test.js +122 -1
- package/app/constants.js +20 -6
- package/app/contexts/store-locator-provider.jsx +7 -1
- package/app/contexts/store-locator-provider.test.jsx +36 -1
- package/app/hooks/use-address-form.js +155 -0
- package/app/hooks/use-address-form.test.js +501 -0
- package/app/hooks/use-auth-modal.js +2 -6
- package/app/hooks/use-current-basket.js +71 -2
- package/app/hooks/use-current-basket.test.js +37 -1
- package/app/hooks/use-dnt-notification.js +4 -4
- package/app/hooks/use-dnt-notification.test.js +5 -5
- package/app/hooks/use-item-shipment-management.js +233 -0
- package/app/hooks/use-item-shipment-management.test.js +696 -0
- package/app/hooks/use-multiship.js +589 -0
- package/app/hooks/use-multiship.test.js +776 -0
- package/app/hooks/use-pickup-shipment.js +70 -106
- package/app/hooks/use-pickup-shipment.test.js +345 -209
- package/app/hooks/use-product-address-assignment.js +280 -0
- package/app/hooks/use-product-address-assignment.test.js +414 -0
- package/app/hooks/use-product-inventory.js +100 -0
- package/app/hooks/use-product-inventory.test.js +254 -0
- package/app/hooks/use-shipment-operations.js +168 -0
- package/app/hooks/use-shipment-operations.test.js +385 -0
- package/app/hooks/use-store-locator.js +24 -2
- package/app/hooks/use-store-locator.test.jsx +109 -1
- package/app/pages/account/index.test.js +1 -1
- package/app/pages/account/profile.test.js +0 -2
- package/app/pages/cart/index.jsx +397 -157
- package/app/pages/cart/index.test.js +353 -2
- package/app/pages/cart/partials/bonus-products-title.jsx +10 -8
- package/app/pages/cart/partials/cart-secondary-button-group.test.js +1 -1
- package/app/pages/cart/partials/order-type-display.jsx +68 -0
- package/app/pages/cart/partials/order-type-display.test.js +241 -0
- package/app/pages/checkout/confirmation.jsx +79 -158
- package/app/pages/checkout/index.jsx +34 -9
- package/app/pages/checkout/index.test.js +245 -118
- package/app/pages/checkout/partials/contact-info.jsx +2 -6
- package/app/pages/checkout/partials/contact-info.test.js +93 -7
- package/app/pages/checkout/partials/payment.jsx +19 -5
- package/app/pages/checkout/partials/pickup-address.jsx +340 -70
- package/app/pages/checkout/partials/pickup-address.test.js +1075 -82
- package/app/pages/checkout/partials/product-shipping-address-card.jsx +382 -0
- package/app/pages/checkout/partials/shipment-details.jsx +209 -0
- package/app/pages/checkout/partials/shipment-details.test.js +246 -0
- package/app/pages/checkout/partials/shipping-address.jsx +156 -68
- package/app/pages/checkout/partials/shipping-address.test.js +673 -0
- package/app/pages/checkout/partials/shipping-method-options.jsx +180 -0
- package/app/pages/checkout/partials/shipping-methods.jsx +403 -0
- package/app/pages/checkout/partials/shipping-methods.test.js +472 -0
- package/app/pages/checkout/partials/shipping-multi-address.jsx +259 -0
- package/app/pages/checkout/partials/shipping-multi-address.test.js +2088 -0
- package/app/pages/checkout/partials/shipping-product-cards.jsx +101 -0
- package/app/pages/checkout/util/checkout-context.js +25 -18
- package/app/pages/login/index.jsx +2 -6
- package/app/pages/product-detail/index.jsx +96 -81
- package/app/pages/product-detail/index.test.js +103 -19
- package/app/pages/product-list/index.jsx +3 -1
- package/app/pages/product-list/partials/inventory-filter.jsx +18 -21
- package/app/pages/product-list/partials/inventory-filter.test.js +15 -17
- package/app/pages/product-list/partials/selected-refinements.jsx +3 -1
- package/app/ssr.js +1 -1
- package/app/static/translations/compiled/en-GB.json +316 -30
- package/app/static/translations/compiled/en-US.json +316 -30
- package/app/static/translations/compiled/en-XA.json +673 -75
- package/app/utils/address-utils.js +112 -0
- package/app/utils/address-utils.test.js +484 -0
- package/app/utils/product-utils.js +17 -5
- package/app/utils/product-utils.test.js +17 -8
- package/app/utils/sfdc-user-agent-utils.js +32 -0
- package/app/utils/sfdc-user-agent-utils.test.js +82 -0
- package/app/utils/shipment-utils.js +196 -0
- package/app/utils/shipment-utils.test.js +458 -0
- package/app/utils/test-utils.js +4 -4
- package/app/utils/utils.js +6 -1
- package/config/default.js +4 -1
- package/config/mocks/default.js +3 -1
- package/package.json +9 -9
- package/translations/en-GB.json +127 -10
- package/translations/en-US.json +127 -10
- package/app/pages/checkout/partials/shipping-options.jsx +0 -269
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
bundleProductItemsForPDP
|
|
29
29
|
} from '@salesforce/retail-react-app/app/mocks/product-bundle'
|
|
30
30
|
import {mockStandardProductOrderable} from '@salesforce/retail-react-app/app/mocks/standard-product'
|
|
31
|
+
import mockConfig from '@salesforce/retail-react-app/config/mocks/default'
|
|
31
32
|
|
|
32
33
|
jest.setTimeout(60000)
|
|
33
34
|
|
|
@@ -79,27 +80,34 @@ jest.mock('@salesforce/retail-react-app/app/components/recommended-products', ()
|
|
|
79
80
|
return MockedRecommendedProducts
|
|
80
81
|
})
|
|
81
82
|
|
|
83
|
+
// Mock getConfig to return test values
|
|
84
|
+
jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-config', () => ({
|
|
85
|
+
getConfig: jest.fn(() => ({
|
|
86
|
+
...mockConfig,
|
|
87
|
+
app: {
|
|
88
|
+
...mockConfig.app,
|
|
89
|
+
storeLocatorEnabled: true,
|
|
90
|
+
multishipEnabled: false
|
|
91
|
+
}
|
|
92
|
+
}))
|
|
93
|
+
}))
|
|
94
|
+
|
|
82
95
|
jest.mock('@salesforce/retail-react-app/app/constants', () => {
|
|
83
96
|
const originalModule = jest.requireActual('@salesforce/retail-react-app/app/constants')
|
|
84
97
|
return {
|
|
85
98
|
...originalModule,
|
|
86
|
-
DEFAULT_DNT_STATE: false
|
|
99
|
+
DEFAULT_DNT_STATE: false,
|
|
100
|
+
STORE_LOCATOR_IS_ENABLED: true
|
|
87
101
|
}
|
|
88
102
|
})
|
|
89
103
|
|
|
90
|
-
jest.mock('@salesforce/retail-react-app/app/
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
) : null
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
StoreLocatorModal: MockStoreLocatorModal
|
|
101
|
-
}
|
|
102
|
-
})
|
|
104
|
+
jest.mock('@salesforce/retail-react-app/app/hooks/use-store-locator', () => ({
|
|
105
|
+
useStoreLocatorModal: jest.fn(() => ({
|
|
106
|
+
isOpen: false,
|
|
107
|
+
onOpen: jest.fn(),
|
|
108
|
+
onClose: jest.fn()
|
|
109
|
+
}))
|
|
110
|
+
}))
|
|
103
111
|
|
|
104
112
|
// Mock useSelectedStore hook
|
|
105
113
|
const mockUseSelectedStore = jest.fn()
|
|
@@ -107,6 +115,14 @@ jest.mock('@salesforce/retail-react-app/app/hooks/use-selected-store', () => ({
|
|
|
107
115
|
useSelectedStore: () => mockUseSelectedStore()
|
|
108
116
|
}))
|
|
109
117
|
|
|
118
|
+
// Mock useMultiship hook
|
|
119
|
+
const mockGetShipmentForItems = jest.fn()
|
|
120
|
+
jest.mock('@salesforce/retail-react-app/app/hooks/use-multiship', () => ({
|
|
121
|
+
useMultiship: () => ({
|
|
122
|
+
getShipmentIdForItems: mockGetShipmentForItems
|
|
123
|
+
})
|
|
124
|
+
}))
|
|
125
|
+
|
|
110
126
|
const MockedComponent = () => {
|
|
111
127
|
return (
|
|
112
128
|
<Switch>
|
|
@@ -128,6 +144,7 @@ beforeEach(() => {
|
|
|
128
144
|
error: null,
|
|
129
145
|
hasSelectedStore: false
|
|
130
146
|
}))
|
|
147
|
+
mockGetShipmentForItems.mockResolvedValue('me')
|
|
131
148
|
|
|
132
149
|
global.server.use(
|
|
133
150
|
// By default, the page will be rendered with a product set
|
|
@@ -330,6 +347,74 @@ describe('product set', () => {
|
|
|
330
347
|
expect(heroImage.getAttribute('loading')).toBe('lazy')
|
|
331
348
|
})
|
|
332
349
|
})
|
|
350
|
+
|
|
351
|
+
test('pickup in store radio is enabled when all child products have inventory in selected store', async () => {
|
|
352
|
+
const inventoryId = 'inventory_m_store_store1'
|
|
353
|
+
const storeId = 'store-123'
|
|
354
|
+
|
|
355
|
+
// Mock useSelectedStore to return a store with inventoryId
|
|
356
|
+
mockUseSelectedStore.mockImplementation(() => ({
|
|
357
|
+
selectedStore: {
|
|
358
|
+
id: storeId,
|
|
359
|
+
name: 'Test Store',
|
|
360
|
+
inventoryId: inventoryId
|
|
361
|
+
},
|
|
362
|
+
isLoading: false,
|
|
363
|
+
error: null,
|
|
364
|
+
hasSelectedStore: true
|
|
365
|
+
}))
|
|
366
|
+
|
|
367
|
+
// Create product set with parent and child products that all have inventory in the selected store
|
|
368
|
+
const productSetWithInventory = {
|
|
369
|
+
...mockedProductSet,
|
|
370
|
+
setProducts: mockedProductSet.setProducts.map((childProduct) => ({
|
|
371
|
+
...childProduct,
|
|
372
|
+
inventories: [
|
|
373
|
+
{
|
|
374
|
+
id: inventoryId,
|
|
375
|
+
orderable: true,
|
|
376
|
+
ats: 10,
|
|
377
|
+
stockLevel: 10
|
|
378
|
+
}
|
|
379
|
+
]
|
|
380
|
+
}))
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
global.server.use(
|
|
384
|
+
rest.get('*/products/:productId', (req, res, ctx) => {
|
|
385
|
+
return res(ctx.json(productSetWithInventory))
|
|
386
|
+
})
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
renderWithProviders(<MockedComponent />)
|
|
390
|
+
|
|
391
|
+
await waitFor(() => {
|
|
392
|
+
expect(screen.getByRole('link', {name: /mens/i})).toBeInTheDocument()
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
// Wait for child products to load
|
|
396
|
+
const childProducts = await screen.findAllByTestId('child-product')
|
|
397
|
+
expect(childProducts).toHaveLength(3) // 3 child products in the winter look set
|
|
398
|
+
|
|
399
|
+
// Check that each child product has pickup in store radio enabled
|
|
400
|
+
for (const childProduct of childProducts) {
|
|
401
|
+
await waitFor(() => {
|
|
402
|
+
const pickupRadio = within(childProduct).getByRole('radio', {
|
|
403
|
+
name: /pick up in store/i
|
|
404
|
+
})
|
|
405
|
+
expect(pickupRadio).toBeEnabled()
|
|
406
|
+
})
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Check that the parent product pickup in store radio is also enabled
|
|
410
|
+
const allPickupRadios = await screen.findAllByRole('radio', {name: /pick up in store/i})
|
|
411
|
+
// Should have 4 pickup radios total: 1 parent + 3 children
|
|
412
|
+
expect(allPickupRadios).toHaveLength(4)
|
|
413
|
+
|
|
414
|
+
// The first pickup radio should be the parent product (rendered before child products)
|
|
415
|
+
const parentPickupRadio = allPickupRadios[0]
|
|
416
|
+
expect(parentPickupRadio).toBeEnabled()
|
|
417
|
+
})
|
|
333
418
|
})
|
|
334
419
|
|
|
335
420
|
describe('Recommended Products', () => {
|
|
@@ -657,8 +742,6 @@ describe('Delivery Options Restrictions', () => {
|
|
|
657
742
|
hasSelectedStore: true
|
|
658
743
|
}))
|
|
659
744
|
|
|
660
|
-
// Track if updatePickupShipment was called
|
|
661
|
-
let updatePickupShipmentCalled = false
|
|
662
745
|
let shipmentUpdateRequest = null
|
|
663
746
|
|
|
664
747
|
// Mock the product to be a simple master product with inventory
|
|
@@ -684,7 +767,6 @@ describe('Delivery Options Restrictions', () => {
|
|
|
684
767
|
}),
|
|
685
768
|
// Mock the shipment update call that updatePickupShipment makes
|
|
686
769
|
rest.patch('*/baskets/:basketId/shipments/:shipmentId', async (req, res, ctx) => {
|
|
687
|
-
updatePickupShipmentCalled = true
|
|
688
770
|
shipmentUpdateRequest = await req.json()
|
|
689
771
|
|
|
690
772
|
// Verify the correct parameters are passed to updatePickupShipment
|
|
@@ -988,7 +1070,8 @@ describe('standard product', () => {
|
|
|
988
1070
|
{
|
|
989
1071
|
productId: mockStandardProductOrderable.id,
|
|
990
1072
|
price: mockStandardProductOrderable.price,
|
|
991
|
-
quantity: 1
|
|
1073
|
+
quantity: 1,
|
|
1074
|
+
shipmentId: 'me'
|
|
992
1075
|
}
|
|
993
1076
|
])
|
|
994
1077
|
})
|
|
@@ -1018,7 +1101,8 @@ describe('standard product', () => {
|
|
|
1018
1101
|
{
|
|
1019
1102
|
productId: mockStandardProductOrderable.id,
|
|
1020
1103
|
price: mockStandardProductOrderable.price,
|
|
1021
|
-
quantity: 3
|
|
1104
|
+
quantity: 3,
|
|
1105
|
+
shipmentId: 'me'
|
|
1022
1106
|
}
|
|
1023
1107
|
])
|
|
1024
1108
|
})
|
|
@@ -94,6 +94,7 @@ import {
|
|
|
94
94
|
PRODUCT_LIST_SELECTABLE_ATTRIBUTE_ID,
|
|
95
95
|
STORE_LOCATOR_IS_ENABLED
|
|
96
96
|
} from '@salesforce/retail-react-app/app/constants'
|
|
97
|
+
import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
|
|
97
98
|
import useNavigation from '@salesforce/retail-react-app/app/hooks/use-navigation'
|
|
98
99
|
import LoadingSpinner from '@salesforce/retail-react-app/app/components/loading-spinner'
|
|
99
100
|
import {useWishList} from '@salesforce/retail-react-app/app/hooks/use-wish-list'
|
|
@@ -126,6 +127,7 @@ const ProductList = (props) => {
|
|
|
126
127
|
const {res} = useServerContext()
|
|
127
128
|
const customerId = useCustomerId()
|
|
128
129
|
const [searchParams, {stringify: stringifySearchParams}] = useSearchParams()
|
|
130
|
+
const storeLocatorEnabled = getConfig()?.app?.storeLocatorEnabled ?? STORE_LOCATOR_IS_ENABLED
|
|
129
131
|
|
|
130
132
|
/**************** Page State ****************/
|
|
131
133
|
const [filtersLoading, setFiltersLoading] = useState(false)
|
|
@@ -400,7 +402,7 @@ const ProductList = (props) => {
|
|
|
400
402
|
|
|
401
403
|
// Helper function to create StoreInventoryFilter component
|
|
402
404
|
const createStoreInventoryFilter = () => {
|
|
403
|
-
if (!
|
|
405
|
+
if (!storeLocatorEnabled) return null
|
|
404
406
|
return (
|
|
405
407
|
<StoreInventoryFilter
|
|
406
408
|
key="storeInventoryFilter"
|
|
@@ -5,23 +5,18 @@
|
|
|
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
|
|
|
8
|
-
import React, {useEffect} from 'react'
|
|
8
|
+
import React, {useEffect, useRef} from 'react'
|
|
9
9
|
import {useIntl, FormattedMessage} from 'react-intl'
|
|
10
10
|
import PropTypes from 'prop-types'
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
Checkbox,
|
|
14
|
-
Stack,
|
|
15
|
-
Text,
|
|
16
|
-
useDisclosure
|
|
17
|
-
} from '@salesforce/retail-react-app/app/components/shared/ui'
|
|
18
|
-
import {StoreLocatorModal} from '@salesforce/retail-react-app/app/components/store-locator'
|
|
11
|
+
import {Heading, Checkbox, Stack, Text} from '@salesforce/retail-react-app/app/components/shared/ui'
|
|
12
|
+
import {useStoreLocatorModal} from '@salesforce/retail-react-app/app/hooks/use-store-locator'
|
|
19
13
|
import {useSelectedStore} from '@salesforce/retail-react-app/app/hooks/use-selected-store'
|
|
20
14
|
|
|
21
15
|
const StoreInventoryFilter = ({toggleFilter, selectedFilters}) => {
|
|
22
|
-
const {isOpen, onOpen
|
|
16
|
+
const {isOpen, onOpen} = useStoreLocatorModal()
|
|
23
17
|
const {formatMessage} = useIntl()
|
|
24
18
|
const {selectedStore} = useSelectedStore()
|
|
19
|
+
const storeLocatorModalRef = useRef(false)
|
|
25
20
|
|
|
26
21
|
const isChecked = selectedFilters?.ilids !== undefined
|
|
27
22
|
|
|
@@ -32,10 +27,22 @@ const StoreInventoryFilter = ({toggleFilter, selectedFilters}) => {
|
|
|
32
27
|
}
|
|
33
28
|
}, [selectedStore])
|
|
34
29
|
|
|
30
|
+
// Handle when modal closes after being opened from this component
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
// If modal was opened from here and is now closed, apply filter if store is selected
|
|
33
|
+
if (storeLocatorModalRef.current && !isOpen) {
|
|
34
|
+
storeLocatorModalRef.current = false
|
|
35
|
+
if (selectedStore?.inventoryId) {
|
|
36
|
+
toggleFilter({value: selectedStore.inventoryId}, 'ilids', false, false)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}, [isOpen, selectedStore, toggleFilter])
|
|
40
|
+
|
|
35
41
|
const handleCheckboxChange = (e) => {
|
|
36
42
|
// If no store is selected or no inventoryId, open store locator
|
|
37
43
|
if (!selectedStore?.inventoryId) {
|
|
38
44
|
e.preventDefault()
|
|
45
|
+
storeLocatorModalRef.current = true
|
|
39
46
|
onOpen()
|
|
40
47
|
return
|
|
41
48
|
}
|
|
@@ -49,18 +56,10 @@ const StoreInventoryFilter = ({toggleFilter, selectedFilters}) => {
|
|
|
49
56
|
const handleStoreNameClick = (e) => {
|
|
50
57
|
e.stopPropagation()
|
|
51
58
|
e.preventDefault()
|
|
59
|
+
storeLocatorModalRef.current = true
|
|
52
60
|
onOpen()
|
|
53
61
|
}
|
|
54
62
|
|
|
55
|
-
const handleStoreLocatorClose = () => {
|
|
56
|
-
// Apply the filter when a store is selected from the locator and the modal closes
|
|
57
|
-
if (selectedStore?.inventoryId) {
|
|
58
|
-
toggleFilter({value: selectedStore.inventoryId}, 'ilids', false, false)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
onClose()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
63
|
const storeLinkText =
|
|
65
64
|
selectedStore?.name ||
|
|
66
65
|
formatMessage({
|
|
@@ -133,8 +132,6 @@ const StoreInventoryFilter = ({toggleFilter, selectedFilters}) => {
|
|
|
133
132
|
/>
|
|
134
133
|
</Checkbox>
|
|
135
134
|
</Stack>
|
|
136
|
-
|
|
137
|
-
<StoreLocatorModal isOpen={isOpen} onClose={handleStoreLocatorClose} />
|
|
138
135
|
</>
|
|
139
136
|
)
|
|
140
137
|
}
|
|
@@ -11,25 +11,15 @@ import userEvent from '@testing-library/user-event'
|
|
|
11
11
|
import {renderWithProviders} from '@salesforce/retail-react-app/app/utils/test-utils'
|
|
12
12
|
import StoreInventoryFilter from '@salesforce/retail-react-app/app/pages/product-list/partials/inventory-filter'
|
|
13
13
|
import {useSelectedStore} from '@salesforce/retail-react-app/app/hooks/use-selected-store'
|
|
14
|
+
import {useStoreLocatorModal} from '@salesforce/retail-react-app/app/hooks/use-store-locator'
|
|
14
15
|
|
|
15
16
|
jest.mock('@salesforce/retail-react-app/app/hooks/use-selected-store', () => ({
|
|
16
17
|
useSelectedStore: jest.fn()
|
|
17
18
|
}))
|
|
18
19
|
|
|
19
|
-
jest.mock('@salesforce/retail-react-app/app/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return isOpen ? (
|
|
23
|
-
<div data-testid="store-locator-modal">
|
|
24
|
-
<button onClick={onClose}>Close Modal</button>
|
|
25
|
-
</div>
|
|
26
|
-
) : null
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
StoreLocatorModal: MockStoreLocatorModal
|
|
31
|
-
}
|
|
32
|
-
})
|
|
20
|
+
jest.mock('@salesforce/retail-react-app/app/hooks/use-store-locator', () => ({
|
|
21
|
+
useStoreLocatorModal: jest.fn()
|
|
22
|
+
}))
|
|
33
23
|
|
|
34
24
|
const mockToggleFilter = jest.fn()
|
|
35
25
|
|
|
@@ -50,6 +40,9 @@ const mockStoreData = {
|
|
|
50
40
|
}
|
|
51
41
|
|
|
52
42
|
describe('StoreInventoryFilter', () => {
|
|
43
|
+
const mockOnOpen = jest.fn()
|
|
44
|
+
const mockOnClose = jest.fn()
|
|
45
|
+
|
|
53
46
|
beforeEach(() => {
|
|
54
47
|
jest.clearAllMocks()
|
|
55
48
|
localStorage.clear()
|
|
@@ -59,6 +52,11 @@ describe('StoreInventoryFilter', () => {
|
|
|
59
52
|
error: null,
|
|
60
53
|
hasSelectedStore: false
|
|
61
54
|
})
|
|
55
|
+
useStoreLocatorModal.mockReturnValue({
|
|
56
|
+
isOpen: false,
|
|
57
|
+
onOpen: mockOnOpen,
|
|
58
|
+
onClose: mockOnClose
|
|
59
|
+
})
|
|
62
60
|
})
|
|
63
61
|
|
|
64
62
|
test('renders component with default state', async () => {
|
|
@@ -103,7 +101,7 @@ describe('StoreInventoryFilter', () => {
|
|
|
103
101
|
const checkbox = screen.getByRole('checkbox')
|
|
104
102
|
await user.click(checkbox)
|
|
105
103
|
|
|
106
|
-
expect(
|
|
104
|
+
expect(mockOnOpen).toHaveBeenCalled()
|
|
107
105
|
})
|
|
108
106
|
|
|
109
107
|
test('opens store locator modal when store name is clicked', async () => {
|
|
@@ -123,7 +121,7 @@ describe('StoreInventoryFilter', () => {
|
|
|
123
121
|
|
|
124
122
|
await user.click(screen.getByText('Test Store Location'))
|
|
125
123
|
|
|
126
|
-
expect(
|
|
124
|
+
expect(mockOnOpen).toHaveBeenCalled()
|
|
127
125
|
})
|
|
128
126
|
|
|
129
127
|
test('calls toggleFilter when checkbox is changed with selected store', async () => {
|
|
@@ -201,7 +199,7 @@ describe('StoreInventoryFilter', () => {
|
|
|
201
199
|
expect(mockToggleFilter).toHaveBeenCalledWith({value: 'inv-456'}, 'ilids', false, false)
|
|
202
200
|
|
|
203
201
|
// Ensure no modal was opened
|
|
204
|
-
expect(
|
|
202
|
+
expect(mockOnOpen).not.toHaveBeenCalled()
|
|
205
203
|
})
|
|
206
204
|
|
|
207
205
|
test('applies filter when selected store changes and checkbox is checked', async () => {
|
|
@@ -13,10 +13,12 @@ import {CloseIcon} from '@salesforce/retail-react-app/app/components/icons'
|
|
|
13
13
|
import {REMOVE_FILTER} from '@salesforce/retail-react-app/app/pages/product-list/partials/refinements-utils'
|
|
14
14
|
import {useSelectedStore} from '@salesforce/retail-react-app/app/hooks/use-selected-store'
|
|
15
15
|
import {STORE_LOCATOR_IS_ENABLED} from '@salesforce/retail-react-app/app/constants'
|
|
16
|
+
import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
|
|
16
17
|
|
|
17
18
|
const SelectedRefinements = ({toggleFilter, selectedFilterValues, filters, handleReset}) => {
|
|
18
19
|
const {formatMessage} = useIntl()
|
|
19
20
|
const {selectedStore} = useSelectedStore()
|
|
21
|
+
const storeLocatorEnabled = getConfig()?.app?.storeLocatorEnabled ?? STORE_LOCATOR_IS_ENABLED
|
|
20
22
|
const priceFilterValues = filters?.find((filter) => filter.attributeId === 'price')
|
|
21
23
|
let selectedFilters = []
|
|
22
24
|
for (const key in selectedFilterValues) {
|
|
@@ -28,7 +30,7 @@ const SelectedRefinements = ({toggleFilter, selectedFilterValues, filters, handl
|
|
|
28
30
|
uiLabel =
|
|
29
31
|
priceFilterValues?.values?.find((priceFilter) => priceFilter.value === filter)
|
|
30
32
|
?.label || filter
|
|
31
|
-
} else if (key === 'ilids' &&
|
|
33
|
+
} else if (key === 'ilids' && storeLocatorEnabled) {
|
|
32
34
|
// Fallback text for in stock selected filter
|
|
33
35
|
uiLabel = formatMessage({
|
|
34
36
|
id: 'selected_refinements.filter.in_stock',
|
package/app/ssr.js
CHANGED
|
@@ -329,7 +329,7 @@ const {handler} = runtime.createHandler(options, (app) => {
|
|
|
329
329
|
)
|
|
330
330
|
|
|
331
331
|
// Handle the redirect from SLAS as to avoid error
|
|
332
|
-
app.get('/callback
|
|
332
|
+
app.get('/callback', (req, res) => {
|
|
333
333
|
// This endpoint does nothing and is not expected to change
|
|
334
334
|
// Thus we cache it for a year to maximize performance
|
|
335
335
|
res.set('Cache-Control', `max-age=31536000`)
|