-
Notifications
You must be signed in to change notification settings - Fork 212
Expand file tree
/
Copy pathuse-checkout-auto-select.js
More file actions
96 lines (85 loc) · 3.37 KB
/
use-checkout-auto-select.js
File metadata and controls
96 lines (85 loc) · 3.37 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
/*
* 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, useRef, useState} from 'react'
/**
* Generic hook for auto-selecting and applying saved customer data during checkout
* @param {Object} config Configuration object
* @param {number} config.currentStep - Current checkout step
* @param {number} config.targetStep - Step this auto-selection should run on
* @param {boolean} config.isCustomerRegistered - Whether customer is registered
* @param {Array} config.items - List of items to select from (addresses, payments, etc.)
* @param {Function} config.getPreferredItem - Function to find preferred item from list
* @param {Function} config.shouldSkip - Optional function returning boolean if auto-select should be skipped
* @param {Function} config.isAlreadyApplied - Function checking if item is already applied
* @param {Function} config.applyItem - Async function to apply the selected item
* @param {Function} config.onSuccess - Optional callback after successful application
* @param {Function} config.onError - Optional callback after error
* @param {boolean} config.enabled - Whether auto-selection is enabled (default: true)
* @returns {Object} { isLoading, hasExecuted, reset }
*/
export const useCheckoutAutoSelect = ({
currentStep,
targetStep,
isCustomerRegistered,
items = [],
getPreferredItem,
shouldSkip = () => false,
isAlreadyApplied = () => false,
applyItem,
onSuccess,
onError,
enabled = true
}) => {
const [isLoading, setIsLoading] = useState(false)
const hasExecutedRef = useRef(false)
const reset = () => {
hasExecutedRef.current = false
setIsLoading(false)
}
useEffect(() => {
const autoSelect = async () => {
// Early returns for conditions that prevent auto-selection
if (!enabled) return
if (currentStep !== targetStep) return
if (hasExecutedRef.current) return
if (isLoading) return
if (!isCustomerRegistered) return
if (!items || items.length === 0) return
if (shouldSkip()) return
if (isAlreadyApplied()) return
// Find the preferred item
const preferredItem = getPreferredItem(items)
if (!preferredItem) return
// Mark as executed before starting to prevent race conditions
hasExecutedRef.current = true
setIsLoading(true)
try {
// Apply the item
await applyItem(preferredItem)
// Call success callback if provided
if (onSuccess) {
await onSuccess(preferredItem)
}
} catch (error) {
// Reset on error to allow manual selection
hasExecutedRef.current = false
// Call error callback if provided
if (onError) {
onError(error)
}
} finally {
setIsLoading(false)
}
}
autoSelect()
}, [currentStep, targetStep, isCustomerRegistered, items, isLoading, enabled])
return {
isLoading,
hasExecuted: hasExecutedRef.current,
reset
}
}