-
Notifications
You must be signed in to change notification settings - Fork 214
Expand file tree
/
Copy pathuse-current-basket.js
More file actions
106 lines (100 loc) · 4.5 KB
/
use-current-basket.js
File metadata and controls
106 lines (100 loc) · 4.5 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
/*
* Copyright (c) 2023, 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 {useCustomerId, useCustomerBaskets} from '@salesforce/commerce-sdk-react'
import {isServer} from '@salesforce/retail-react-app/app/utils/utils'
import {isPickupShipment} from '@salesforce/retail-react-app/app/utils/shipment-utils'
import {isAddressEmpty} from '@salesforce/retail-react-app/app/utils/address-utils'
import {STORE_LOCATOR_IS_ENABLED} from '@salesforce/retail-react-app/app/constants'
import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
import {useMemo} from 'react'
import {useSFPayments} from '@salesforce/retail-react-app/app/hooks/use-sf-payments'
/**
* This hook combine some commerce-react-sdk hooks to provide more derived data for Retail App baskets
* @param id - basket id to get the current used basket among baskets returned, use first basket in the array if not defined
* @param shouldFetchProductDetail - boolean to indicate if the baskets should fetch product details based on basket items
*/
export const useCurrentBasket = ({id = ''} = {}) => {
const storeLocatorEnabled = getConfig()?.app?.storeLocatorEnabled ?? STORE_LOCATOR_IS_ENABLED
const customerId = useCustomerId()
const {confirmingBasket} = useSFPayments()
const {data: basketsData, ...restOfQuery} = useCustomerBaskets(
{parameters: {customerId}},
{
enabled: !!customerId && !isServer
}
)
// Select the current basket, prioritizing confirmingBasket, then matching id, then first non-temporary basket
// Filters out temporary baskets to prevent them from showing in the cart
const currentBasket =
confirmingBasket && !confirmingBasket.temporaryBasket
? confirmingBasket
: basketsData?.baskets?.find((basket) => basket?.basketId === id) ||
basketsData?.baskets?.find((basket) => !basket.temporaryBasket)
const memoizedDerived = useMemo(() => {
// count the number of items in each shipment and rollup total
let totalItems = 0
const shipmentIdToTotalItems =
currentBasket?.productItems?.reduce((acc, item) => {
totalItems += item.quantity
acc[item.shipmentId] = acc[item.shipmentId] || 0
acc[item.shipmentId] += item.quantity
return acc
}, {}) ?? {}
// count the number on non-empty pickup and delivery shipments
// also count the number of delivery shipments missing an address or shipping method
let totalDeliveryShipments = 0
let totalPickupShipments = 0
const pickupStoreIds = []
let isMissingShippingAddress = false
let isMissingShippingMethod = false
currentBasket?.shipments?.forEach((shipment) => {
if (shipmentIdToTotalItems[shipment.shipmentId]) {
if (storeLocatorEnabled && isPickupShipment(shipment)) {
totalPickupShipments += 1
pickupStoreIds.push(shipment.c_fromStoreId)
} else {
totalDeliveryShipments += 1
if (isAddressEmpty(shipment.shippingAddress)) {
isMissingShippingAddress = true
}
if (!shipment.shippingMethod) {
isMissingShippingMethod = true
}
}
}
})
// sorting helps with query caching
pickupStoreIds.sort()
// Calculate total shipping cost
// Use currentBasket.shippingTotal to include all costs (base _ promotions + surcharges + other fees)
const totalShippingCost = currentBasket?.shippingTotal || 0
return {
totalItems,
shipmentIdToTotalItems,
totalDeliveryShipments,
totalPickupShipments,
pickupStoreIds,
isMissingShippingAddress,
isMissingShippingMethod,
totalShippingCost
}
}, [
currentBasket?.productItems,
currentBasket?.shipments,
currentBasket?.shippingItems,
storeLocatorEnabled
])
return {
...restOfQuery,
data: currentBasket,
derivedData: {
// Only true if a non-temporary basket exists (temporary baskets are filtered out above)
hasBasket: !!currentBasket,
...memoizedDerived
}
}
}