@tagadapay/plugin-sdk 2.4.39 → 2.5.0

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 (106) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +2 -0
  3. package/dist/react/hooks/useCheckout.js +19 -2
  4. package/dist/react/hooks/useCheckoutSession.d.ts +19 -0
  5. package/dist/react/hooks/useCheckoutSession.js +108 -0
  6. package/dist/react/hooks/useCheckoutToken.d.ts +17 -0
  7. package/dist/react/hooks/useCheckoutToken.js +80 -0
  8. package/dist/react/hooks/useOrderBump.js +92 -13
  9. package/dist/react/hooks/useOrderBumpV2.d.ts +17 -0
  10. package/dist/react/hooks/useOrderBumpV2.js +95 -0
  11. package/dist/react/hooks/useOrderBumpV3.d.ts +23 -0
  12. package/dist/react/hooks/useOrderBumpV3.js +109 -0
  13. package/dist/react/hooks/usePostPurchases.js +11 -5
  14. package/dist/react/index.d.ts +8 -0
  15. package/dist/react/index.js +4 -0
  16. package/dist/react/services/apiService.d.ts +1 -0
  17. package/dist/react/services/apiService.js +3 -0
  18. package/dist/v2/core/googleAutocomplete.d.ts +65 -0
  19. package/dist/v2/core/googleAutocomplete.js +94 -0
  20. package/dist/v2/core/index.d.ts +8 -0
  21. package/dist/v2/core/index.js +11 -0
  22. package/dist/v2/core/isoData.d.ts +50 -0
  23. package/dist/v2/core/isoData.js +103 -0
  24. package/dist/v2/core/resources/apiClient.d.ts +25 -0
  25. package/dist/v2/core/resources/apiClient.js +95 -0
  26. package/dist/v2/core/resources/checkout.d.ts +189 -0
  27. package/dist/v2/core/resources/checkout.js +119 -0
  28. package/dist/v2/core/resources/index.d.ts +13 -0
  29. package/dist/v2/core/resources/index.js +13 -0
  30. package/dist/v2/core/resources/offers.d.ts +98 -0
  31. package/dist/v2/core/resources/offers.js +115 -0
  32. package/dist/v2/core/resources/orders.d.ts +40 -0
  33. package/dist/v2/core/resources/orders.js +59 -0
  34. package/dist/v2/core/resources/payments.d.ts +140 -0
  35. package/dist/v2/core/resources/payments.js +126 -0
  36. package/dist/v2/core/resources/postPurchases.d.ts +182 -0
  37. package/dist/v2/core/resources/postPurchases.js +116 -0
  38. package/dist/v2/core/resources/products.d.ts +29 -0
  39. package/dist/v2/core/resources/products.js +49 -0
  40. package/dist/v2/core/resources/promotions.d.ts +45 -0
  41. package/dist/v2/core/resources/promotions.js +87 -0
  42. package/dist/v2/core/resources/threeds.d.ts +23 -0
  43. package/dist/v2/core/resources/threeds.js +15 -0
  44. package/dist/v2/core/utils/checkout.d.ts +24 -0
  45. package/dist/v2/core/utils/checkout.js +30 -0
  46. package/dist/v2/core/utils/currency.d.ts +28 -0
  47. package/dist/v2/core/utils/currency.js +272 -0
  48. package/dist/v2/core/utils/index.d.ts +12 -0
  49. package/dist/v2/core/utils/index.js +12 -0
  50. package/dist/v2/core/utils/order.d.ts +159 -0
  51. package/dist/v2/core/utils/order.js +42 -0
  52. package/dist/v2/core/utils/orderBump.d.ts +40 -0
  53. package/dist/v2/core/utils/orderBump.js +47 -0
  54. package/dist/v2/core/utils/pluginConfig.d.ts +43 -0
  55. package/dist/v2/core/utils/pluginConfig.js +155 -0
  56. package/dist/v2/core/utils/postPurchases.d.ts +32 -0
  57. package/dist/v2/core/utils/postPurchases.js +42 -0
  58. package/dist/v2/core/utils/products.d.ts +58 -0
  59. package/dist/v2/core/utils/products.js +64 -0
  60. package/dist/v2/core/utils/promotions.d.ts +24 -0
  61. package/dist/v2/core/utils/promotions.js +30 -0
  62. package/dist/v2/index.d.ts +19 -0
  63. package/dist/v2/index.js +15 -0
  64. package/dist/v2/react/components/DebugDrawer.d.ts +7 -0
  65. package/dist/v2/react/components/DebugDrawer.js +383 -0
  66. package/dist/v2/react/hooks/useApiQuery.d.ts +28 -0
  67. package/dist/v2/react/hooks/useApiQuery.js +84 -0
  68. package/dist/v2/react/hooks/useCheckoutQuery.d.ts +39 -0
  69. package/dist/v2/react/hooks/useCheckoutQuery.js +208 -0
  70. package/dist/v2/react/hooks/useCheckoutToken.d.ts +17 -0
  71. package/dist/v2/react/hooks/useCheckoutToken.js +80 -0
  72. package/dist/v2/react/hooks/useCurrency.d.ts +9 -0
  73. package/dist/v2/react/hooks/useCurrency.js +21 -0
  74. package/dist/v2/react/hooks/useGeoLocation.d.ts +138 -0
  75. package/dist/v2/react/hooks/useGeoLocation.js +126 -0
  76. package/dist/v2/react/hooks/useGoogleAutocomplete.d.ts +74 -0
  77. package/dist/v2/react/hooks/useGoogleAutocomplete.js +207 -0
  78. package/dist/v2/react/hooks/useISOData.d.ts +61 -0
  79. package/dist/v2/react/hooks/useISOData.js +176 -0
  80. package/dist/v2/react/hooks/useOffersQuery.d.ts +65 -0
  81. package/dist/v2/react/hooks/useOffersQuery.js +353 -0
  82. package/dist/v2/react/hooks/useOrderBumpQuery.d.ts +20 -0
  83. package/dist/v2/react/hooks/useOrderBumpQuery.js +88 -0
  84. package/dist/v2/react/hooks/useOrderQuery.d.ts +29 -0
  85. package/dist/v2/react/hooks/useOrderQuery.js +98 -0
  86. package/dist/v2/react/hooks/usePaymentPolling.d.ts +45 -0
  87. package/dist/v2/react/hooks/usePaymentPolling.js +153 -0
  88. package/dist/v2/react/hooks/usePaymentQuery.d.ts +19 -0
  89. package/dist/v2/react/hooks/usePaymentQuery.js +283 -0
  90. package/dist/v2/react/hooks/usePluginConfig.d.ts +16 -0
  91. package/dist/v2/react/hooks/usePluginConfig.js +36 -0
  92. package/dist/v2/react/hooks/usePostPurchasesQuery.d.ts +63 -0
  93. package/dist/v2/react/hooks/usePostPurchasesQuery.js +365 -0
  94. package/dist/v2/react/hooks/useProductsQuery.d.ts +31 -0
  95. package/dist/v2/react/hooks/useProductsQuery.js +102 -0
  96. package/dist/v2/react/hooks/usePromotionsQuery.d.ts +28 -0
  97. package/dist/v2/react/hooks/usePromotionsQuery.js +97 -0
  98. package/dist/v2/react/hooks/useThreeds.d.ts +36 -0
  99. package/dist/v2/react/hooks/useThreeds.js +166 -0
  100. package/dist/v2/react/hooks/useThreedsModal.d.ts +13 -0
  101. package/dist/v2/react/hooks/useThreedsModal.js +343 -0
  102. package/dist/v2/react/index.d.ts +38 -0
  103. package/dist/v2/react/index.js +27 -0
  104. package/dist/v2/react/providers/TagadaProvider.d.ts +63 -0
  105. package/dist/v2/react/providers/TagadaProvider.js +680 -0
  106. package/package.json +10 -3
