-
Notifications
You must be signed in to change notification settings - Fork 212
Expand file tree
/
Copy pathuse-derived-product.js
More file actions
127 lines (117 loc) · 5.22 KB
/
use-derived-product.js
File metadata and controls
127 lines (117 loc) · 5.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
* Copyright (c) 2021, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import {useEffect, useState} from 'react'
import {useVariant} from '@salesforce/retail-react-app/app/hooks/use-variant'
import {useIntl} from 'react-intl'
import {useVariationParams} from '@salesforce/retail-react-app/app/hooks/use-variation-params'
import {useVariationAttributes} from '@salesforce/retail-react-app/app/hooks/use-variation-attributes'
import {useSelectedStore} from '@salesforce/retail-react-app/app/hooks/use-selected-store'
import {STORE_LOCATOR_IS_ENABLED} from '@salesforce/retail-react-app/app/constants'
const OUT_OF_STOCK = 'OUT_OF_STOCK'
const UNFULFILLABLE = 'UNFULFILLABLE'
const getInventoryById = (product, inventoryId) => {
if (!inventoryId || !product?.inventories) {
return null
}
return product.inventories.find((inv) => inv.id === inventoryId)
}
// TODO: This needs to be refactored.
export const useDerivedProduct = (
product,
isProductPartOfSet = false,
isProductPartOfBundle = false
) => {
const showLoading = !product
const isProductABundle = product?.type?.bundle
const stockLevel = product?.inventory?.stockLevel || 0
const stepQuantity = product?.stepQuantity || 1
const minOrderQuantity = stockLevel > 0 ? product?.minOrderQuantity || 1 : 0
const initialQuantity = product?.quantity || product?.minOrderQuantity || 1
// used for product bundles when there are multiple products
const lowestStockLevelProductName = product?.inventory?.lowestStockLevelProductName
const intl = useIntl()
const variant = useVariant(product, isProductPartOfSet, isProductPartOfBundle)
const variationParams = useVariationParams(product, isProductPartOfSet, isProductPartOfBundle)
const variationAttributes = useVariationAttributes(
product,
isProductPartOfSet,
isProductPartOfBundle
)
const [quantity, setQuantity] = useState(initialQuantity)
const {selectedStore} = useSelectedStore()
// Only enable BOPIS functionality if the feature toggle is on
const isBopisEnabled = STORE_LOCATOR_IS_ENABLED
const selectedInventoryId = isBopisEnabled ? selectedStore?.inventoryId || null : null
const selectedStoreInventory = getInventoryById(product, selectedInventoryId)
const selectedStoreStockLevel = selectedStoreInventory?.stockLevel || 0
// selectedStoreStockLevel and selectedStoreInventory are already variant specific,
// so we don't need to check for variation attributes
const isSelectedStoreOutOfStock =
!selectedStoreStockLevel ||
selectedStoreStockLevel < quantity ||
!selectedStoreInventory?.orderable
// A product is considered out of stock if the stock level is 0 or if we have all our
// variation attributes selected, but don't have a variant. We do this because the API
// will sometimes return all the variants even if they are out of stock, but for other
// products it won't.
const isOutOfStock =
!stockLevel ||
(!isProductABundle &&
!variant &&
Object.keys(variationParams).length === variationAttributes.length) ||
(!isProductABundle && variant && !variant.orderable)
const unfulfillable = stockLevel < quantity
const inventoryMessages = {
[OUT_OF_STOCK]: intl.formatMessage({
defaultMessage: 'Out of stock',
id: 'use_product.message.out_of_stock'
}),
[UNFULFILLABLE]: lowestStockLevelProductName
? intl.formatMessage(
{
defaultMessage: 'Only {stockLevel} left for {productName}!',
id: 'use_product.message.inventory_remaining_for_product'
},
{stockLevel, productName: lowestStockLevelProductName}
)
: intl.formatMessage(
{
defaultMessage: 'Only {stockLevel} left!',
id: 'use_product.message.inventory_remaining'
},
{stockLevel}
)
}
// showInventoryMessage controls if add to cart button is disabled
const showInventoryMessage = (variant || isProductABundle) && (isOutOfStock || unfulfillable)
const inventoryMessage =
(isOutOfStock && inventoryMessages[OUT_OF_STOCK]) ||
(unfulfillable && inventoryMessages[UNFULFILLABLE])
// If the `initialQuantity` changes, update the state. This typically happens
// when either the master product changes, or the inventory of the product changes
// from out-of-stock to in-stock or vice versa.
useEffect(() => {
setQuantity(initialQuantity)
}, [initialQuantity])
return {
showLoading,
showInventoryMessage,
inventoryMessage,
variationAttributes,
quantity,
minOrderQuantity,
stepQuantity,
variationParams,
setQuantity,
variant,
stockLevel,
isOutOfStock,
unfulfillable,
isSelectedStoreOutOfStock: isBopisEnabled ? isSelectedStoreOutOfStock : false,
selectedStore: isBopisEnabled ? selectedStore : null
}
}