@tagadapay/plugin-sdk 3.1.0 → 3.1.2
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/dist/external-tracker.js +1 -1
- package/dist/external-tracker.min.js +1 -1
- package/dist/v2/react/components/ApplePayButton.js +20 -4
- package/dist/v2/react/hooks/useApplePay.d.ts +16 -0
- package/dist/v2/react/hooks/useApplePay.js +247 -0
- package/dist/v2/react/hooks/usePaymentQuery.js +23 -20
- package/dist/v2/react/index.d.ts +2 -0
- package/dist/v2/react/index.js +1 -0
- package/package.json +1 -1
package/dist/external-tracker.js
CHANGED
|
@@ -9,6 +9,7 @@ import { OrdersResource } from '../../core/resources/orders';
|
|
|
9
9
|
import { useExpressPaymentMethods } from '../hooks/useExpressPaymentMethods';
|
|
10
10
|
import { getGlobalApiClient } from '../hooks/useApiQuery';
|
|
11
11
|
import { getBasisTheoryApiKey } from '../../../react/config/payment';
|
|
12
|
+
import { minorUnitsToMajorUnits, getCurrencyInfo } from '../../../react/utils/money';
|
|
12
13
|
export const ApplePayButton = ({ className = '', disabled = false, onSuccess, onError, onCancel, storeName, currencyCode = 'USD', variant = 'default', size = 'lg', checkout, }) => {
|
|
13
14
|
const { applePayPaymentMethod, shippingMethods, lineItems, handleAddExpressId, updateCheckoutSessionValues, updateCustomerEmail, reComputeOrderSummary, setError: setContextError, } = useExpressPaymentMethods();
|
|
14
15
|
const [processingPayment, setProcessingPayment] = useState(false);
|
|
@@ -66,6 +67,20 @@ export const ApplePayButton = ({ className = '', disabled = false, onSuccess, on
|
|
|
66
67
|
};
|
|
67
68
|
checkApplePayAvailability();
|
|
68
69
|
}, [applePayPaymentMethod, handleAddExpressId]);
|
|
70
|
+
// Helper to convert minor units to currency string for Apple Pay
|
|
71
|
+
// Uses SDK's minorUnitsToMajorUnits which properly handles different currency decimal places
|
|
72
|
+
const minorUnitsToCurrencyString = useCallback((amountMinor, currency) => {
|
|
73
|
+
if (!amountMinor || !currency)
|
|
74
|
+
return '0.00';
|
|
75
|
+
const currencyInfo = getCurrencyInfo(currency);
|
|
76
|
+
if (!currencyInfo) {
|
|
77
|
+
// Fallback to simple division if currency info not found
|
|
78
|
+
console.warn(`Currency info not found for ${currency}, using fallback`);
|
|
79
|
+
return (amountMinor / 100).toFixed(2);
|
|
80
|
+
}
|
|
81
|
+
const majorUnits = minorUnitsToMajorUnits(amountMinor, currency);
|
|
82
|
+
return majorUnits.toFixed(currencyInfo.ISOdigits);
|
|
83
|
+
}, []);
|
|
69
84
|
// Convert Apple Pay contact to internal Address format
|
|
70
85
|
const applePayContactToAddress = useCallback((contact) => {
|
|
71
86
|
return {
|
|
@@ -218,13 +233,13 @@ export const ApplePayButton = ({ className = '', disabled = false, onSuccess, on
|
|
|
218
233
|
return;
|
|
219
234
|
}
|
|
220
235
|
const paymentRequest = {
|
|
221
|
-
countryCode: 'US',
|
|
222
|
-
currencyCode:
|
|
236
|
+
countryCode: applePayPaymentMethod?.metadata?.country || 'US',
|
|
237
|
+
currencyCode: checkout.summary.currency,
|
|
223
238
|
supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
|
|
224
239
|
merchantCapabilities: ['supports3DS'],
|
|
225
240
|
total: {
|
|
226
241
|
label: storeName || checkout.checkoutSession.store?.name || 'Total',
|
|
227
|
-
amount: (checkout.summary.totalAdjustedAmount
|
|
242
|
+
amount: minorUnitsToCurrencyString(checkout.summary.totalAdjustedAmount, checkout.summary.currency),
|
|
228
243
|
type: 'final',
|
|
229
244
|
},
|
|
230
245
|
lineItems: lineItems.map((item) => ({
|
|
@@ -359,7 +374,6 @@ export const ApplePayButton = ({ className = '', disabled = false, onSuccess, on
|
|
|
359
374
|
isApplePayAvailable,
|
|
360
375
|
processingPayment,
|
|
361
376
|
checkout,
|
|
362
|
-
currencyCode,
|
|
363
377
|
storeName,
|
|
364
378
|
lineItems,
|
|
365
379
|
shippingMethods,
|
|
@@ -371,6 +385,8 @@ export const ApplePayButton = ({ className = '', disabled = false, onSuccess, on
|
|
|
371
385
|
onCancel,
|
|
372
386
|
onError,
|
|
373
387
|
setContextError,
|
|
388
|
+
minorUnitsToCurrencyString,
|
|
389
|
+
applePayPaymentMethod,
|
|
374
390
|
]);
|
|
375
391
|
// Button size classes
|
|
376
392
|
const sizeClasses = {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apple Pay Hook for v2 Architecture
|
|
3
|
+
* Handles Apple Pay payment flow with Basis Theory integration
|
|
4
|
+
*/
|
|
5
|
+
export interface UseApplePayOptions {
|
|
6
|
+
onSuccess?: (result: any) => void;
|
|
7
|
+
onError?: (error: string) => void;
|
|
8
|
+
onCancel?: () => void;
|
|
9
|
+
}
|
|
10
|
+
export interface UseApplePayResult {
|
|
11
|
+
handleApplePayClick: () => void;
|
|
12
|
+
processingPayment: boolean;
|
|
13
|
+
applePayError: string | null;
|
|
14
|
+
isAvailable: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function useApplePay(options?: UseApplePayOptions): UseApplePayResult;
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apple Pay Hook for v2 Architecture
|
|
3
|
+
* Handles Apple Pay payment flow with Basis Theory integration
|
|
4
|
+
*/
|
|
5
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
6
|
+
import { getBasisTheoryApiKey } from '../../../react/config/payment';
|
|
7
|
+
import { minorUnitsToMajorUnits, getCurrencyInfo } from '../../../react/utils/money';
|
|
8
|
+
import { useCheckoutQuery } from './useCheckoutQuery';
|
|
9
|
+
import { usePaymentQuery } from './usePaymentQuery';
|
|
10
|
+
import { PaymentsResource } from '../../core/resources/payments';
|
|
11
|
+
import { OrdersResource } from '../../core/resources/orders';
|
|
12
|
+
import { getGlobalApiClient } from './useApiQuery';
|
|
13
|
+
export function useApplePay(options = {}) {
|
|
14
|
+
const [processingPayment, setProcessingPayment] = useState(false);
|
|
15
|
+
const [error, setError] = useState(null);
|
|
16
|
+
const [isAvailable, setIsAvailable] = useState(false);
|
|
17
|
+
const { checkout } = useCheckoutQuery();
|
|
18
|
+
const { createApplePayPaymentInstrument } = usePaymentQuery();
|
|
19
|
+
const checkoutSessionId = checkout?.checkoutSession?.id;
|
|
20
|
+
const store = checkout?.checkoutSession?.store;
|
|
21
|
+
const summary = checkout?.summary;
|
|
22
|
+
const basistheoryPublicKey = getBasisTheoryApiKey();
|
|
23
|
+
// Create SDK resource clients
|
|
24
|
+
const paymentsResource = new PaymentsResource(getGlobalApiClient());
|
|
25
|
+
const ordersResource = new OrdersResource(getGlobalApiClient());
|
|
26
|
+
// Helper to convert minor units to currency string for Apple Pay
|
|
27
|
+
const minorUnitsToCurrencyString = useCallback((amountMinor, currency) => {
|
|
28
|
+
if (!amountMinor || !currency)
|
|
29
|
+
return '0.00';
|
|
30
|
+
const currencyInfo = getCurrencyInfo(currency);
|
|
31
|
+
if (!currencyInfo) {
|
|
32
|
+
console.warn(`Currency info not found for ${currency}, using fallback`);
|
|
33
|
+
return (amountMinor / 100).toFixed(2);
|
|
34
|
+
}
|
|
35
|
+
const majorUnits = minorUnitsToMajorUnits(amountMinor, currency);
|
|
36
|
+
return majorUnits.toFixed(currencyInfo.ISOdigits);
|
|
37
|
+
}, []);
|
|
38
|
+
// Check Apple Pay availability on mount
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const checkApplePayAvailability = () => {
|
|
41
|
+
if (typeof window === 'undefined' || !window.ApplePaySession) {
|
|
42
|
+
setIsAvailable(false);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const canMakePayments = window.ApplePaySession.canMakePayments();
|
|
47
|
+
setIsAvailable(canMakePayments);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error('Error checking Apple Pay availability:', error);
|
|
51
|
+
setIsAvailable(false);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
checkApplePayAvailability();
|
|
55
|
+
}, []);
|
|
56
|
+
// Validate merchant with Basis Theory
|
|
57
|
+
const validateMerchant = useCallback(async () => {
|
|
58
|
+
try {
|
|
59
|
+
const response = await fetch('https://api.basistheory.com/apple-pay/session', {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
'BT-API-KEY': basistheoryPublicKey,
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify({
|
|
66
|
+
display_name: store?.name || 'Store',
|
|
67
|
+
domain: window.location.host,
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
72
|
+
}
|
|
73
|
+
return response.json();
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.error('Merchant validation failed:', err);
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
}, [basistheoryPublicKey, store?.name]);
|
|
80
|
+
// Tokenize Apple Pay payment with Basis Theory
|
|
81
|
+
const tokenizeApplePay = useCallback(async (event) => {
|
|
82
|
+
try {
|
|
83
|
+
const response = await fetch('https://api.basistheory.com/apple-pay', {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
headers: {
|
|
86
|
+
'Content-Type': 'application/json',
|
|
87
|
+
'BT-API-KEY': basistheoryPublicKey,
|
|
88
|
+
},
|
|
89
|
+
body: JSON.stringify({
|
|
90
|
+
apple_payment_data: event.payment.token,
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
setError('Payment Failed');
|
|
95
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
96
|
+
}
|
|
97
|
+
const result = await response.json();
|
|
98
|
+
return result.apple_pay; // Basis Theory returns the Apple Pay token in the apple_pay field
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
console.error('Tokenization failed:', error);
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}, [basistheoryPublicKey]);
|
|
105
|
+
// Charge payment using SDK methods
|
|
106
|
+
const chargePayment = useCallback(async (applePayToken) => {
|
|
107
|
+
if (!checkoutSessionId) {
|
|
108
|
+
throw new Error('Checkout session ID not available');
|
|
109
|
+
}
|
|
110
|
+
setProcessingPayment(true);
|
|
111
|
+
try {
|
|
112
|
+
// 1. Tokenize with Basis Theory (already done - we have applePayToken)
|
|
113
|
+
// 2. Create payment instrument from the tokenized Apple Pay payment
|
|
114
|
+
const paymentInstrumentData = {
|
|
115
|
+
type: 'apple_pay',
|
|
116
|
+
token: applePayToken.id,
|
|
117
|
+
dpanType: applePayToken.type,
|
|
118
|
+
card: {
|
|
119
|
+
bin: applePayToken.card.bin,
|
|
120
|
+
last4: applePayToken.card.last4,
|
|
121
|
+
expirationMonth: applePayToken.card.expiration_month,
|
|
122
|
+
expirationYear: applePayToken.card.expiration_year,
|
|
123
|
+
brand: applePayToken.card.brand,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
const paymentInstrument = await paymentsResource.createPaymentInstrument(paymentInstrumentData);
|
|
127
|
+
if (!paymentInstrument?.id) {
|
|
128
|
+
throw new Error('Failed to create payment instrument');
|
|
129
|
+
}
|
|
130
|
+
// 3. Create order from checkout session
|
|
131
|
+
const orderResponse = await ordersResource.createOrder(checkoutSessionId);
|
|
132
|
+
if (!orderResponse?.success || !orderResponse?.order?.id) {
|
|
133
|
+
throw new Error('Failed to create order');
|
|
134
|
+
}
|
|
135
|
+
// 4. Process payment
|
|
136
|
+
const paymentResult = await paymentsResource.processPaymentDirect(checkoutSessionId, paymentInstrument.id, undefined, {
|
|
137
|
+
initiatedBy: 'customer',
|
|
138
|
+
source: 'checkout',
|
|
139
|
+
});
|
|
140
|
+
if (options.onSuccess) {
|
|
141
|
+
options.onSuccess(paymentResult);
|
|
142
|
+
}
|
|
143
|
+
return paymentResult;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
console.error('Payment failed:', error);
|
|
147
|
+
const errorMessage = error instanceof Error ? error.message : 'Payment Failed';
|
|
148
|
+
setError(errorMessage);
|
|
149
|
+
if (options.onError) {
|
|
150
|
+
options.onError(errorMessage);
|
|
151
|
+
}
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
setProcessingPayment(false);
|
|
156
|
+
}
|
|
157
|
+
}, [checkoutSessionId, paymentsResource, ordersResource, options]);
|
|
158
|
+
// Handle Apple Pay button click - opens Apple Pay sheet
|
|
159
|
+
const handleApplePayClick = useCallback(() => {
|
|
160
|
+
if (!summary || !store) {
|
|
161
|
+
console.error('Order summary or store not available');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const total = {
|
|
165
|
+
label: store.name || 'Store',
|
|
166
|
+
amount: minorUnitsToCurrencyString(summary.totalAdjustedAmount, summary.currency),
|
|
167
|
+
type: 'final',
|
|
168
|
+
};
|
|
169
|
+
const lineItems = [
|
|
170
|
+
{
|
|
171
|
+
label: 'Subtotal',
|
|
172
|
+
amount: minorUnitsToCurrencyString(summary.subtotalAdjustedAmount, summary.currency),
|
|
173
|
+
type: 'final',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
label: 'Shipping',
|
|
177
|
+
amount: minorUnitsToCurrencyString(summary.shippingCost ?? 0, summary.currency),
|
|
178
|
+
type: 'final',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
label: 'Tax',
|
|
182
|
+
amount: minorUnitsToCurrencyString(summary.totalTaxAmount, summary.currency),
|
|
183
|
+
type: 'final',
|
|
184
|
+
},
|
|
185
|
+
];
|
|
186
|
+
const request = {
|
|
187
|
+
countryCode: 'US', // TODO: Get from checkout session metadata
|
|
188
|
+
currencyCode: summary.currency,
|
|
189
|
+
supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
|
|
190
|
+
merchantCapabilities: ['supports3DS'],
|
|
191
|
+
total,
|
|
192
|
+
lineItems,
|
|
193
|
+
};
|
|
194
|
+
try {
|
|
195
|
+
const session = new ApplePaySession(3, request);
|
|
196
|
+
session.onvalidatemerchant = (event) => {
|
|
197
|
+
void (async () => {
|
|
198
|
+
try {
|
|
199
|
+
console.log('Merchant validation requested for:', event.validationURL);
|
|
200
|
+
const merchantSession = await validateMerchant();
|
|
201
|
+
session.completeMerchantValidation(merchantSession);
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
console.error('Merchant validation failed:', error);
|
|
205
|
+
session.abort();
|
|
206
|
+
}
|
|
207
|
+
})();
|
|
208
|
+
};
|
|
209
|
+
session.onpaymentauthorized = (event) => {
|
|
210
|
+
void (async () => {
|
|
211
|
+
try {
|
|
212
|
+
const applePayToken = await tokenizeApplePay(event);
|
|
213
|
+
session.completePayment(ApplePaySession.STATUS_SUCCESS);
|
|
214
|
+
await chargePayment(applePayToken);
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
console.error('Payment processing failed:', error);
|
|
218
|
+
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
|
219
|
+
}
|
|
220
|
+
})();
|
|
221
|
+
};
|
|
222
|
+
session.onerror = (event) => {
|
|
223
|
+
console.error('Apple Pay Session Error:', event);
|
|
224
|
+
};
|
|
225
|
+
session.oncancel = () => {
|
|
226
|
+
console.log('Payment cancelled by user');
|
|
227
|
+
if (options.onCancel) {
|
|
228
|
+
options.onCancel();
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
session.begin();
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
console.error('Failed to start Apple Pay session:', error);
|
|
235
|
+
setError('Failed to start Apple Pay session');
|
|
236
|
+
if (options.onError) {
|
|
237
|
+
options.onError('Failed to start Apple Pay session');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}, [summary, store, minorUnitsToCurrencyString, validateMerchant, tokenizeApplePay, chargePayment, options]);
|
|
241
|
+
return {
|
|
242
|
+
handleApplePayClick,
|
|
243
|
+
processingPayment,
|
|
244
|
+
applePayError: error,
|
|
245
|
+
isAvailable,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
@@ -127,30 +127,33 @@ export function usePaymentQuery() {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
break;
|
|
130
|
-
case 'processor_auth':
|
|
130
|
+
case 'processor_auth': {
|
|
131
|
+
// Always auto-redirect for processor auth (e.g., 3DS, external payment flows)
|
|
132
|
+
if (actionData.metadata?.redirect?.redirectUrl) {
|
|
133
|
+
window.location.href = actionData.metadata.redirect.redirectUrl;
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
131
137
|
case 'redirect': {
|
|
138
|
+
// For redirect type, let funnel orchestrator handle navigation via callbacks
|
|
132
139
|
// Only auto-redirect if explicitly enabled (disableAutoRedirect: false)
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (shouldRedirect && actionData.metadata?.redirect?.redirectUrl) {
|
|
140
|
+
const shouldAutoRedirect = options.disableAutoRedirect === false;
|
|
141
|
+
if (shouldAutoRedirect && actionData.metadata?.redirect?.redirectUrl) {
|
|
136
142
|
window.location.href = actionData.metadata.redirect.redirectUrl;
|
|
137
143
|
}
|
|
138
|
-
else {
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// Funnel-aligned callback (recommended)
|
|
152
|
-
options.onPaymentSuccess?.(response);
|
|
153
|
-
}
|
|
144
|
+
else if (payment.status === 'succeeded') {
|
|
145
|
+
// Payment succeeded - call success callbacks for funnel navigation
|
|
146
|
+
setIsLoading(false);
|
|
147
|
+
const response = {
|
|
148
|
+
paymentId: payment.id,
|
|
149
|
+
payment,
|
|
150
|
+
// Extract order from payment if available (for funnel path resolution)
|
|
151
|
+
order: payment.order,
|
|
152
|
+
};
|
|
153
|
+
// Legacy callback (backwards compatibility)
|
|
154
|
+
options.onSuccess?.(response);
|
|
155
|
+
// Funnel-aligned callback (recommended)
|
|
156
|
+
options.onPaymentSuccess?.(response);
|
|
154
157
|
}
|
|
155
158
|
break;
|
|
156
159
|
}
|
package/dist/v2/react/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { TagadaProvider, useTagadaContext } from './providers/TagadaProvider';
|
|
|
7
7
|
export type { DebugScript } from './providers/TagadaProvider';
|
|
8
8
|
export { ApplePayButton } from './components/ApplePayButton';
|
|
9
9
|
export { GooglePayButton } from './components/GooglePayButton';
|
|
10
|
+
export { useApplePay } from './hooks/useApplePay';
|
|
10
11
|
export { useAuth } from './hooks/useAuth';
|
|
11
12
|
export { useCheckoutToken } from './hooks/useCheckoutToken';
|
|
12
13
|
export { useClubOffers } from './hooks/useClubOffers';
|
|
@@ -42,6 +43,7 @@ export { useTranslation } from './hooks/useTranslation';
|
|
|
42
43
|
export { useVipOffersQuery as useVipOffers } from './hooks/useVipOffersQuery';
|
|
43
44
|
export { useFunnel } from './hooks/useFunnel';
|
|
44
45
|
export { useFunnel as useFunnelLegacy, useSimpleFunnel } from './hooks/useFunnelLegacy';
|
|
46
|
+
export type { UseApplePayOptions, UseApplePayResult } from './hooks/useApplePay';
|
|
45
47
|
export type { UseCheckoutTokenOptions, UseCheckoutTokenResult } from './hooks/useCheckoutToken';
|
|
46
48
|
export type { ClubOffer, ClubOfferItem, ClubOfferLineItem, ClubOfferSummary, UseClubOffersOptions, UseClubOffersResult } from './hooks/useClubOffers';
|
|
47
49
|
export type { UseCreditsOptions, UseCreditsResult } from './hooks/useCredits';
|
package/dist/v2/react/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { TagadaProvider, useTagadaContext } from './providers/TagadaProvider';
|
|
|
9
9
|
export { ApplePayButton } from './components/ApplePayButton';
|
|
10
10
|
export { GooglePayButton } from './components/GooglePayButton';
|
|
11
11
|
// Hooks
|
|
12
|
+
export { useApplePay } from './hooks/useApplePay';
|
|
12
13
|
export { useAuth } from './hooks/useAuth';
|
|
13
14
|
export { useCheckoutToken } from './hooks/useCheckoutToken';
|
|
14
15
|
export { useClubOffers } from './hooks/useClubOffers';
|