@@ -0,0 +1,153 @@
1
+ import { useCallback, useRef, useEffect, useMemo } from 'react';
2
+ import { PaymentsResource } from '../../core/resources/payments';
3
+ import { getGlobalApiClient } from './useApiQuery';
4
+ export function usePaymentPolling() {
5
+ const pollIntervalRef = useRef(null);
6
+ const attemptsRef = useRef(0);
7
+ const isPollingRef = useRef(false);
8
+ const isMountedRef = useRef(true);
9
+ const currentPaymentIdRef = useRef(null);
10
+ // Create payments resource client
11
+ const paymentsResource = useMemo(() => {
12
+ try {
13
+ return new PaymentsResource(getGlobalApiClient());
14
+ }
15
+ catch (error) {
16
+ throw new Error('Failed to initialize payments resource: ' + (error instanceof Error ? error.message : 'Unknown error'));
17
+ }
18
+ }, []);
19
+ // Track mounted state and cleanup
20
+ useEffect(() => {
21
+ isMountedRef.current = true;
22
+ return () => {
23
+ isMountedRef.current = false;
24
+ stopPolling();
25
+ };
26
+ }, []);
27
+ const stopPolling = useCallback(() => {
28
+ if (pollIntervalRef.current) {
29
+ clearInterval(pollIntervalRef.current);
30
+ pollIntervalRef.current = null;
31
+ }
32
+ isPollingRef.current = false;
33
+ currentPaymentIdRef.current = null;
34
+ if (isMountedRef.current) {
35
+ console.log('Stopped polling payment status');
36
+ }
37
+ }, []);
38
+ const startPolling = useCallback((paymentId, options = {}) => {
39
+ if (!paymentId) {
40
+ console.error('Cannot poll payment status: paymentId is missing');
41
+ return { stop: stopPolling, isPolling: () => false };
42
+ }
43
+ // Prevent multiple polling sessions for the same payment
44
+ if (currentPaymentIdRef.current === paymentId && isPollingRef.current) {
45
+ console.log('Already polling for payment:', paymentId);
46
+ return { stop: stopPolling, isPolling: () => isPollingRef.current };
47
+ }
48
+ // Clean up any existing polling
49
+ stopPolling();
50
+ // Don't start polling if component is unmounted
51
+ if (!isMountedRef.current) {
52
+ console.log('Component unmounted, skipping polling start');
53
+ return { stop: stopPolling, isPolling: () => false };
54
+ }
55
+ // Reset attempts counter and set current payment
56
+ attemptsRef.current = 0;
57
+ isPollingRef.current = true;
58
+ currentPaymentIdRef.current = paymentId;
59
+ const { onRequireAction, onSuccess, onFailure, maxAttempts = 20, pollInterval = 1500 } = options;
60
+ console.log('Starting to poll payment status for:', paymentId);
61
+ const checkPaymentStatus = async () => {
62
+ // Stop if component was unmounted or polling was stopped
63
+ if (!isMountedRef.current || !isPollingRef.current) {
64
+ return;
65
+ }
66
+ try {
67
+ attemptsRef.current++;
68
+ console.log(`Polling attempt ${attemptsRef.current}/${maxAttempts} for payment ${paymentId}`);
69
+ const payment = await paymentsResource.getPaymentStatus(paymentId);
70
+ // Check again after async operation
71
+ if (!isMountedRef.current || !isPollingRef.current) {
72
+ return;
73
+ }
74
+ // Type guard and validation
75
+ if (!payment?.id) {
76
+ console.warn('Invalid payment response received');
77
+ return;
78
+ }
79
+ console.log('Payment status update:', payment);
80
+ // Check if payment requires action
81
+ if (payment.requireAction !== 'none' && payment.requireActionData) {
82
+ console.log('Payment requires new action, handling...');
83
+ stopPolling();
84
+ if (isMountedRef.current && onRequireAction) {
85
+ onRequireAction(payment, stopPolling);
86
+ }
87
+ return;
88
+ }
89
+ // Check for successful payment
90
+ if (payment.status === 'succeeded' ||
91
+ (payment.status === 'pending' && payment.subStatus === 'authorized')) {
92
+ console.log('Payment succeeded, stopping polling');
93
+ stopPolling();
94
+ if (isMountedRef.current && onSuccess) {
95
+ onSuccess(payment);
96
+ }
97
+ return;
98
+ }
99
+ // Check for failed payment (non-succeeded and not pending)
100
+ if (payment.status !== 'succeeded' && payment.status !== 'pending') {
101
+ console.log('Payment failed, stopping polling');
102
+ stopPolling();
103
+ if (isMountedRef.current && onFailure) {
104
+ onFailure(payment.status || 'Payment failed');
105
+ }
106
+ return;
107
+ }
108
+ // Stop after max attempts
109
+ if (attemptsRef.current >= maxAttempts) {
110
+ console.log('Reached maximum polling attempts');
111
+ stopPolling();
112
+ if (isMountedRef.current && onFailure) {
113
+ onFailure('Payment verification timeout');
114
+ }
115
+ }
116
+ }
117
+ catch (error) {
118
+ console.error('Error checking payment status:', error);
119
+ // Stop polling on repeated errors to prevent infinite loops
120
+ if (attemptsRef.current >= 3) {
121
+ console.log('Multiple errors encountered, stopping polling');
122
+ stopPolling();
123
+ if (isMountedRef.current && onFailure) {
124
+ onFailure('Payment verification failed due to network errors');
125
+ }
126
+ }
127
+ // Continue polling for occasional errors
128
+ }
129
+ };
130
+ // Start polling immediately, but check if still mounted
131
+ if (isMountedRef.current && isPollingRef.current) {
132
+ void checkPaymentStatus();
133
+ pollIntervalRef.current = setInterval(() => {
134
+ if (isMountedRef.current && isPollingRef.current) {
135
+ void checkPaymentStatus();
136
+ }
137
+ else {
138
+ stopPolling();
139
+ }
140
+ }, pollInterval);
141
+ }
142
+ // Return control object
143
+ return {
144
+ stop: stopPolling,
145
+ isPolling: () => isPollingRef.current && isMountedRef.current,
146
+ };
147
+ }, [paymentsResource, stopPolling]);
148
+ return {
149
+ startPolling,
150
+ stopPolling,
151
+ isPolling: () => isPollingRef.current && isMountedRef.current,
152
+ };
153
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Payment Hook using TanStack Query (V2)
3
+ * Matches the old usePayment.ts implementation exactly for easy migration
4
+ */
5
+ import type { PaymentResponse, PaymentOptions, CardPaymentMethod, ApplePayToken, PaymentInstrumentResponse, PaymentInstrumentCustomerResponse } from '../../core/resources/payments';
6
+ export type { Payment as PaymentType, PaymentResponse, PaymentOptions, CardPaymentMethod, ApplePayToken, PaymentInstrumentResponse, PaymentInstrumentCustomerResponse, PaymentInstrumentCustomer } from '../../core/resources/payments';
7
+ export interface PaymentHook {
8
+ processCardPayment: (checkoutSessionId: string, cardData: CardPaymentMethod, options?: PaymentOptions) => Promise<PaymentResponse>;
9
+ processApplePayPayment: (checkoutSessionId: string, applePayToken: ApplePayToken, options?: PaymentOptions) => Promise<PaymentResponse>;
10
+ processPaymentWithInstrument: (checkoutSessionId: string, paymentInstrumentId: string, options?: PaymentOptions) => Promise<PaymentResponse>;
11
+ createCardPaymentInstrument: (cardData: CardPaymentMethod) => Promise<PaymentInstrumentResponse>;
12
+ createApplePayPaymentInstrument: (applePayToken: ApplePayToken) => Promise<PaymentInstrumentResponse>;
13
+ getCardPaymentInstruments: () => Promise<PaymentInstrumentCustomerResponse>;
14
+ isLoading: boolean;
15
+ error: string | null;
16
+ clearError: () => void;
17
+ currentPaymentId: string | null;
18
+ }
19
+ export declare function usePaymentQuery(): PaymentHook;
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Payment Hook using TanStack Query (V2)
3
+ * Matches the old usePayment.ts implementation exactly for easy migration
4
+ */
5
+ import { useState, useCallback, useMemo, useRef, useEffect } from 'react';
6
+ import { useBasisTheory } from '@basis-theory/basis-theory-react';
7
+ import { getBasisTheoryApiKey } from '../../../react/config/payment';
8
+ import { useTagadaContext } from '../providers/TagadaProvider';
9
+ import { PaymentsResource } from '../../core/resources/payments';
10
+ import { usePaymentPolling } from './usePaymentPolling';
11
+ import { useThreeds } from './useThreeds';
12
+ import { getGlobalApiClient } from './useApiQuery';
13
+ export function usePaymentQuery() {
14
+ const { environment } = useTagadaContext();
15
+ // Create payments resource client
16
+ const paymentsResource = useMemo(() => {
17
+ try {
18
+ return new PaymentsResource(getGlobalApiClient());
19
+ }
20
+ catch (error) {
21
+ throw new Error('Failed to initialize payments resource: ' + (error instanceof Error ? error.message : 'Unknown error'));
22
+ }
23
+ }, []);
24
+ const [isLoading, setIsLoading] = useState(false);
25
+ const [error, setError] = useState(null);
26
+ const [currentPaymentId, setCurrentPaymentId] = useState(null);
27
+ const { startPolling, stopPolling } = usePaymentPolling();
28
+ const { createSession, startChallenge } = useThreeds();
29
+ // Track challenge in progress to prevent multiple challenges
30
+ const challengeInProgressRef = useRef(false);
31
+ // Stabilize environment value to prevent re-renders
32
+ const currentEnvironment = useMemo(() => environment?.environment || 'local', [environment?.environment]);
33
+ // Get API key from embedded configuration with proper environment detection
34
+ const apiKey = useMemo(() => getBasisTheoryApiKey(currentEnvironment), [currentEnvironment]);
35
+ // Initialize BasisTheory using React wrapper
36
+ const { bt: basisTheory, error: btError } = useBasisTheory(apiKey, {
37
+ elements: false,
38
+ });
39
+ // Handle BasisTheory initialization errors (only log once when state changes)
40
+ useEffect(() => {
41
+ if (btError) {
42
+ console.error('BasisTheory initialization error:', btError);
43
+ setError('Failed to initialize payment processor: ' + btError.message);
44
+ }
45
+ else if (basisTheory && !error) {
46
+ console.log('✅ BasisTheory initialized successfully');
47
+ setError(null); // Clear any previous errors
48
+ }
49
+ }, [basisTheory, btError]); // Removed error from dependency to prevent loops
50
+ // Clean up polling when component unmounts
51
+ useEffect(() => {
52
+ return () => {
53
+ stopPolling();
54
+ };
55
+ }, [stopPolling]);
56
+ // Handle payment actions (3DS, redirects, etc.) - matches old implementation
57
+ const handlePaymentAction = useCallback(async (payment, options = {}) => {
58
+ if (payment.requireAction === 'none')
59
+ return;
60
+ if (payment?.requireActionData?.processed)
61
+ return;
62
+ const actionData = payment.requireActionData;
63
+ if (!actionData)
64
+ return;
65
+ // Mark action as processed
66
+ try {
67
+ await paymentsResource.markPaymentActionProcessed(payment.id);
68
+ }
69
+ catch (error) {
70
+ console.error('Error setting payment action as processed', error);
71
+ }
72
+ console.log('Processing payment action:', actionData.type);
73
+ switch (actionData.type) {
74
+ case 'threeds_auth':
75
+ if (actionData.metadata?.threedsSession && !challengeInProgressRef.current) {
76
+ try {
77
+ challengeInProgressRef.current = true;
78
+ console.log('Starting 3DS challenge...');
79
+ await startChallenge({
80
+ sessionId: actionData.metadata.threedsSession.externalSessionId,
81
+ acsChallengeUrl: actionData.metadata.threedsSession.acsChallengeUrl,
82
+ acsTransactionId: actionData.metadata.threedsSession.acsTransID,
83
+ threeDSVersion: actionData.metadata.threedsSession.messageVersion,
84
+ }, { provider: options.threedsProvider || 'basis_theory' });
85
+ challengeInProgressRef.current = false;
86
+ console.log('3DS challenge completed');
87
+ // Start polling after challenge completion
88
+ if (payment.id) {
89
+ startPolling(payment.id, {
90
+ onRequireAction: (updatedPayment) => {
91
+ void handlePaymentAction(updatedPayment, options);
92
+ },
93
+ onSuccess: (successPayment) => {
94
+ setIsLoading(false);
95
+ options.onSuccess?.({
96
+ paymentId: successPayment.id,
97
+ payment: successPayment,
98
+ });
99
+ },
100
+ onFailure: (errorMsg) => {
101
+ console.error('Payment failed:', errorMsg);
102
+ setError(errorMsg);
103
+ setIsLoading(false);
104
+ options.onFailure?.(errorMsg);
105
+ },
106
+ });
107
+ }
108
+ }
109
+ catch (error) {
110
+ challengeInProgressRef.current = false;
111
+ console.error('Error starting 3DS challenge:', error);
112
+ const errorMsg = error instanceof Error ? error.message : 'Failed to start 3DS challenge';
113
+ setError(errorMsg);
114
+ setIsLoading(false);
115
+ options.onFailure?.(errorMsg);
116
+ }
117
+ }
118
+ break;
119
+ case 'processor_auth':
120
+ case 'redirect': {
121
+ if (actionData.metadata?.redirect?.redirectUrl) {
122
+ window.location.href = actionData.metadata.redirect.redirectUrl;
123
+ }
124
+ break;
125
+ }
126
+ case 'error': {
127
+ const errorMsg = actionData.message || 'Payment processing failed';
128
+ setError(errorMsg);
129
+ setIsLoading(false);
130
+ options.onFailure?.(errorMsg);
131
+ break;
132
+ }
133
+ }
134
+ options.onRequireAction?.(payment);
135
+ }, [paymentsResource, startPolling, startChallenge]);
136
+ // Create card payment instrument - matches old implementation
137
+ const createCardPaymentInstrument = useCallback((cardData) => {
138
+ return paymentsResource.createCardPaymentInstrument(basisTheory, cardData);
139
+ }, [basisTheory, paymentsResource]);
140
+ // Create Apple Pay payment instrument - matches old implementation
141
+ const createApplePayPaymentInstrument = useCallback((applePayToken) => {
142
+ return paymentsResource.createApplePayPaymentInstrument(basisTheory, applePayToken);
143
+ }, [basisTheory, paymentsResource]);
144
+ // Process payment directly with checkout session - matches old implementation
145
+ const processPaymentDirect = useCallback(async (checkoutSessionId, paymentInstrumentId, threedsSessionId, options = {}) => {
146
+ try {
147
+ const response = await paymentsResource.processPaymentDirect(checkoutSessionId, paymentInstrumentId, threedsSessionId, {
148
+ initiatedBy: options.initiatedBy,
149
+ source: options.source,
150
+ });
151
+ console.log('Payment response:', response);
152
+ setCurrentPaymentId(response.payment?.id);
153
+ if (response.payment.requireAction !== 'none') {
154
+ await handlePaymentAction(response.payment, options);
155
+ }
156
+ else if (response.payment.status === 'succeeded') {
157
+ setIsLoading(false);
158
+ options.onSuccess?.(response);
159
+ }
160
+ else {
161
+ // Start polling for payment status
162
+ startPolling(response.payment?.id, {
163
+ onRequireAction: (payment) => {
164
+ void handlePaymentAction(payment, options);
165
+ },
166
+ onSuccess: (payment) => {
167
+ setIsLoading(false);
168
+ options.onSuccess?.({
169
+ paymentId: payment.id,
170
+ payment,
171
+ });
172
+ },
173
+ onFailure: (errorMsg) => {
174
+ console.error('Payment failed:', errorMsg);
175
+ setError(errorMsg);
176
+ setIsLoading(false);
177
+ options.onFailure?.(errorMsg);
178
+ },
179
+ });
180
+ }
181
+ return response;
182
+ }
183
+ catch (error) {
184
+ const errorMsg = error instanceof Error ? error.message : 'Payment failed';
185
+ setError(errorMsg);
186
+ setIsLoading(false);
187
+ options.onFailure?.(errorMsg);
188
+ throw error;
189
+ }
190
+ }, [paymentsResource, handlePaymentAction, startPolling]);
191
+ // Process card payment - matches old implementation
192
+ const processCardPayment = useCallback(async (checkoutSessionId, cardData, options = {}) => {
193
+ setIsLoading(true);
194
+ setError(null);
195
+ try {
196
+ // 1. Create payment instrument
197
+ const paymentInstrument = await createCardPaymentInstrument(cardData);
198
+ // 2. Create 3DS session if enabled
199
+ let threedsSessionId;
200
+ if (options.enableThreeds !== false) {
201
+ try {
202
+ const threedsSession = await createSession(paymentInstrument, {
203
+ provider: options.threedsProvider || 'basis_theory',
204
+ });
205
+ threedsSessionId = threedsSession.id;
206
+ }
207
+ catch (error) {
208
+ console.warn('Failed to create 3DS session, proceeding without 3DS:', error);
209
+ }
210
+ }
211
+ // 3. Process payment directly
212
+ return await processPaymentDirect(checkoutSessionId, paymentInstrument.id, threedsSessionId, options);
213
+ }
214
+ catch (error) {
215
+ setIsLoading(false);
216
+ const errorMsg = error instanceof Error ? error.message : 'Payment failed';
217
+ setError(errorMsg);
218
+ options.onFailure?.(errorMsg);
219
+ throw error;
220
+ }
221
+ }, [createCardPaymentInstrument, createSession, processPaymentDirect]);
222
+ // Process Apple Pay payment - matches old implementation
223
+ const processApplePayPayment = useCallback(async (checkoutSessionId, applePayToken, options = {}) => {
224
+ setIsLoading(true);
225
+ setError(null);
226
+ try {
227
+ // 1. Create payment instrument
228
+ const paymentInstrument = await createApplePayPaymentInstrument(applePayToken);
229
+ // 2. Process payment directly (Apple Pay typically doesn't require 3DS)
230
+ return await processPaymentDirect(checkoutSessionId, paymentInstrument.id, undefined, options);
231
+ }
232
+ catch (error) {
233
+ setIsLoading(false);
234
+ const errorMsg = error instanceof Error ? error.message : 'Apple Pay payment failed';
235
+ setError(errorMsg);
236
+ options.onFailure?.(errorMsg);
237
+ throw error;
238
+ }
239
+ }, [createApplePayPaymentInstrument, processPaymentDirect]);
240
+ // Process payment with existing instrument - matches old implementation
241
+ const processPaymentWithInstrument = useCallback(async (checkoutSessionId, paymentInstrumentId, options = {}) => {
242
+ setIsLoading(true);
243
+ setError(null);
244
+ try {
245
+ return await processPaymentDirect(checkoutSessionId, paymentInstrumentId, undefined, options);
246
+ }
247
+ catch (error) {
248
+ setIsLoading(false);
249
+ const errorMsg = error instanceof Error ? error.message : 'Payment failed';
250
+ setError(errorMsg);
251
+ options.onFailure?.(errorMsg);
252
+ throw error;
253
+ }
254
+ }, [processPaymentDirect]);
255
+ // Get card payment instruments - matches old implementation
256
+ const getCardPaymentInstruments = useCallback(async () => {
257
+ try {
258
+ const response = await paymentsResource.getCardPaymentInstruments();
259
+ return response;
260
+ }
261
+ catch (error) {
262
+ console.error('Error fetching card payment instruments:', error);
263
+ const errorMsg = error instanceof Error ? error.message : 'Failed to fetch payment instruments';
264
+ setError(errorMsg);
265
+ throw error;
266
+ }
267
+ }, [paymentsResource]);
268
+ const clearError = useCallback(() => {
269
+ setError(null);
270
+ }, []);
271
+ return {
272
+ processCardPayment,
273
+ processApplePayPayment,
274
+ processPaymentWithInstrument,
275
+ createCardPaymentInstrument,
276
+ createApplePayPaymentInstrument,
277
+ getCardPaymentInstruments,
278
+ isLoading: isLoading || !basisTheory, // Indicate loading if BasisTheory is not initialized
279
+ error,
280
+ clearError,
281
+ currentPaymentId,
282
+ };
283
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Plugin Configuration Hook
3
+ * Uses PluginConfigUtils for business logic
4
+ */
5
+ import { PluginConfig, RawPluginConfig } from '../../core/utils/pluginConfig';
6
+ export interface UsePluginConfigOptions {
7
+ rawConfig?: RawPluginConfig;
8
+ }
9
+ export interface UsePluginConfigResult<TConfig = Record<string, any>> {
10
+ config: PluginConfig<TConfig>;
11
+ storeId?: string;
12
+ accountId?: string;
13
+ basePath?: string;
14
+ isValid: boolean;
15
+ }
16
+ export declare function usePluginConfig<TConfig = Record<string, any>>(options?: UsePluginConfigOptions): UsePluginConfigResult<TConfig>;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Plugin Configuration Hook
3
+ * Uses PluginConfigUtils for business logic
4
+ */
5
+ import { useMemo } from 'react';
6
+ import { useTagadaContext } from '../providers/TagadaProvider';
7
+ import { PluginConfigUtils } from '../../core/utils/pluginConfig';
8
+ export function usePluginConfig(options = {}) {
9
+ const { pluginConfig } = useTagadaContext();
10
+ const config = useMemo(() => {
11
+ const baseConfig = PluginConfigUtils.getPluginConfig(options.rawConfig, {
12
+ storeId: pluginConfig.storeId,
13
+ accountId: pluginConfig.accountId,
14
+ basePath: pluginConfig.basePath,
15
+ });
16
+ // Merge config properties from the loaded plugin config
17
+ return {
18
+ ...baseConfig,
19
+ ...pluginConfig.config,
20
+ storeId: pluginConfig.storeId,
21
+ accountId: pluginConfig.accountId,
22
+ basePath: pluginConfig.basePath,
23
+ };
24
+ }, [options.rawConfig, pluginConfig]);
25
+ const isValid = useMemo(() => {
26
+ return PluginConfigUtils.validateConfig(config);
27
+ }, [config]);
28
+ console.log('🔍 [usePluginConfig] Config:', config);
29
+ return {
30
+ config,
31
+ storeId: config.storeId,
32
+ accountId: config.accountId,
33
+ basePath: config.basePath,
34
+ isValid,
35
+ };
36
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Post Purchases Hook using TanStack Query
3
+ * Handles post-purchase offers with automatic caching
4
+ */
5
+ import { PostPurchaseOffer, PostPurchaseOfferItem, PostPurchaseOfferSummary, CheckoutSessionState, OrderSummary, CurrencyOptions } from '../../core/resources/postPurchases';
6
+ export interface UsePostPurchasesQueryOptions {
7
+ orderId: string;
8
+ enabled?: boolean;
9
+ autoInitializeCheckout?: boolean;
10
+ }
11
+ export interface UsePostPurchasesQueryResult {
12
+ offers: PostPurchaseOffer[];
13
+ isLoading: boolean;
14
+ error: Error | null;
15
+ acceptOffer: (offerId: string, items: PostPurchaseOfferItem[]) => Promise<{
16
+ success: boolean;
17
+ summary?: PostPurchaseOfferSummary;
18
+ error?: string;
19
+ }>;
20
+ declineOffer: (offerId: string) => Promise<{
21
+ success: boolean;
22
+ error?: string;
23
+ }>;
24
+ previewOffer: (offerId: string, items: PostPurchaseOfferItem[]) => Promise<{
25
+ success: boolean;
26
+ summary?: PostPurchaseOfferSummary;
27
+ error?: string;
28
+ }>;
29
+ refresh: () => void;
30
+ payWithCheckoutSession: (checkoutSessionId: string, orderId?: string) => Promise<void>;
31
+ initCheckoutSession: (offerId: string, orderId: string) => Promise<{
32
+ checkoutSessionId: string;
33
+ }>;
34
+ initCheckoutSessionWithVariants: (offerId: string, orderId: string, lineItems: {
35
+ variantId: string;
36
+ quantity: number;
37
+ }[]) => Promise<{
38
+ checkoutSessionId: string;
39
+ }>;
40
+ getOffer: (offerId: string) => PostPurchaseOffer | undefined;
41
+ getTotalValue: () => number;
42
+ getTotalSavings: () => number;
43
+ getCheckoutSessionState: (offerId: string) => CheckoutSessionState | null;
44
+ initializeOfferCheckout: (offerId: string) => Promise<void>;
45
+ getAvailableVariants: (offerId: string, productId: string) => {
46
+ variantId: string;
47
+ variantName: string;
48
+ variantSku: string | null;
49
+ variantDefault: boolean | null;
50
+ variantExternalId: string | null;
51
+ priceId: string;
52
+ currencyOptions: CurrencyOptions;
53
+ }[];
54
+ selectVariant: (offerId: string, productId: string, variantId: string) => Promise<void>;
55
+ getOrderSummary: (offerId: string) => OrderSummary | null;
56
+ isLoadingVariants: (offerId: string, productId: string) => boolean;
57
+ isUpdatingOrderSummary: (offerId: string) => boolean;
58
+ confirmPurchase: (offerId: string, options?: {
59
+ draft?: boolean;
60
+ returnUrl?: string;
61
+ }) => Promise<void>;
62
+ }
63
+ export declare function usePostPurchasesQuery(options: UsePostPurchasesQueryOptions): UsePostPurchasesQueryResult;