@tagadapay/plugin-sdk 2.6.2 → 2.6.6

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.
Files changed (55) hide show
  1. package/README.md +1090 -623
  2. package/dist/react/components/GooglePayButton.d.ts +12 -0
  3. package/dist/react/components/GooglePayButton.js +340 -0
  4. package/dist/react/components/index.d.ts +3 -2
  5. package/dist/react/components/index.js +3 -2
  6. package/dist/react/hooks/useApplePay.js +38 -10
  7. package/dist/react/hooks/{useExpressPayment.d.ts → useExpressPaymentMethods.d.ts} +13 -10
  8. package/dist/react/hooks/{useExpressPayment.js → useExpressPaymentMethods.js} +17 -8
  9. package/dist/react/hooks/useGoogleAutocomplete.d.ts +2 -0
  10. package/dist/react/hooks/useGoogleAutocomplete.js +18 -2
  11. package/dist/react/hooks/useGooglePay.d.ts +22 -0
  12. package/dist/react/hooks/useGooglePay.js +32 -0
  13. package/dist/react/index.d.ts +9 -7
  14. package/dist/react/index.js +8 -5
  15. package/dist/react/providers/TagadaProvider.js +5 -5
  16. package/dist/react/types/apple-pay.d.ts +0 -25
  17. package/dist/v2/core/googleAutocomplete.d.ts +2 -0
  18. package/dist/v2/core/googleAutocomplete.js +23 -4
  19. package/dist/v2/core/resources/checkout.d.ts +70 -2
  20. package/dist/v2/core/resources/discounts.d.ts +53 -0
  21. package/dist/v2/core/resources/discounts.js +29 -0
  22. package/dist/v2/core/resources/expressPaymentMethods.d.ts +56 -0
  23. package/dist/v2/core/resources/expressPaymentMethods.js +27 -0
  24. package/dist/v2/core/resources/index.d.ts +7 -4
  25. package/dist/v2/core/resources/index.js +7 -4
  26. package/dist/v2/core/resources/shippingRates.d.ts +36 -0
  27. package/dist/v2/core/resources/shippingRates.js +23 -0
  28. package/dist/v2/core/resources/vipOffers.d.ts +37 -0
  29. package/dist/v2/core/resources/vipOffers.js +27 -0
  30. package/dist/v2/core/utils/order.d.ts +1 -0
  31. package/dist/v2/core/utils/pluginConfig.d.ts +6 -6
  32. package/dist/v2/index.d.ts +12 -9
  33. package/dist/v2/index.js +3 -3
  34. package/dist/v2/react/components/ApplePayButton.d.ts +141 -0
  35. package/dist/v2/react/components/ApplePayButton.js +320 -0
  36. package/dist/v2/react/components/GooglePayButton.d.ts +19 -0
  37. package/dist/v2/react/components/GooglePayButton.js +355 -0
  38. package/dist/v2/react/hooks/useApiQuery.d.ts +4 -1
  39. package/dist/v2/react/hooks/useApiQuery.js +4 -1
  40. package/dist/v2/react/hooks/useDiscountsQuery.d.ts +30 -0
  41. package/dist/v2/react/hooks/useDiscountsQuery.js +175 -0
  42. package/dist/v2/react/hooks/useExpressPaymentMethods.d.ts +12 -0
  43. package/dist/v2/react/hooks/useExpressPaymentMethods.js +17 -0
  44. package/dist/v2/react/hooks/useGoogleAutocomplete.d.ts +2 -0
  45. package/dist/v2/react/hooks/useGoogleAutocomplete.js +18 -2
  46. package/dist/v2/react/hooks/useShippingRatesQuery.d.ts +22 -0
  47. package/dist/v2/react/hooks/useShippingRatesQuery.js +134 -0
  48. package/dist/v2/react/hooks/useVipOffersQuery.d.ts +72 -0
  49. package/dist/v2/react/hooks/useVipOffersQuery.js +140 -0
  50. package/dist/v2/react/index.d.ts +30 -17
  51. package/dist/v2/react/index.js +18 -10
  52. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +59 -0
  53. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +165 -0
  54. package/dist/v2/react/providers/TagadaProvider.js +5 -5
  55. package/package.json +90 -90
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { CheckoutData } from '../hooks/useCheckout';
3
+ interface GooglePayButtonProps {
4
+ className?: string;
5
+ disabled?: boolean;
6
+ onSuccess?: (payment: any) => void;
7
+ onError?: (error: string) => void;
8
+ onCancel?: () => void;
9
+ checkout: CheckoutData | null;
10
+ }
11
+ export declare const GooglePayButton: React.FC<GooglePayButtonProps>;
12
+ export default GooglePayButton;
@@ -0,0 +1,340 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import GooglePayButtonReact from '@google-pay/button-react';
3
+ import { useCallback, useEffect, useState } from 'react';
4
+ import { useExpressPaymentMethods } from '../hooks/useExpressPaymentMethods';
5
+ import { useOrderSummary } from '../hooks/useOrderSummary';
6
+ import { usePayment } from '../hooks/usePayment';
7
+ import { useShippingRates } from '../hooks/useShippingRates';
8
+ import { Button } from './Button';
9
+ const basistheoryPublicKey = process.env.NEXT_PUBLIC_BASIS_THEORY_PUBLIC_API_KEY || '';
10
+ const basistheoryTenantId = process.env.NEXT_PUBLIC_BASIS_THEORY_TENANT_ID || '0b283fa3-44a1-4535-adff-e99ad0a58a47';
11
+ export const GooglePayButton = ({ className = '', disabled = false, onSuccess, onError, onCancel, checkout, }) => {
12
+ const { googlePayPaymentMethod, reComputeOrderSummary, handleAddExpressId, updateCheckoutSessionValues, updateCustomerEmail, shippingMethods, setError: setContextError, } = useExpressPaymentMethods();
13
+ const [processingPayment, setProcessingPayment] = useState(false);
14
+ const [pendingPaymentData, setPendingPaymentData] = useState(null);
15
+ const [googlePayError, setGooglePayError] = useState(null);
16
+ const checkoutSessionId = checkout?.checkoutSession?.id;
17
+ const { processApplePayPayment: processExpressPayment } = usePayment(); // Will create processGooglePayPayment method
18
+ const { orderSummary } = useOrderSummary({ sessionId: checkoutSessionId });
19
+ const { selectRate } = useShippingRates({ checkout: checkout || undefined });
20
+ // Don't render if no Google Pay payment method is enabled
21
+ if (!googlePayPaymentMethod) {
22
+ return null;
23
+ }
24
+ // Register express payment method
25
+ useEffect(() => {
26
+ handleAddExpressId('google_pay');
27
+ }, [handleAddExpressId]);
28
+ // Convert Google Pay address to internal Address format
29
+ const googlePayAddressToAddress = useCallback((googlePayAddress) => {
30
+ return {
31
+ address1: googlePayAddress.address1 || '',
32
+ address2: googlePayAddress.address2 || '',
33
+ lastName: googlePayAddress.name?.split(' ').slice(-1)[0] || '',
34
+ firstName: googlePayAddress.name?.split(' ').slice(0, -1).join(' ') || '',
35
+ city: googlePayAddress.locality || '',
36
+ state: googlePayAddress.administrativeArea || '',
37
+ country: googlePayAddress.countryCode || '',
38
+ postal: googlePayAddress.postalCode || '',
39
+ phone: googlePayAddress.phoneNumber || '',
40
+ email: '',
41
+ };
42
+ }, []);
43
+ // Tokenize Google Pay data using Basis Theory
44
+ const tokenizeGooglePayTokenWithBasisTheory = useCallback(async (paymentData) => {
45
+ try {
46
+ const googlePayTokenString = paymentData.paymentMethodData.tokenizationData.token;
47
+ const googlePayToken = JSON.parse(googlePayTokenString);
48
+ const response = await fetch('https://api.basistheory.com/google-pay', {
49
+ method: 'POST',
50
+ headers: {
51
+ 'Content-Type': 'application/json',
52
+ 'BT-API-KEY': basistheoryPublicKey,
53
+ },
54
+ body: JSON.stringify({
55
+ google_payment_data: googlePayToken,
56
+ }),
57
+ });
58
+ if (!response.ok) {
59
+ const errorData = await response.json().catch(() => ({}));
60
+ console.error('Basis Theory API error:', errorData);
61
+ throw new Error(`HTTP error! Status: ${response.status}`);
62
+ }
63
+ const jsonResponse = await response.json();
64
+ return jsonResponse?.token_intent || jsonResponse?.google_pay;
65
+ }
66
+ catch (error) {
67
+ console.error('Error tokenizing Google Pay data:', error);
68
+ throw error;
69
+ }
70
+ }, []);
71
+ // Charge payment in backend
72
+ const chargePayment = useCallback(async (token) => {
73
+ if (!checkoutSessionId) {
74
+ throw new Error('Checkout session ID is not available');
75
+ }
76
+ setProcessingPayment(true);
77
+ try {
78
+ // Use the payment hook to process the Google Pay payment
79
+ // Note: You'll need to implement processGooglePayPayment similar to processApplePayPayment
80
+ await processExpressPayment(checkoutSessionId, token, {
81
+ onSuccess: (payment) => {
82
+ setProcessingPayment(false);
83
+ if (onSuccess) {
84
+ onSuccess(payment);
85
+ }
86
+ },
87
+ onFailure: (error) => {
88
+ setProcessingPayment(false);
89
+ const errorMessage = error || 'Payment Failed';
90
+ setGooglePayError(errorMessage);
91
+ setContextError(errorMessage);
92
+ if (onError) {
93
+ onError(errorMessage);
94
+ }
95
+ },
96
+ });
97
+ }
98
+ catch (error) {
99
+ console.error('Error charging payment:', error);
100
+ const errorMessage = error instanceof Error ? error.message : 'Payment Failed';
101
+ setProcessingPayment(false);
102
+ setGooglePayError(errorMessage);
103
+ setContextError(errorMessage);
104
+ if (onError) {
105
+ onError(errorMessage);
106
+ }
107
+ throw error;
108
+ }
109
+ }, [checkoutSessionId, processExpressPayment, onSuccess, onError, setContextError]);
110
+ // Process payment data
111
+ const onGooglePaymentData = useCallback(async (paymentData) => {
112
+ setProcessingPayment(true);
113
+ try {
114
+ // Extract billing address if available
115
+ let billingAddress;
116
+ if (paymentData.paymentMethodData.info?.billingAddress) {
117
+ billingAddress = googlePayAddressToAddress(paymentData.paymentMethodData.info.billingAddress);
118
+ }
119
+ // Extract shipping address if available
120
+ let shippingAddress;
121
+ if (paymentData.shippingAddress) {
122
+ shippingAddress = googlePayAddressToAddress(paymentData.shippingAddress);
123
+ }
124
+ // Update checkout session with addresses before processing payment
125
+ if (shippingAddress) {
126
+ await updateCheckoutSessionValues({
127
+ data: {
128
+ shippingAddress,
129
+ billingAddress: billingAddress ?? null,
130
+ },
131
+ });
132
+ }
133
+ // Update customer email if provided
134
+ if (paymentData.email) {
135
+ await updateCustomerEmail({
136
+ data: {
137
+ email: paymentData.email,
138
+ },
139
+ });
140
+ }
141
+ const payToken = await tokenizeGooglePayTokenWithBasisTheory(paymentData);
142
+ await chargePayment(payToken);
143
+ }
144
+ catch (error) {
145
+ console.error('Error processing Google Pay payment:', error);
146
+ const errorMessage = error instanceof Error ? error.message : 'Payment Failed';
147
+ setProcessingPayment(false);
148
+ setGooglePayError(errorMessage);
149
+ setContextError(errorMessage);
150
+ if (onError) {
151
+ onError(errorMessage);
152
+ }
153
+ }
154
+ }, [
155
+ googlePayAddressToAddress,
156
+ updateCheckoutSessionValues,
157
+ updateCustomerEmail,
158
+ tokenizeGooglePayTokenWithBasisTheory,
159
+ chargePayment,
160
+ onError,
161
+ setContextError,
162
+ ]);
163
+ // Effect to process payment data in background
164
+ useEffect(() => {
165
+ if (pendingPaymentData && !processingPayment) {
166
+ const processPaymentInBackground = async () => {
167
+ try {
168
+ await onGooglePaymentData(pendingPaymentData);
169
+ }
170
+ catch (error) {
171
+ console.error('Background payment processing failed:', error);
172
+ }
173
+ finally {
174
+ setPendingPaymentData(null);
175
+ }
176
+ };
177
+ void processPaymentInBackground();
178
+ }
179
+ }, [pendingPaymentData, processingPayment, onGooglePaymentData]);
180
+ // Handle payment data changes during the flow
181
+ const handleGooglePayDataChanged = useCallback((intermediatePaymentData) => {
182
+ return new Promise((resolve) => {
183
+ const processCallback = async () => {
184
+ try {
185
+ const paymentDataRequestUpdate = {};
186
+ if (intermediatePaymentData.callbackTrigger === 'SHIPPING_ADDRESS') {
187
+ const address = intermediatePaymentData.shippingAddress;
188
+ const shippingAddress = {
189
+ address1: address?.addressLines?.[0] || '',
190
+ address2: address?.addressLines?.[1] || '',
191
+ lastName: address?.name?.split(' ').slice(-1)[0] || '',
192
+ firstName: address?.name?.split(' ').slice(0, -1).join(' ') || '',
193
+ city: address?.locality || '',
194
+ state: address?.administrativeArea || '',
195
+ country: address?.countryCode || '',
196
+ postal: address?.postalCode || '',
197
+ phone: address?.phoneNumber || '',
198
+ email: '',
199
+ };
200
+ await updateCheckoutSessionValues({
201
+ data: { shippingAddress },
202
+ });
203
+ const newOrderSummary = await reComputeOrderSummary();
204
+ if (newOrderSummary) {
205
+ paymentDataRequestUpdate.newShippingOptionParameters = {
206
+ defaultSelectedOptionId: newOrderSummary.shippingMethods[0]?.identifier || '',
207
+ shippingOptions: newOrderSummary.shippingMethods.map((method) => ({
208
+ id: method.identifier,
209
+ label: method.label,
210
+ description: method.amount + ': ' + method.detail || '',
211
+ })),
212
+ };
213
+ paymentDataRequestUpdate.newTransactionInfo = {
214
+ totalPriceStatus: 'FINAL',
215
+ totalPrice: newOrderSummary.total.amount,
216
+ currencyCode: orderSummary?.currency || 'USD',
217
+ };
218
+ }
219
+ }
220
+ else if (intermediatePaymentData.callbackTrigger === 'SHIPPING_OPTION') {
221
+ // Update shipping rate
222
+ if (selectRate) {
223
+ await selectRate(intermediatePaymentData.shippingOptionData.id);
224
+ }
225
+ const newOrderSummary = await reComputeOrderSummary();
226
+ if (newOrderSummary) {
227
+ paymentDataRequestUpdate.newTransactionInfo = {
228
+ totalPriceStatus: 'FINAL',
229
+ totalPrice: newOrderSummary.total.amount,
230
+ currencyCode: orderSummary?.currency || 'USD',
231
+ };
232
+ }
233
+ }
234
+ else if (intermediatePaymentData.callbackTrigger === 'OFFER') {
235
+ console.log('OFFER callback triggered, no action needed');
236
+ }
237
+ else if (intermediatePaymentData.callbackTrigger === 'INITIALIZE') {
238
+ console.log('INITIALIZE callback triggered, no action needed');
239
+ }
240
+ resolve(paymentDataRequestUpdate);
241
+ }
242
+ catch (error) {
243
+ console.error('Error in onPaymentDataChanged:', error);
244
+ resolve({
245
+ error: {
246
+ reason: 'SHIPPING_ADDRESS_UNSERVICEABLE',
247
+ message: 'Unable to calculate shipping for this address',
248
+ intent: intermediatePaymentData.callbackTrigger,
249
+ },
250
+ });
251
+ }
252
+ };
253
+ void processCallback();
254
+ });
255
+ }, [updateCheckoutSessionValues, reComputeOrderSummary, selectRate, orderSummary]);
256
+ // Handle payment authorization
257
+ const handleGooglePayAuthorized = useCallback((paymentData) => {
258
+ setPendingPaymentData(paymentData);
259
+ return Promise.resolve({ transactionState: 'SUCCESS' });
260
+ }, []);
261
+ // Don't render if no order summary
262
+ if (!orderSummary) {
263
+ return null;
264
+ }
265
+ const minorUnitsToCurrencyString = (amountMinor, currency) => {
266
+ return (amountMinor / 100).toFixed(2);
267
+ };
268
+ const allowedCardNetworks = ['AMEX', 'DISCOVER', 'INTERAC', 'JCB', 'MASTERCARD', 'VISA'];
269
+ const allowedCardAuthMethods = ['PAN_ONLY', 'CRYPTOGRAM_3DS'];
270
+ const baseCardPaymentMethod = {
271
+ type: 'CARD',
272
+ parameters: {
273
+ allowedAuthMethods: allowedCardAuthMethods,
274
+ allowedCardNetworks: allowedCardNetworks,
275
+ billingAddressRequired: true,
276
+ billingAddressParameters: {
277
+ format: 'FULL',
278
+ phoneNumberRequired: true,
279
+ },
280
+ },
281
+ };
282
+ const tokenizationSpecification = {
283
+ type: 'PAYMENT_GATEWAY',
284
+ parameters: {
285
+ gateway: 'basistheory',
286
+ gatewayMerchantId: basistheoryTenantId,
287
+ },
288
+ };
289
+ const paymentRequest = {
290
+ apiVersion: 2,
291
+ apiVersionMinor: 0,
292
+ allowedPaymentMethods: [
293
+ {
294
+ ...baseCardPaymentMethod,
295
+ tokenizationSpecification,
296
+ },
297
+ ],
298
+ transactionInfo: {
299
+ totalPriceStatus: 'FINAL',
300
+ totalPrice: minorUnitsToCurrencyString(orderSummary.totalAdjustedAmount, orderSummary.currency),
301
+ currencyCode: orderSummary.currency,
302
+ },
303
+ merchantInfo: {
304
+ merchantName: googlePayPaymentMethod?.metadata?.merchantName ||
305
+ checkout?.checkoutSession?.store?.name ||
306
+ 'Store',
307
+ merchantId: googlePayPaymentMethod?.metadata?.sandboxed
308
+ ? '12345678901234567890'
309
+ : googlePayPaymentMethod?.metadata?.merchantId || '12345678901234567890',
310
+ },
311
+ shippingAddressRequired: true,
312
+ shippingOptionRequired: true,
313
+ emailRequired: true,
314
+ callbackIntents: ['SHIPPING_OPTION', 'SHIPPING_ADDRESS', 'PAYMENT_AUTHORIZATION'],
315
+ shippingOptionParameters: {
316
+ defaultSelectedOptionId: shippingMethods.length > 0 ? shippingMethods[0].identifier : '',
317
+ shippingOptions: shippingMethods.map((method) => ({
318
+ id: method.identifier,
319
+ label: method.label,
320
+ description: method.amount + ': ' + method.detail || '',
321
+ })),
322
+ },
323
+ };
324
+ const environment = googlePayPaymentMethod?.metadata?.sandboxed ? 'TEST' : 'PRODUCTION';
325
+ return (_jsxs("div", { className: "w-full", children: [!processingPayment ? (_jsx(GooglePayButtonReact, { environment: environment, paymentRequest: paymentRequest, onPaymentAuthorized: handleGooglePayAuthorized, onPaymentDataChanged: handleGooglePayDataChanged, onError: (error) => {
326
+ console.error('Google Pay error:', error);
327
+ const errorMessage = 'Google Pay error: ' + error.statusMessage;
328
+ setGooglePayError(errorMessage);
329
+ setContextError(errorMessage);
330
+ if (onError) {
331
+ onError(errorMessage);
332
+ }
333
+ }, onCancel: () => {
334
+ console.log('Google Pay payment cancelled');
335
+ if (onCancel) {
336
+ onCancel();
337
+ }
338
+ }, existingPaymentMethodRequired: false, buttonColor: "black", buttonType: "plain", buttonSizeMode: "fill", buttonLocale: "en", className: `m-0 h-10 w-full rounded-sm p-0 text-base text-white ${className}` })) : (_jsx(Button, { type: "button", variant: "outline", size: "lg", className: "h-10 w-full bg-black text-base text-white shadow-sm hover:bg-black/80", disabled: true, children: _jsxs("div", { className: "flex items-center justify-center gap-3", children: [_jsx("div", { className: "h-5 w-5 animate-spin rounded-full border-2 border-white border-t-transparent" }), _jsx("span", { className: "font-medium", children: "Processing..." })] }) })), googlePayError && (_jsx("div", { className: "mt-2 rounded border border-red-200 bg-red-50 p-2 text-sm text-red-600", children: googlePayError }))] }));
339
+ };
340
+ export default GooglePayButton;
@@ -1,3 +1,4 @@
1
- export { default as DebugDrawer } from './DebugDrawer';
2
- export { default as Button } from './Button';
3
1
  export { default as ApplePayButton } from './ApplePayButton';
