-
Notifications
You must be signed in to change notification settings - Fork 212
Expand file tree
/
Copy pathcheckout-context.js
More file actions
139 lines (122 loc) · 4.79 KB
/
checkout-context.js
File metadata and controls
139 lines (122 loc) · 4.79 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
128
129
130
131
132
133
134
135
136
137
138
139
/*
* Copyright (c) 2023, Salesforce, 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 React, {useEffect, useState} from 'react'
import PropTypes from 'prop-types'
import useEinstein from '@salesforce/retail-react-app/app/hooks/use-einstein'
import {useCurrentCustomer} from '@salesforce/retail-react-app/app/hooks/use-current-customer'
import {useCurrentBasket} from '@salesforce/retail-react-app/app/hooks/use-current-basket'
import {isPickupShipment} from '@salesforce/retail-react-app/app/utils/shipment-utils'
const CheckoutContext = React.createContext()
export const CheckoutProvider = ({children}) => {
const {data: customer} = useCurrentCustomer()
const {data: basket} = useCurrentBasket()
const einstein = useEinstein()
const [step, setStep] = useState()
const [contactPhone, setContactPhone] = useState('')
const CHECKOUT_STEPS_LIST = [
'CONTACT_INFO',
'PICKUP_ADDRESS',
'SHIPPING_ADDRESS',
'SHIPPING_OPTIONS',
'PAYMENT',
'REVIEW_ORDER'
]
const STEPS = CHECKOUT_STEPS_LIST.reduce((acc, step, idx) => ({...acc, [step]: idx}), {})
const getCheckoutStepName = (step) => CHECKOUT_STEPS_LIST[step]
useEffect(() => {
if (!customer || !basket) {
return
}
let step = STEPS.REVIEW_ORDER
const shipments = basket?.shipments || []
const productItems = basket?.productItems || []
const shipmentsWithItems = shipments.filter((s) =>
productItems.some((i) => i.shipmentId === s.shipmentId)
)
const hasDeliveryShipments = shipmentsWithItems.some((s) => !isPickupShipment(s))
const anyDeliveryMissingAddress = shipmentsWithItems.some(
(s) => !isPickupShipment(s) && !s?.shippingAddress?.address1
)
const anyDeliveryMissingMethod = shipmentsWithItems.some(
(s) => !isPickupShipment(s) && !s?.shippingMethod
)
if (customer.isGuest && !basket.customerInfo?.email) {
step = STEPS.CONTACT_INFO
} else if (anyDeliveryMissingAddress) {
// Mixed or delivery-only: prioritize collecting delivery address first
step = STEPS.SHIPPING_ADDRESS
} else if (!hasDeliveryShipments && !shipmentsWithItems[0]?.shippingAddress?.address1) {
// Pickup-only and we haven't set the pickup address details yet
step = STEPS.PICKUP_ADDRESS
} else if (anyDeliveryMissingMethod) {
// Delivery shipments exist and need a shipping method
step = STEPS.SHIPPING_OPTIONS
} else if (!basket.paymentInstruments || !basket.billingAddress) {
step = STEPS.PAYMENT
}
setStep(step)
}, [
customer?.isGuest,
basket?.customerInfo?.email,
basket?.shipments,
basket?.paymentInstruments,
basket?.billingAddress
])
/**************** Einstein ****************/
// Run this once when checkout begins
useEffect(() => {
if (basket?.productItems) {
einstein.sendBeginCheckout(basket, {
checkoutType: 'one-click'
})
}
}, [])
// Run this every time checkout steps change
useEffect(() => {
if (step != undefined) {
einstein.sendCheckoutStep(getCheckoutStepName(step), step, basket, {
checkoutType: 'one-click'
})
}
}, [step])
const goToNextStep = () => {
// Check if current step is CONTACT_INFO
if (step === STEPS.CONTACT_INFO) {
// Determine if it's a pickup order - only if BOPIS is enabled
const shipments = basket?.shipments || []
const productItems = basket?.productItems || []
const shipmentsWithItems = shipments.filter((s) =>
productItems.some((i) => i.shipmentId === s.shipmentId)
)
const hasDeliveryShipments = shipmentsWithItems.some((s) => !isPickupShipment(s))
// Skip to appropriate next step; when mixed, go to SHIPPING_ADDRESS
setStep(hasDeliveryShipments ? STEPS.SHIPPING_ADDRESS : STEPS.PAYMENT)
} else {
setStep(step + 1)
}
}
const goToStep = (step) => setStep(step)
const value = {
step,
STEPS,
goToNextStep,
goToStep,
contactPhone,
setContactPhone
}
return <CheckoutContext.Provider value={value}>{children}</CheckoutContext.Provider>
}
CheckoutProvider.propTypes = {
children: PropTypes.any
}
/**
* A hook for managing checkout state and actions
* @returns {Object} Checkout data and actions
*/
export const useCheckout = () => {
return React.useContext(CheckoutContext)
}