2
+ export { default as Button } from './Button';
3
+ export { default as DebugDrawer } from './DebugDrawer';
4
+ export { default as GooglePayButton } from './GooglePayButton';
@@ -1,3 +1,4 @@
1
- export { default as DebugDrawer } from './DebugDrawer';
2
- export { default as Button } from './Button';
3
1
  export { default as ApplePayButton } from './ApplePayButton';
2
+ export { default as Button } from './Button';
3
+ export { default as DebugDrawer } from './DebugDrawer';
4
+ export { default as GooglePayButton } from './GooglePayButton';
@@ -282,7 +282,9 @@ export function useApplePay(options = {}) {
282
282
  // Tokenize the Apple Pay payment
283
283
  const applePayToken = await tokenizeApplePay(event);
284
284
  // Complete the Apple Pay session
285
- session.completePayment(window.ApplePaySession.STATUS_SUCCESS);
285
+ session.completePayment({
286
+ status: window.ApplePaySession.STATUS_SUCCESS,
287
+ });
286
288
  // Process the payment using the SDK's payment methods
287
289
  await processApplePayPayment(checkoutSessionId, applePayToken, {
288
290
  onSuccess: (payment) => {
@@ -298,7 +300,9 @@ export function useApplePay(options = {}) {
298
300
  }
299
301
  catch (error) {
300
302
  console.error('Payment processing failed:', error);
301
- session.completePayment(window.ApplePaySession.STATUS_FAILURE);
303
+ session.completePayment({
304
+ status: window.ApplePaySession.STATUS_FAILURE,
305
+ });
302
306
  setProcessingPayment(false);
303
307
  const errorMsg = error instanceof Error ? error.message : 'Payment processing failed';
304
308
  setError(errorMsg);
@@ -317,7 +321,18 @@ export function useApplePay(options = {}) {
317
321
  return;
318
322
  }
319
323
  const { lineItems: newLineItems, total: newTotal } = newOrderSummary;
320
- session.completeShippingMethodSelection(window.ApplePaySession.STATUS_SUCCESS, newTotal, newLineItems);
324
+ session.completeShippingMethodSelection({
325
+ newTotal: {
326
+ label: newTotal.label,
327
+ amount: newTotal.amount,
328
+ type: 'final',
329
+ },
330
+ newLineItems: newLineItems.map(item => ({
331
+ label: item.label,
332
+ amount: item.amount,
333
+ type: 'final',
334
+ })),
335
+ });
321
336
  }
322
337
  catch (error) {
323
338
  console.error('Shipping method selection failed:', error);
@@ -343,7 +358,24 @@ export function useApplePay(options = {}) {
343
358
  console.log('======= APPLE PAY ON SHIPPING CONTACT SELECTED ======');
344
359
  console.log('newOrderSummary', newOrderSummary);
345
360
  console.log(newLineItems, newTotal, newShippingMethods);
346
- session.completeShippingContactSelection(window.ApplePaySession.STATUS_SUCCESS, newShippingMethods, newTotal, newLineItems);
361
+ session.completeShippingContactSelection({
362
+ newShippingMethods: newShippingMethods.map(method => ({
363
+ label: method.label,
364
+ amount: method.amount,
365
+ detail: method.detail,
366
+ identifier: method.identifier,
367
+ })),
368
+ newTotal: {
369
+ label: newTotal.label,
370
+ amount: newTotal.amount,
371
+ type: 'final',
372
+ },
373
+ newLineItems: newLineItems.map(item => ({
374
+ label: item.label,
375
+ amount: item.amount,
376
+ type: 'final',
377
+ })),
378
+ });
347
379
  }
348
380
  catch (error) {
349
381
  console.error('Shipping contact selection failed:', error);
@@ -351,12 +383,8 @@ export function useApplePay(options = {}) {
351
383
  }
352
384
  })();
353
385
  };
354
- session.onerror = (event) => {
355
- console.error('Apple Pay Session Error:', event);
356
- const errorMsg = 'Apple Pay session error';
357
- setError(errorMsg);
358
- options.onError?.(errorMsg);
359
- };
386
+ // Note: ApplePaySession doesn't have an onerror handler
387
+ // Error handling is done in the specific event handlers above
360
388
  session.oncancel = () => {
361
389
  console.log('Payment cancelled by user');
362
390
  setProcessingPayment(false);
@@ -30,9 +30,17 @@ type ExpressShippingMethod = {
30
30
  identifier: string;
31
31
  detail: string;
32
32
  };
33
- export interface ExpressPaymentContextType {
33
+ export interface ExpressPaymentMethodsContextType {
34
+ paymentMethods: PaymentMethod[] | undefined;
34
35
  applePayPaymentMethod?: PaymentMethod;
35
36
  googlePayPaymentMethod?: PaymentMethod;
37
+ paypalPaymentMethod?: PaymentMethod;
38
+ klarnaPaymentMethod?: PaymentMethod;
39
+ availableExpressPaymentMethodIds: string[];
40
+ setAvailableExpressPaymentMethodIds: (value: string[]) => void;
41
+ handleAddExpressId: (id: string) => void;
42
+ shippingMethods: ExpressShippingMethod[];
43
+ lineItems: ExpressOrderLineItem[];
36
44
  reComputeOrderSummary: () => Promise<{
37
45
  lineItems: ExpressOrderLineItem[];
38
46
  total: {
@@ -41,12 +49,6 @@ export interface ExpressPaymentContextType {
41
49
  };
42
50
  shippingMethods: ExpressShippingMethod[];
43
51
  } | undefined>;
44
- loading?: boolean;
45
- availableExpressPaymentMethodIds: string[];
46
- setAvailableExpressPaymentMethodIds: (value: string[]) => void;
47
- shippingMethods: ExpressShippingMethod[];
48
- lineItems: ExpressOrderLineItem[];
49
- handleAddExpressId: (id: string) => void;
50
52
  updateCheckoutSessionValues: (input: {
51
53
  data: {
52
54
  shippingAddress: Address;
@@ -58,14 +60,15 @@ export interface ExpressPaymentContextType {
58
60
  email: string;
59
61
  };
60
62
  }) => Promise<void>;
63
+ loading?: boolean;
61
64
  error: string | null;
62
65
  setError: (error: string | null) => void;
63
66
  }
64
- interface ExpressPaymentProviderProps {
67
+ interface ExpressPaymentMethodsProviderProps {
65
68
  children: ReactNode;
66
69
  customerId?: string;
67
70
  checkout?: CheckoutData;
68
71
  }
69
- export declare const ExpressPaymentProvider: React.FC<ExpressPaymentProviderProps>;
70
- export declare const useExpressPayment: () => ExpressPaymentContextType;
72
+ export declare const ExpressPaymentMethodsProvider: React.FC<ExpressPaymentMethodsProviderProps>;
73
+ export declare const useExpressPaymentMethods: () => ExpressPaymentMethodsContextType;
71
74
  export {};
@@ -3,8 +3,8 @@ import React, { createContext, useCallback, useContext, useMemo, useState } from
3
3
  import { useTagadaContext } from '../providers/TagadaProvider';
4
4
  import { useOrderSummary } from './useOrderSummary';
5
5
  import { useShippingRates } from './useShippingRates';
6
- const ExpressPaymentContext = createContext(undefined);
7
- export const ExpressPaymentProvider = ({ children, customerId, checkout, }) => {
6
+ const ExpressPaymentMethodsContext = createContext(undefined);
7
+ export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout, }) => {
8
8
  const { apiService } = useTagadaContext();
9
9
  const [availableExpressPaymentMethodIds, setAvailableExpressPaymentMethodIds] = useState([]);
10
10
  const [error, setError] = useState(null);
@@ -37,7 +37,7 @@ export const ExpressPaymentProvider = ({ children, customerId, checkout, }) => {
37
37
  return () => {
38
38
  mounted = false;
39
39
  };
40
- }, [apiService, checkoutSessionId]);
40
+ }, [apiService, checkoutSessionId, checkout]);
41
41
  const handleAddExpressId = (id) => {
42
42
  setAvailableExpressPaymentMethodIds((prev) => (prev.includes(id) ? prev : [...prev, id]));
43
43
  };
@@ -128,14 +128,20 @@ export const ExpressPaymentProvider = ({ children, customerId, checkout, }) => {
128
128
  body: input,
129
129
  });
130
130
  }, [apiService, customerId]);
131
+ // Identify specific payment method types
131
132
  const enabledApplePayPaymentMethod = useMemo(() => paymentMethods?.find((p) => p.type === 'apple_pay'), [paymentMethods]);
132
133
  const enabledGooglePayPaymentMethod = useMemo(() => paymentMethods?.find((p) => p.type === 'google_pay'), [paymentMethods]);
134
+ const enabledPaypalPaymentMethod = useMemo(() => paymentMethods?.find((p) => p.type === 'paypal'), [paymentMethods]);
135
+ const enabledKlarnaPaymentMethod = useMemo(() => paymentMethods?.find((p) => p.type === 'klarna'), [paymentMethods]);
133
136
  const loading = !paymentMethods || isLoadingPaymentMethods || isLoadingOrderSummary;
134
137
  const contextValue = {
138
+ paymentMethods: paymentMethods || undefined,
135
139
  availableExpressPaymentMethodIds,
136
140
  setAvailableExpressPaymentMethodIds,
137
141
  applePayPaymentMethod: enabledApplePayPaymentMethod,
138
142
  googlePayPaymentMethod: enabledGooglePayPaymentMethod,
143
+ paypalPaymentMethod: enabledPaypalPaymentMethod,
144
+ klarnaPaymentMethod: enabledKlarnaPaymentMethod,
139
145
  shippingMethods,
140
146
  lineItems,
141
147
  reComputeOrderSummary,
@@ -146,13 +152,16 @@ export const ExpressPaymentProvider = ({ children, customerId, checkout, }) => {
146
152
  error,
147
153
  setError,
148
154
  };
149
- const hasAnyEnabled = Boolean(enabledApplePayPaymentMethod || enabledGooglePayPaymentMethod);
150
- return (_jsx(ExpressPaymentContext.Provider, { value: contextValue, children: hasAnyEnabled ? _jsx(_Fragment, { children: children }) : _jsx(_Fragment, {}) }));
155
+ const hasAnyEnabled = Boolean(enabledApplePayPaymentMethod ||
156
+ enabledGooglePayPaymentMethod ||
157
+ enabledPaypalPaymentMethod ||
158
+ enabledKlarnaPaymentMethod);
159
+ return (_jsx(ExpressPaymentMethodsContext.Provider, { value: contextValue, children: hasAnyEnabled ? _jsx(_Fragment, { children: children }) : _jsx(_Fragment, {}) }));
151
160
  };
152
- export const useExpressPayment = () => {
153
- const context = useContext(ExpressPaymentContext);
161
+ export const useExpressPaymentMethods = () => {
162
+ const context = useContext(ExpressPaymentMethodsContext);
154
163
  if (context === undefined) {
155
- throw new Error('useExpressPayment must be used within an ExpressPaymentProvider');
164
+ throw new Error('useExpressPaymentMethods must be used within an ExpressPaymentMethodsProvider');
156
165
  }
157
166
  return context;
158
167
  };
@@ -38,6 +38,8 @@ export interface ExtractedAddress {
38
38
  locality: string;
39
39
  administrativeAreaLevel1: string;
40
40
  administrativeAreaLevel1Long: string;
41
+ administrativeAreaLevel2: string;
42
+ administrativeAreaLevel2Long: string;
41
43
  country: string;
42
44
  postalCode: string;
43
45
  }
@@ -155,6 +155,8 @@ export function useGoogleAutocomplete(options) {
155
155
  locality: '',
156
156
  administrativeAreaLevel1: '',
157
157
  administrativeAreaLevel1Long: '',
158
+ administrativeAreaLevel2: '',
159
+ administrativeAreaLevel2Long: '',
158
160
  country: '',
159
161
  postalCode: '',
160
162
  };
@@ -170,8 +172,13 @@ export function useGoogleAutocomplete(options) {
170
172
  if (types.includes('locality')) {
171
173
  extracted.locality = component.long_name;
172
174
  }
173
- if (types.includes('administrative_area_level_2') && !!!extracted.locality) {
174
- extracted.locality = component.long_name;
175
+ if (types.includes('administrative_area_level_2')) {
176
+ extracted.administrativeAreaLevel2 = component.short_name;
177
+ extracted.administrativeAreaLevel2Long = component.long_name;
178
+ // Use level_2 as fallback for locality if locality is not set
179
+ if (!extracted.locality) {
180
+ extracted.locality = component.long_name;
181
+ }
175
182
  }
176
183
  if (types.includes('administrative_area_level_1')) {
177
184
  extracted.administrativeAreaLevel1 = component.short_name;
@@ -184,6 +191,15 @@ export function useGoogleAutocomplete(options) {
184
191
  extracted.postalCode = component.long_name;
185
192
  }
186
193
  });
194
+ // For countries like France where administrative_area_level_1 (région) may be missing,
195
+ // use administrative_area_level_2 (département) as the primary state/province value
196
+ // We prefer the long_name (e.g., "Bouches-du-Rhône") over short_name (e.g., "13")
197
+ // because it's more likely to match our state database entries
198
+ if (!extracted.administrativeAreaLevel1 && extracted.administrativeAreaLevel2) {
199
+ // Use long name as the primary value (e.g., "Bouches-du-Rhône" instead of "13")
200
+ extracted.administrativeAreaLevel1 = extracted.administrativeAreaLevel2Long || extracted.administrativeAreaLevel2;
201
+ extracted.administrativeAreaLevel1Long = extracted.administrativeAreaLevel2Long;
202
+ }
187
203
  console.log('🏗️ Extracted address components:', extracted);
188
204
  return extracted;
189
205
  }, []);
@@ -0,0 +1,22 @@
1
+ interface UseGooglePayOptions {
2
+ onSuccess?: (payment: any) => void;
3
+ onError?: (error: string) => void;
4
+ onCancel?: () => void;
5
+ checkoutSessionId?: string;
6
+ customerId?: string;
7
+ storeName?: string;
8
+ currencyCode?: string;
9
+ merchantId?: string;
10
+ merchantName?: string;
11
+ }
12
+ export declare const useGooglePay: ({ onSuccess, onError, onCancel, checkoutSessionId, customerId, storeName, currencyCode, merchantId, merchantName, }: UseGooglePayOptions) => {
13
+ handleGooglePayAuthorized: (paymentData: any) => Promise<any>;
14
+ handleGooglePayDataChanged: (intermediatePaymentData: any) => Promise<any>;
15
+ processingPayment: boolean;
16
+ setProcessingPayment: import("react").Dispatch<import("react").SetStateAction<boolean>>;
17
+ googlePayError: string | null;
18
+ setGooglePayError: import("react").Dispatch<import("react").SetStateAction<string | null>>;
19
+ isGooglePayAvailable: boolean;
20
+ paymentRequest: null;
21
+ };
22
+ export {};