@tagadapay/plugin-sdk 3.1.24 → 4.0.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.
- package/README.md +1129 -1129
- package/build-cdn.js +499 -499
- package/dist/external-tracker.js +247 -2875
- package/dist/external-tracker.min.js +2 -2
- package/dist/external-tracker.min.js.map +4 -4
- package/dist/react/config/payment.d.ts +2 -2
- package/dist/react/config/payment.js +5 -5
- package/dist/react/hooks/useCheckout.js +7 -2
- package/dist/react/hooks/usePayment.d.ts +7 -0
- package/dist/react/hooks/usePayment.js +1 -0
- package/dist/react/providers/TagadaProvider.js +5 -5
- package/dist/tagada-react-sdk-minimal.min.js +2 -2
- package/dist/tagada-react-sdk-minimal.min.js.map +4 -4
- package/dist/tagada-react-sdk.js +1680 -1172
- package/dist/tagada-react-sdk.min.js +2 -2
- package/dist/tagada-react-sdk.min.js.map +4 -4
- package/dist/tagada-sdk.js +1701 -3410
- package/dist/tagada-sdk.min.js +2 -2
- package/dist/tagada-sdk.min.js.map +4 -4
- package/dist/v2/core/client.js +1 -0
- package/dist/v2/core/config/environment.d.ts +3 -3
- package/dist/v2/core/config/environment.js +7 -7
- package/dist/v2/core/funnelClient.d.ts +10 -0
- package/dist/v2/core/funnelClient.js +1 -1
- package/dist/v2/core/resources/apiClient.d.ts +18 -14
- package/dist/v2/core/resources/apiClient.js +151 -109
- package/dist/v2/core/resources/checkout.d.ts +1 -1
- package/dist/v2/core/resources/funnel.d.ts +1 -1
- package/dist/v2/core/resources/geo.d.ts +50 -0
- package/dist/v2/core/resources/geo.js +35 -0
- package/dist/v2/core/resources/index.d.ts +1 -1
- package/dist/v2/core/resources/index.js +1 -1
- package/dist/v2/core/resources/offers.js +4 -4
- package/dist/v2/core/resources/payments.d.ts +20 -1
- package/dist/v2/core/resources/payments.js +8 -0
- package/dist/v2/core/utils/currency.d.ts +3 -0
- package/dist/v2/core/utils/currency.js +40 -2
- package/dist/v2/core/utils/deviceInfo.d.ts +1 -0
- package/dist/v2/core/utils/deviceInfo.js +1 -0
- package/dist/v2/core/utils/previewMode.js +12 -0
- package/dist/v2/core/utils/previewModeIndicator.js +101 -101
- package/dist/v2/react/components/ApplePayButton.js +39 -16
- package/dist/v2/react/components/FunnelScriptInjector.js +167 -19
- package/dist/v2/react/components/StripeExpressButton.d.ts +8 -0
- package/dist/v2/react/components/StripeExpressButton.js +23 -3
- package/dist/v2/react/hooks/payment-actions/useAirwallexRadarAction.js +1 -0
- package/dist/v2/react/hooks/payment-actions/useNgeniusThreedsAction.d.ts +15 -0
- package/dist/v2/react/hooks/payment-actions/useNgeniusThreedsAction.js +166 -0
- package/dist/v2/react/hooks/payment-actions/usePaymentActionHandler.js +12 -0
- package/dist/v2/react/hooks/payment-processing/usePaymentProcessors.js +1 -0
- package/dist/v2/react/hooks/useApiQuery.d.ts +1 -1
- package/dist/v2/react/hooks/useApiQuery.js +1 -1
- package/dist/v2/react/hooks/useCheckoutQuery.js +6 -2
- package/dist/v2/react/hooks/useISOData.js +25 -7
- package/dist/v2/react/hooks/usePaymentPolling.d.ts +1 -1
- package/dist/v2/react/hooks/usePreviewOffer.js +1 -1
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +7 -0
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +105 -9
- package/dist/v2/react/providers/TagadaProvider.js +6 -6
- package/dist/v2/standalone/apple-pay-service.d.ts +12 -0
- package/dist/v2/standalone/apple-pay-service.js +12 -0
- package/dist/v2/standalone/external-tracker.d.ts +1 -1
- package/dist/v2/standalone/google-pay-service.d.ts +9 -0
- package/dist/v2/standalone/google-pay-service.js +9 -0
- package/dist/v2/standalone/index.d.ts +8 -1
- package/dist/v2/standalone/index.js +7 -0
- package/dist/v2/standalone/payment-service.d.ts +18 -5
- package/dist/v2/standalone/payment-service.js +63 -9
- package/package.json +115 -114
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { useMemo, useEffect, useState, useCallback } from 'react';
|
|
2
|
-
import { getCountries, getStatesForCountry, ensureGeoDataLoaded, importLanguage, isLanguageRegistered, getRegisteredLanguages } from '../../../data/iso3166';
|
|
2
|
+
import { getCountries, getStatesForCountry, ensureGeoDataLoaded, AVAILABLE_LANGUAGES, importLanguage, isLanguageRegistered, getRegisteredLanguages } from '../../../data/iso3166';
|
|
3
3
|
/**
|
|
4
4
|
* React hook for accessing ISO3166 countries and regions data.
|
|
5
5
|
* Fetches slim JSON from CDN on first use, then caches in memory.
|
|
6
6
|
*/
|
|
7
7
|
export function useISOData(language = 'en', autoImport = true, disputeSetting = 'UN') {
|
|
8
|
-
|
|
8
|
+
// Normalize: if the caller passed an unsupported locale (e.g. 'nl'),
|
|
9
|
+
// silently fall back to English so the country dropdown still renders.
|
|
10
|
+
// The CDN only hosts languages listed in AVAILABLE_LANGUAGES; any other
|
|
11
|
+
// value would 404 and leave `isLanguageLoaded` stuck on false.
|
|
12
|
+
const effectiveLanguage = AVAILABLE_LANGUAGES.includes(language) ? language : 'en';
|
|
13
|
+
const [isLanguageLoaded, setIsLanguageLoaded] = useState(isLanguageRegistered(effectiveLanguage));
|
|
9
14
|
const [registeredLanguages, setRegisteredLanguages] = useState(getRegisteredLanguages);
|
|
10
15
|
// Fetch geodata from CDN (countries + regions) for the requested language
|
|
11
16
|
useEffect(() => {
|
|
12
17
|
let cancelled = false;
|
|
13
|
-
ensureGeoDataLoaded(
|
|
18
|
+
ensureGeoDataLoaded(effectiveLanguage)
|
|
14
19
|
.then(() => {
|
|
15
20
|
if (!cancelled) {
|
|
16
21
|
setIsLanguageLoaded(true);
|
|
@@ -19,9 +24,22 @@ export function useISOData(language = 'en', autoImport = true, disputeSetting =
|
|
|
19
24
|
})
|
|
20
25
|
.catch((err) => {
|
|
21
26
|
console.error('[SDK] Failed to load geodata from CDN:', err);
|
|
27
|
+
if (cancelled)
|
|
28
|
+
return;
|
|
29
|
+
// English is prefetched on module load (iso3166.ts). If it
|
|
30
|
+
// landed, unblock the UI — getCountriesCached() falls back to 'en'.
|
|
31
|
+
if (isLanguageRegistered('en')) {
|
|
32
|
+
setIsLanguageLoaded(true);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Otherwise try one last English fetch as ultimate fallback.
|
|
36
|
+
ensureGeoDataLoaded('en')
|
|
37
|
+
.then(() => { if (!cancelled)
|
|
38
|
+
setIsLanguageLoaded(true); })
|
|
39
|
+
.catch(() => { });
|
|
22
40
|
});
|
|
23
41
|
return () => { cancelled = true; };
|
|
24
|
-
}, [
|
|
42
|
+
}, [effectiveLanguage, autoImport]);
|
|
25
43
|
const data = useMemo(() => {
|
|
26
44
|
if (!isLanguageLoaded) {
|
|
27
45
|
return {
|
|
@@ -34,7 +52,7 @@ export function useISOData(language = 'en', autoImport = true, disputeSetting =
|
|
|
34
52
|
};
|
|
35
53
|
}
|
|
36
54
|
try {
|
|
37
|
-
const countriesArray = getCountries(
|
|
55
|
+
const countriesArray = getCountries(effectiveLanguage);
|
|
38
56
|
const countries = {};
|
|
39
57
|
countriesArray.forEach((country) => {
|
|
40
58
|
countries[country.code] = {
|
|
@@ -46,7 +64,7 @@ export function useISOData(language = 'en', autoImport = true, disputeSetting =
|
|
|
46
64
|
});
|
|
47
65
|
const getRegions = (countryCode) => {
|
|
48
66
|
try {
|
|
49
|
-
const states = getStatesForCountry(countryCode,
|
|
67
|
+
const states = getStatesForCountry(countryCode, effectiveLanguage);
|
|
50
68
|
return states.map((state) => ({
|
|
51
69
|
iso: state.code,
|
|
52
70
|
name: state.name,
|
|
@@ -97,7 +115,7 @@ export function useISOData(language = 'en', autoImport = true, disputeSetting =
|
|
|
97
115
|
registeredLanguages,
|
|
98
116
|
};
|
|
99
117
|
}
|
|
100
|
-
}, [
|
|
118
|
+
}, [effectiveLanguage, disputeSetting, isLanguageLoaded, registeredLanguages]);
|
|
101
119
|
return data;
|
|
102
120
|
}
|
|
103
121
|
/**
|
|
@@ -4,7 +4,7 @@ export interface Payment {
|
|
|
4
4
|
subStatus: string;
|
|
5
5
|
requireAction: 'none' | 'redirect' | 'redirect_to_payment' | 'error' | 'radar' | 'stripe_express_checkout';
|
|
6
6
|
requireActionData?: {
|
|
7
|
-
type: 'redirect' | 'redirect_to_payment' | 'threeds_auth' | 'processor_auth' | 'error' | 'stripe_radar' | 'finix_radar' | 'radar' | 'kesspay_auth' | 'trustflow_auth' | 'mastercard_auth' | 'stripe_express_checkout';
|
|
7
|
+
type: 'redirect' | 'redirect_to_payment' | 'threeds_auth' | 'processor_auth' | 'error' | 'stripe_radar' | 'finix_radar' | 'radar' | 'kesspay_auth' | 'trustflow_auth' | 'mastercard_auth' | 'ngenius_3ds' | 'stripe_express_checkout';
|
|
8
8
|
url?: string;
|
|
9
9
|
processed: boolean;
|
|
10
10
|
processorId?: string;
|
|
@@ -12,7 +12,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
|
12
12
|
import { OffersResource } from '../../core/resources/offers';
|
|
13
13
|
import { getGlobalApiClient } from './useApiQuery';
|
|
14
14
|
export function usePreviewOffer(options) {
|
|
15
|
-
const { offerId, currency: requestedCurrency = '
|
|
15
|
+
const { offerId, currency: requestedCurrency = '', initialSelections = {} } = options;
|
|
16
16
|
const queryParamsCurrency = typeof window !== 'undefined'
|
|
17
17
|
? new URLSearchParams(window.location.search).get('currency') || undefined
|
|
18
18
|
: undefined;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Express Payment Methods Context Provider using v2 Architecture
|
|
3
3
|
* Manages express payment methods (Apple Pay, Google Pay, PayPal, Klarna)
|
|
4
|
+
*
|
|
5
|
+
* Payment methods are resolved from:
|
|
6
|
+
* 1. paymentSetupConfig prop (from __TGD_STEP_CONFIG__ or useStepConfig)
|
|
7
|
+
* 2. API fallback (GET /api/v1/payment-methods) for legacy integrations
|
|
4
8
|
*/
|
|
5
9
|
import React, { ReactNode } from 'react';
|
|
6
10
|
import { TagadaError } from '../../core/errors';
|
|
11
|
+
import type { PaymentSetupConfig } from '../../core/funnelClient';
|
|
7
12
|
import { CheckoutData } from '../../core/resources/checkout';
|
|
8
13
|
import { Address, PaymentMethod } from '../../core/resources/expressPaymentMethods';
|
|
9
14
|
type ExpressOrderLineItem = {
|
|
@@ -56,6 +61,8 @@ interface ExpressPaymentMethodsProviderProps {
|
|
|
56
61
|
children: ReactNode;
|
|
57
62
|
customerId?: string;
|
|
58
63
|
checkout?: CheckoutData;
|
|
64
|
+
/** Step-level payment config from __TGD_STEP_CONFIG__ / useStepConfig(). */
|
|
65
|
+
paymentSetupConfig?: PaymentSetupConfig;
|
|
59
66
|
}
|
|
60
67
|
export declare const ExpressPaymentMethodsContext: React.Context<ExpressPaymentMethodsContextType | undefined>;
|
|
61
68
|
export declare const ExpressPaymentMethodsProvider: React.FC<ExpressPaymentMethodsProviderProps>;
|
|
@@ -2,19 +2,74 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
/**
|
|
3
3
|
* Express Payment Methods Context Provider using v2 Architecture
|
|
4
4
|
* Manages express payment methods (Apple Pay, Google Pay, PayPal, Klarna)
|
|
5
|
+
*
|
|
6
|
+
* Payment methods are resolved from:
|
|
7
|
+
* 1. paymentSetupConfig prop (from __TGD_STEP_CONFIG__ or useStepConfig)
|
|
8
|
+
* 2. API fallback (GET /api/v1/payment-methods) for legacy integrations
|
|
5
9
|
*/
|
|
6
10
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
7
|
-
import { createContext, useCallback, useMemo, useState } from 'react';
|
|
11
|
+
import { createContext, useCallback, useEffect, useMemo, useState } from 'react';
|
|
8
12
|
import { TagadaError, TagadaErrorCode } from '../../core/errors';
|
|
9
13
|
import { ExpressPaymentMethodsResource, } from '../../core/resources/expressPaymentMethods';
|
|
10
14
|
import { getGlobalApiClient } from '../hooks/useApiQuery';
|
|
11
15
|
import { useShippingRatesQuery } from '../hooks/useShippingRatesQuery';
|
|
12
16
|
export const ExpressPaymentMethodsContext = createContext(undefined);
|
|
13
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Synthesize PaymentMethod[] from paymentSetupConfig entries.
|
|
19
|
+
* Converts express_checkout:processorId entries into the shape the provider expects.
|
|
20
|
+
*/
|
|
21
|
+
function paymentMethodsFromSetupConfig(config) {
|
|
22
|
+
const methods = [];
|
|
23
|
+
for (const [key, entry] of Object.entries(config)) {
|
|
24
|
+
if (!entry.enabled)
|
|
25
|
+
continue;
|
|
26
|
+
// express_checkout:processorId entries → synthesize a stripe_apm-style method
|
|
27
|
+
if (key.startsWith('express_checkout:') && entry.methods) {
|
|
28
|
+
methods.push({
|
|
29
|
+
id: key,
|
|
30
|
+
type: 'stripe_apm',
|
|
31
|
+
title: entry.label || 'Express Checkout',
|
|
32
|
+
iconUrl: entry.logoUrl || '',
|
|
33
|
+
default: false,
|
|
34
|
+
settings: {
|
|
35
|
+
publishableKey: entry.publishableKey,
|
|
36
|
+
processors: [{
|
|
37
|
+
processorId: entry.processorId,
|
|
38
|
+
methods: entry.methods,
|
|
39
|
+
}],
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
// Individual express methods (apple_pay, google_pay, etc.)
|
|
45
|
+
// Match by: explicit express flag, type, method, provider, or key name
|
|
46
|
+
const resolvedMethod = entry.method || entry.provider || key;
|
|
47
|
+
const isExpressMethod = entry.express
|
|
48
|
+
|| entry.type === 'apple_pay' || entry.type === 'google_pay'
|
|
49
|
+
|| resolvedMethod === 'apple_pay' || resolvedMethod === 'google_pay';
|
|
50
|
+
if (isExpressMethod) {
|
|
51
|
+
methods.push({
|
|
52
|
+
id: key,
|
|
53
|
+
type: entry.type === 'apple_pay' || entry.type === 'google_pay' ? entry.type : resolvedMethod,
|
|
54
|
+
title: entry.label || key,
|
|
55
|
+
iconUrl: entry.logoUrl || '',
|
|
56
|
+
default: false,
|
|
57
|
+
settings: { processorId: entry.processorId, publishableKey: entry.publishableKey },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return methods;
|
|
62
|
+
}
|
|
63
|
+
export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout, paymentSetupConfig, }) => {
|
|
14
64
|
const queryClient = useQueryClient();
|
|
15
65
|
const [availableExpressPaymentMethodIds, setAvailableExpressPaymentMethodIds] = useState([]);
|
|
16
66
|
const [error, setError] = useState(null);
|
|
17
67
|
const checkoutSessionId = checkout?.checkoutSession?.id;
|
|
68
|
+
// If paymentSetupConfig is provided AND contains at least one enabled method, derive from it.
|
|
69
|
+
// Missing, empty `{}`, or all-disabled configs fall through to the API fallback.
|
|
70
|
+
const configDerivedMethods = useMemo(() => (paymentSetupConfig && Object.values(paymentSetupConfig).some((v) => v?.enabled === true))
|
|
71
|
+
? paymentMethodsFromSetupConfig(paymentSetupConfig)
|
|
72
|
+
: undefined, [paymentSetupConfig]);
|
|
18
73
|
// Create express payment methods resource client
|
|
19
74
|
const expressPaymentResource = useMemo(() => {
|
|
20
75
|
try {
|
|
@@ -25,14 +80,15 @@ export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout,
|
|
|
25
80
|
(error instanceof Error ? error.message : 'Unknown error'));
|
|
26
81
|
}
|
|
27
82
|
}, []);
|
|
28
|
-
//
|
|
29
|
-
const { data:
|
|
83
|
+
// Only fetch from API when paymentSetupConfig is NOT provided
|
|
84
|
+
const { data: apiPaymentMethods, isLoading: isLoadingPaymentMethods } = useQuery({
|
|
30
85
|
queryKey: ['payment-methods', checkoutSessionId],
|
|
31
86
|
queryFn: () => expressPaymentResource.getPaymentMethods(checkoutSessionId),
|
|
32
|
-
enabled: !!checkoutSessionId,
|
|
33
|
-
staleTime: 60000,
|
|
87
|
+
enabled: !!checkoutSessionId && !configDerivedMethods,
|
|
88
|
+
staleTime: 60000,
|
|
34
89
|
refetchOnWindowFocus: false,
|
|
35
90
|
});
|
|
91
|
+
const paymentMethods = configDerivedMethods ?? apiPaymentMethods;
|
|
36
92
|
// Use v2 shipping rates hook
|
|
37
93
|
const { shippingRates, refetch: refetchRates } = useShippingRatesQuery({ checkout });
|
|
38
94
|
// Get order summary from checkout data
|
|
@@ -161,8 +217,48 @@ export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout,
|
|
|
161
217
|
return;
|
|
162
218
|
await updateEmailMutation.mutateAsync(input.data);
|
|
163
219
|
}, [customerId, updateEmailMutation]);
|
|
164
|
-
// Check if Apple Pay is available
|
|
165
|
-
const isApplePayAvailable = typeof window !== 'undefined' && typeof window.ApplePaySession !== 'undefined';
|
|
220
|
+
// Check if Apple Pay is available — load SDK on demand then re-check reactively
|
|
221
|
+
const [isApplePayAvailable, setIsApplePayAvailable] = useState(() => typeof window !== 'undefined' && typeof window.ApplePaySession !== 'undefined');
|
|
222
|
+
const [isApplePaySdkLoading, setIsApplePaySdkLoading] = useState(false);
|
|
223
|
+
const hasApplePayConfig = paymentMethods?.some((p) => p.type === 'apple_pay');
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
if (isApplePayAvailable || !hasApplePayConfig)
|
|
226
|
+
return;
|
|
227
|
+
const APPLE_PAY_SDK_URL = 'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js';
|
|
228
|
+
const onSdkReady = () => {
|
|
229
|
+
if (typeof window.ApplePaySession !== 'undefined') {
|
|
230
|
+
setIsApplePayAvailable(true);
|
|
231
|
+
}
|
|
232
|
+
setIsApplePaySdkLoading(false);
|
|
233
|
+
};
|
|
234
|
+
// Check if script is already in DOM (may still be loading)
|
|
235
|
+
const existing = document.querySelector(`script[src="${APPLE_PAY_SDK_URL}"]`);
|
|
236
|
+
if (existing) {
|
|
237
|
+
setIsApplePaySdkLoading(true);
|
|
238
|
+
// Script may already be loaded or still loading
|
|
239
|
+
if (typeof window.ApplePaySession !== 'undefined') {
|
|
240
|
+
onSdkReady();
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
existing.addEventListener('load', onSdkReady);
|
|
244
|
+
// Fallback timeout in case we missed the load event
|
|
245
|
+
const timer = setTimeout(onSdkReady, 2000);
|
|
246
|
+
return () => {
|
|
247
|
+
existing.removeEventListener('load', onSdkReady);
|
|
248
|
+
clearTimeout(timer);
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
setIsApplePaySdkLoading(true);
|
|
254
|
+
const script = document.createElement('script');
|
|
255
|
+
script.src = APPLE_PAY_SDK_URL;
|
|
256
|
+
script.crossOrigin = 'anonymous';
|
|
257
|
+
script.async = true;
|
|
258
|
+
script.onload = onSdkReady;
|
|
259
|
+
script.onerror = () => setIsApplePaySdkLoading(false);
|
|
260
|
+
document.head.appendChild(script);
|
|
261
|
+
}, [isApplePayAvailable, hasApplePayConfig]);
|
|
166
262
|
// Identify specific payment method types
|
|
167
263
|
const applePayPaymentMethod = useMemo(() => {
|
|
168
264
|
return isApplePayAvailable ? paymentMethods?.find((p) => p.type === 'apple_pay') : undefined;
|
|
@@ -177,7 +273,7 @@ export const ExpressPaymentMethodsProvider = ({ children, customerId, checkout,
|
|
|
177
273
|
return paymentMethods?.find((p) => (p.type === 'stripe_apm' || p.type === 'tagadapay_apm') &&
|
|
178
274
|
p.settings?.processors?.some((g) => EXPRESS_METHOD_KEYS.some((key) => g?.methods?.[key]?.enabled === true)));
|
|
179
275
|
}, [paymentMethods]);
|
|
180
|
-
const loading = !paymentMethods || isLoadingPaymentMethods;
|
|
276
|
+
const loading = !paymentMethods || (!configDerivedMethods && isLoadingPaymentMethods) || isApplePaySdkLoading;
|
|
181
277
|
const tagadaError = useMemo(() => error ? new TagadaError(error, { code: TagadaErrorCode.PAYMENT_FAILED }) : null, [error]);
|
|
182
278
|
const contextValue = {
|
|
183
279
|
paymentMethods,
|
|
@@ -38,11 +38,11 @@ const InitializationLoader = () => (_jsxs("div", { style: {
|
|
|
38
38
|
borderTop: '1.5px solid #9ca3af',
|
|
39
39
|
borderRadius: '50%',
|
|
40
40
|
animation: 'tagada-spin 1s linear infinite',
|
|
41
|
-
} }), _jsx("span", { children: "Loading..." }), _jsx("style", { children: `
|
|
42
|
-
@keyframes tagada-spin {
|
|
43
|
-
0% { transform: rotate(0deg); }
|
|
44
|
-
100% { transform: rotate(360deg); }
|
|
45
|
-
}
|
|
41
|
+
} }), _jsx("span", { children: "Loading..." }), _jsx("style", { children: `
|
|
42
|
+
@keyframes tagada-spin {
|
|
43
|
+
0% { transform: rotate(0deg); }
|
|
44
|
+
100% { transform: rotate(360deg); }
|
|
45
|
+
}
|
|
46
46
|
` })] }));
|
|
47
47
|
const TagadaContext = createContext(null);
|
|
48
48
|
export function TagadaProvider({ children, environment, customApiConfig, debugMode, localConfig, blockUntilSessionReady = false, rawPluginConfig, features, funnelId, autoInitializeFunnel = true, onNavigate, onFunnelError, debugScripts = [], }) {
|
|
@@ -315,7 +315,7 @@ export function TagadaProvider({ children, environment, customApiConfig, debugMo
|
|
|
315
315
|
console.log('🚀 [TagadaProvider] Auto-redirecting to:', result.url);
|
|
316
316
|
// Set pending redirect flag BEFORE navigation to prevent renders
|
|
317
317
|
setPendingRedirect(true);
|
|
318
|
-
window.location.
|
|
318
|
+
window.location.replace(result.url);
|
|
319
319
|
}
|
|
320
320
|
};
|
|
321
321
|
const next = async (event, options) => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apple Pay Service (Standalone) — re-export shim.
|
|
3
|
+
*
|
|
4
|
+
* The canonical implementation lives in `@tagadapay/core-js` so partner
|
|
5
|
+
* code, the studio, the native checkout, and the plugin-sdk all share a
|
|
6
|
+
* single source of truth for the native Apple Pay primitive (BasisTheory
|
|
7
|
+
* tokenization, no checkout session). This file preserves the historical
|
|
8
|
+
* import path `@tagadapay/plugin-sdk/v2/standalone` so existing consumers
|
|
9
|
+
* (studio-app, vanilla-checkout templates, …) keep working without
|
|
10
|
+
* code changes.
|
|
11
|
+
*/
|
|
12
|
+
export { isApplePayAvailable, startApplePaySession, type ApplePayServiceConfig, type ApplePayPaymentRequest, type ApplePayTokenResult, type ApplePayShippingContact, type ApplePayCallbacks, } from '@tagadapay/core-js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apple Pay Service (Standalone) — re-export shim.
|
|
3
|
+
*
|
|
4
|
+
* The canonical implementation lives in `@tagadapay/core-js` so partner
|
|
5
|
+
* code, the studio, the native checkout, and the plugin-sdk all share a
|
|
6
|
+
* single source of truth for the native Apple Pay primitive (BasisTheory
|
|
7
|
+
* tokenization, no checkout session). This file preserves the historical
|
|
8
|
+
* import path `@tagadapay/plugin-sdk/v2/standalone` so existing consumers
|
|
9
|
+
* (studio-app, vanilla-checkout templates, …) keep working without
|
|
10
|
+
* code changes.
|
|
11
|
+
*/
|
|
12
|
+
export { isApplePayAvailable, startApplePaySession, } from '@tagadapay/core-js';
|
|
@@ -36,7 +36,7 @@ export interface TagadaTrackerConfig {
|
|
|
36
36
|
stepName?: string;
|
|
37
37
|
/** Step type (optional — e.g., 'landing', 'offer', 'external') */
|
|
38
38
|
stepType?: string;
|
|
39
|
-
/** API base URL (defaults to https://
|
|
39
|
+
/** API base URL (defaults to https://api.tagada.io) */
|
|
40
40
|
apiBaseUrl?: string;
|
|
41
41
|
/** Enable debug logging */
|
|
42
42
|
debug?: boolean;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Pay Service (Standalone) — re-export shim.
|
|
3
|
+
*
|
|
4
|
+
* The canonical implementation lives in `@tagadapay/core-js`. This file
|
|
5
|
+
* preserves the historical import path `@tagadapay/plugin-sdk/v2/standalone`
|
|
6
|
+
* for downstream consumers (studio-app, vanilla-checkout templates,
|
|
7
|
+
* payment-error-dashboard) — they keep working unchanged.
|
|
8
|
+
*/
|
|
9
|
+
export { isGooglePayAvailable, startGooglePaySession, type GooglePayServiceConfig, type GooglePayPaymentRequest, type GooglePayTokenResult, type GooglePayAddress, type GooglePayCallbacks, } from '@tagadapay/core-js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Pay Service (Standalone) — re-export shim.
|
|
3
|
+
*
|
|
4
|
+
* The canonical implementation lives in `@tagadapay/core-js`. This file
|
|
5
|
+
* preserves the historical import path `@tagadapay/plugin-sdk/v2/standalone`
|
|
6
|
+
* for downstream consumers (studio-app, vanilla-checkout templates,
|
|
7
|
+
* payment-error-dashboard) — they keep working unchanged.
|
|
8
|
+
*/
|
|
9
|
+
export { isGooglePayAvailable, startGooglePaySession, } from '@tagadapay/core-js';
|
|
@@ -25,12 +25,15 @@ export { TagadaClient, ApiClient, CheckoutResource };
|
|
|
25
25
|
export { ShippingRatesResource } from '../core/resources/shippingRates';
|
|
26
26
|
export { PaymentsResource } from '../core/resources/payments';
|
|
27
27
|
export { OrdersResource } from '../core/resources/orders';
|
|
28
|
+
export { OffersResource } from '../core/resources/offers';
|
|
28
29
|
export { ExpressPaymentMethodsResource } from '../core/resources/expressPaymentMethods';
|
|
29
30
|
export type { PaymentMethod as ExpressPaymentMethod } from '../core/resources/expressPaymentMethods';
|
|
30
31
|
export type { ShippingRate, ShippingRatesResponse, ShippingRatesPreviewParams } from '../core/resources/shippingRates';
|
|
31
|
-
export type { Payment, PaymentResponse, CardPaymentMethod, BasisTheoryInstance, GooglePayToken, ApplePayToken, PaymentInstrumentInput, PaymentInstrumentResponse, PaymentInstrumentCustomerResponse, } from '../core/resources/payments';
|
|
32
|
+
export type { Payment, PaymentResponse, PaymentOptions, CardPaymentMethod, BasisTheoryInstance, GooglePayToken, ApplePayToken, PaymentInstrumentInput, PaymentInstrumentResponse, PaymentInstrumentCustomerResponse, } from '../core/resources/payments';
|
|
32
33
|
export { StoreConfigResource } from '../core/resources/storeConfig';
|
|
33
34
|
export type { StoreConfig } from '../core/resources/storeConfig';
|
|
35
|
+
export { GeoResource } from '../core/resources/geo';
|
|
36
|
+
export type { GeoLocationData } from '../core/resources/geo';
|
|
34
37
|
export { ThreedsResource } from '../core/resources/threeds';
|
|
35
38
|
export { ISODataCore } from '../core/isoData';
|
|
36
39
|
export type { ISOCountry, ISORegion } from '../core/isoData';
|
|
@@ -50,6 +53,10 @@ export { getAssignedStepConfig } from '../core/funnelClient';
|
|
|
50
53
|
export type { RuntimeStepConfig } from '../core/funnelClient';
|
|
51
54
|
export { PaymentService } from './payment-service';
|
|
52
55
|
export type { PaymentServiceConfig, PaymentResult, PaymentCallbacks, CardData, ApmData, } from './payment-service';
|
|
56
|
+
export { isApplePayAvailable, startApplePaySession } from './apple-pay-service';
|
|
57
|
+
export type { ApplePayServiceConfig, ApplePayPaymentRequest, ApplePayTokenResult, ApplePayShippingContact, ApplePayCallbacks, } from './apple-pay-service';
|
|
58
|
+
export { isGooglePayAvailable, startGooglePaySession } from './google-pay-service';
|
|
59
|
+
export type { GooglePayServiceConfig, GooglePayPaymentRequest, GooglePayTokenResult, GooglePayAddress, GooglePayCallbacks, } from './google-pay-service';
|
|
53
60
|
/**
|
|
54
61
|
* Get BasisTheory public API key based on hostname detection.
|
|
55
62
|
* Delegates to the centralized isProductionBasisTheory() logic.
|
|
@@ -134,9 +134,12 @@ export { TagadaClient, ApiClient, CheckoutResource };
|
|
|
134
134
|
export { ShippingRatesResource } from '../core/resources/shippingRates';
|
|
135
135
|
export { PaymentsResource } from '../core/resources/payments';
|
|
136
136
|
export { OrdersResource } from '../core/resources/orders';
|
|
137
|
+
export { OffersResource } from '../core/resources/offers';
|
|
137
138
|
export { ExpressPaymentMethodsResource } from '../core/resources/expressPaymentMethods';
|
|
138
139
|
// Re-export Store Config (for standalone resolvers / builders)
|
|
139
140
|
export { StoreConfigResource } from '../core/resources/storeConfig';
|
|
141
|
+
// Re-export Geo Resource (for standalone geolocation / country detection)
|
|
142
|
+
export { GeoResource } from '../core/resources/geo';
|
|
140
143
|
// Re-export 3DS Resource (for standalone resolvers / builders)
|
|
141
144
|
export { ThreedsResource } from '../core/resources/threeds';
|
|
142
145
|
// Re-export ISO Data Core (for standalone address form / resolvers)
|
|
@@ -155,6 +158,10 @@ export { getAssignedPaymentFlowId };
|
|
|
155
158
|
export { getAssignedStepConfig } from '../core/funnelClient';
|
|
156
159
|
// Re-export Payment Service (standalone payment processing — no React)
|
|
157
160
|
export { PaymentService } from './payment-service';
|
|
161
|
+
// Re-export Apple Pay Service (standalone native Apple Pay — no React)
|
|
162
|
+
export { isApplePayAvailable, startApplePaySession } from './apple-pay-service';
|
|
163
|
+
// Re-export Google Pay Service (standalone native Google Pay — no React)
|
|
164
|
+
export { isGooglePayAvailable, startGooglePaySession } from './google-pay-service';
|
|
158
165
|
/**
|
|
159
166
|
* Get BasisTheory public API key based on hostname detection.
|
|
160
167
|
* Delegates to the centralized isProductionBasisTheory() logic.
|
|
@@ -51,6 +51,8 @@ export interface PaymentCallbacks {
|
|
|
51
51
|
onSuccess?: (payment: Payment) => void;
|
|
52
52
|
onFailure?: (error: string) => void;
|
|
53
53
|
onRedirectReturn?: (paymentId: string) => void;
|
|
54
|
+
/** Called before a browser redirect, allows caller to await async work (e.g. funnel navigate) */
|
|
55
|
+
onBeforeRedirect?: (payment: Payment, redirectUrl: string) => Promise<void>;
|
|
54
56
|
}
|
|
55
57
|
export interface PollingCallbacks {
|
|
56
58
|
onSuccess: (payment: Payment) => void;
|
|
@@ -101,6 +103,7 @@ export declare class PaymentService {
|
|
|
101
103
|
private handleTrustFlowAuth;
|
|
102
104
|
private handleFinixRadar;
|
|
103
105
|
private handleStripeRadar;
|
|
106
|
+
private handleNgeniusThreeds;
|
|
104
107
|
private handleAirwallexRadar;
|
|
105
108
|
private handleMasterCardAuth;
|
|
106
109
|
private loadScript;
|
|
@@ -126,9 +129,19 @@ export declare class PaymentService {
|
|
|
126
129
|
id: string;
|
|
127
130
|
sessionId: string;
|
|
128
131
|
}>;
|
|
129
|
-
processCardPayment(checkoutSessionId: string, cardData: CardData
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
processCardPayment(checkoutSessionId: string, cardData: CardData, options?: {
|
|
133
|
+
shippingRateId?: string;
|
|
134
|
+
}): Promise<PaymentResult>;
|
|
135
|
+
processApplePayPayment(checkoutSessionId: string, applePayToken: ApplePayToken, options?: {
|
|
136
|
+
shippingRateId?: string;
|
|
137
|
+
}): Promise<PaymentResult>;
|
|
138
|
+
processGooglePayPayment(checkoutSessionId: string, googlePayToken: GooglePayToken, options?: {
|
|
139
|
+
shippingRateId?: string;
|
|
140
|
+
}): Promise<PaymentResult>;
|
|
141
|
+
processPaymentWithInstrument(checkoutSessionId: string, paymentInstrumentId: string, options?: {
|
|
142
|
+
shippingRateId?: string;
|
|
143
|
+
}): Promise<PaymentResult>;
|
|
144
|
+
processApmPayment(checkoutSessionId: string, apmData: ApmData, options?: {
|
|
145
|
+
shippingRateId?: string;
|
|
146
|
+
}): Promise<PaymentResult>;
|
|
134
147
|
}
|
|
@@ -212,6 +212,7 @@ export class PaymentService {
|
|
|
212
212
|
paymentFlowId,
|
|
213
213
|
processorId: extra?.processorId,
|
|
214
214
|
paymentMethod: extra?.paymentMethod,
|
|
215
|
+
shippingRateId: extra?.shippingRateId,
|
|
215
216
|
});
|
|
216
217
|
console.log('[PaymentService] Payment response:', {
|
|
217
218
|
paymentId: response.payment?.id,
|
|
@@ -301,6 +302,9 @@ export class PaymentService {
|
|
|
301
302
|
const redirectUrl = actionData.metadata?.redirect?.redirectUrl || actionData.redirectUrl || actionData.url;
|
|
302
303
|
if (redirectUrl) {
|
|
303
304
|
console.log('[PaymentService] Redirecting:', redirectUrl);
|
|
305
|
+
if (this.callbacks.onBeforeRedirect) {
|
|
306
|
+
await this.callbacks.onBeforeRedirect(payment, redirectUrl);
|
|
307
|
+
}
|
|
304
308
|
window.location.href = redirectUrl;
|
|
305
309
|
}
|
|
306
310
|
else if (payment.status === 'succeeded') {
|
|
@@ -343,6 +347,9 @@ export class PaymentService {
|
|
|
343
347
|
case 'mastercard_auth':
|
|
344
348
|
await this.handleMasterCardAuth(payment, actionData);
|
|
345
349
|
break;
|
|
350
|
+
case 'ngenius_3ds':
|
|
351
|
+
await this.handleNgeniusThreeds(payment, actionData);
|
|
352
|
+
break;
|
|
346
353
|
default: {
|
|
347
354
|
console.log('[PaymentService] Unhandled action, starting polling:', actionData.type);
|
|
348
355
|
this.startPolling(payment.id, {
|
|
@@ -501,6 +508,51 @@ export class PaymentService {
|
|
|
501
508
|
}
|
|
502
509
|
}
|
|
503
510
|
// --------------------------------------------------------------------------
|
|
511
|
+
// N-Genius 3DS (WebSDK)
|
|
512
|
+
// --------------------------------------------------------------------------
|
|
513
|
+
async handleNgeniusThreeds(payment, actionData) {
|
|
514
|
+
const sdk = actionData.metadata?.sdk;
|
|
515
|
+
if (!sdk?.paymentResponse || !sdk.orderReference || !sdk.paymentReference) {
|
|
516
|
+
this.callbacks.onError?.('N-Genius 3DS: missing SDK metadata');
|
|
517
|
+
this.callbacks.onProcessing?.(false);
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
try {
|
|
521
|
+
const sdkUrl = sdk.isSandboxed
|
|
522
|
+
? 'https://paypage.sandbox.ngenius-payments.com/hosted-sessions/sdk.js'
|
|
523
|
+
: 'https://paypage.ngenius-payments.com/hosted-sessions/sdk.js';
|
|
524
|
+
if (!document.getElementById('ngenius-websdk')) {
|
|
525
|
+
await new Promise((resolve, reject) => {
|
|
526
|
+
const script = document.createElement('script');
|
|
527
|
+
script.id = 'ngenius-websdk';
|
|
528
|
+
script.src = sdkUrl;
|
|
529
|
+
script.onload = () => resolve();
|
|
530
|
+
script.onerror = () => reject(new Error('Failed to load N-Genius WebSDK'));
|
|
531
|
+
document.head.appendChild(script);
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
const NI = window.NI;
|
|
535
|
+
if (!NI?.handlePaymentResponse) {
|
|
536
|
+
throw new Error('N-Genius WebSDK did not expose window.NI.handlePaymentResponse');
|
|
537
|
+
}
|
|
538
|
+
console.log('[N-Genius 3DS] Starting WebSDK challenge');
|
|
539
|
+
const outcome = await NI.handlePaymentResponse(sdk.paymentResponse, { mountId: 'ngenius-3ds-container', style: { width: '100%', height: 500 } });
|
|
540
|
+
console.log('[N-Genius 3DS] WebSDK outcome:', outcome.status);
|
|
541
|
+
const completedPayment = await this.paymentsResource.ngeniusThreedsComplete({
|
|
542
|
+
paymentId: payment.id,
|
|
543
|
+
orderReference: sdk.orderReference,
|
|
544
|
+
paymentReference: sdk.paymentReference,
|
|
545
|
+
});
|
|
546
|
+
await this.handleResumedPayment(completedPayment);
|
|
547
|
+
}
|
|
548
|
+
catch (error) {
|
|
549
|
+
const msg = error instanceof Error ? error.message : 'N-Genius 3DS failed';
|
|
550
|
+
console.error('[N-Genius 3DS] Error:', error);
|
|
551
|
+
this.callbacks.onError?.(msg);
|
|
552
|
+
this.callbacks.onProcessing?.(false);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
// --------------------------------------------------------------------------
|
|
504
556
|
// Airwallex Radar
|
|
505
557
|
// --------------------------------------------------------------------------
|
|
506
558
|
async handleAirwallexRadar(payment, actionData) {
|
|
@@ -533,6 +585,7 @@ export class PaymentService {
|
|
|
533
585
|
existingScript.setAttribute('data-order-session-id', sessionId);
|
|
534
586
|
}
|
|
535
587
|
await this.paymentsResource.saveRadarSession({
|
|
588
|
+
paymentId: payment.id,
|
|
536
589
|
checkoutSessionId,
|
|
537
590
|
orderId,
|
|
538
591
|
airwallexRadarSessionId: sessionId,
|
|
@@ -834,7 +887,7 @@ export class PaymentService {
|
|
|
834
887
|
// ==========================================================================
|
|
835
888
|
// PAYMENT PROCESSING (all methods)
|
|
836
889
|
// ==========================================================================
|
|
837
|
-
async processCardPayment(checkoutSessionId, cardData) {
|
|
890
|
+
async processCardPayment(checkoutSessionId, cardData, options) {
|
|
838
891
|
this.callbacks.onProcessing?.(true);
|
|
839
892
|
this.callbacks.onError?.(null);
|
|
840
893
|
try {
|
|
@@ -857,7 +910,7 @@ export class PaymentService {
|
|
|
857
910
|
// Continue without 3DS
|
|
858
911
|
}
|
|
859
912
|
}
|
|
860
|
-
return await this.processAndHandle(checkoutSessionId, instrument.id, threedsSessionId);
|
|
913
|
+
return await this.processAndHandle(checkoutSessionId, instrument.id, threedsSessionId, { shippingRateId: options?.shippingRateId });
|
|
861
914
|
}
|
|
862
915
|
catch (error) {
|
|
863
916
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -866,12 +919,12 @@ export class PaymentService {
|
|
|
866
919
|
return { success: false, error: msg };
|
|
867
920
|
}
|
|
868
921
|
}
|
|
869
|
-
async processApplePayPayment(checkoutSessionId, applePayToken) {
|
|
922
|
+
async processApplePayPayment(checkoutSessionId, applePayToken, options) {
|
|
870
923
|
this.callbacks.onProcessing?.(true);
|
|
871
924
|
this.callbacks.onError?.(null);
|
|
872
925
|
try {
|
|
873
926
|
const instrument = await this.createApplePayPaymentInstrument(applePayToken);
|
|
874
|
-
return await this.processAndHandle(checkoutSessionId, instrument.id);
|
|
927
|
+
return await this.processAndHandle(checkoutSessionId, instrument.id, undefined, { shippingRateId: options?.shippingRateId });
|
|
875
928
|
}
|
|
876
929
|
catch (error) {
|
|
877
930
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -880,12 +933,12 @@ export class PaymentService {
|
|
|
880
933
|
return { success: false, error: msg };
|
|
881
934
|
}
|
|
882
935
|
}
|
|
883
|
-
async processGooglePayPayment(checkoutSessionId, googlePayToken) {
|
|
936
|
+
async processGooglePayPayment(checkoutSessionId, googlePayToken, options) {
|
|
884
937
|
this.callbacks.onProcessing?.(true);
|
|
885
938
|
this.callbacks.onError?.(null);
|
|
886
939
|
try {
|
|
887
940
|
const instrument = await this.createGooglePayPaymentInstrument(googlePayToken);
|
|
888
|
-
return await this.processAndHandle(checkoutSessionId, instrument.id);
|
|
941
|
+
return await this.processAndHandle(checkoutSessionId, instrument.id, undefined, { shippingRateId: options?.shippingRateId });
|
|
889
942
|
}
|
|
890
943
|
catch (error) {
|
|
891
944
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -894,11 +947,11 @@ export class PaymentService {
|
|
|
894
947
|
return { success: false, error: msg };
|
|
895
948
|
}
|
|
896
949
|
}
|
|
897
|
-
async processPaymentWithInstrument(checkoutSessionId, paymentInstrumentId) {
|
|
950
|
+
async processPaymentWithInstrument(checkoutSessionId, paymentInstrumentId, options) {
|
|
898
951
|
this.callbacks.onProcessing?.(true);
|
|
899
952
|
this.callbacks.onError?.(null);
|
|
900
953
|
try {
|
|
901
|
-
return await this.processAndHandle(checkoutSessionId, paymentInstrumentId);
|
|
954
|
+
return await this.processAndHandle(checkoutSessionId, paymentInstrumentId, undefined, { shippingRateId: options?.shippingRateId });
|
|
902
955
|
}
|
|
903
956
|
catch (error) {
|
|
904
957
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -907,7 +960,7 @@ export class PaymentService {
|
|
|
907
960
|
return { success: false, error: msg };
|
|
908
961
|
}
|
|
909
962
|
}
|
|
910
|
-
async processApmPayment(checkoutSessionId, apmData) {
|
|
963
|
+
async processApmPayment(checkoutSessionId, apmData, options) {
|
|
911
964
|
this.callbacks.onProcessing?.(true);
|
|
912
965
|
this.callbacks.onError?.(null);
|
|
913
966
|
try {
|
|
@@ -916,6 +969,7 @@ export class PaymentService {
|
|
|
916
969
|
paymentMethod: apmData.paymentMethod,
|
|
917
970
|
initiatedBy: apmData.initiatedBy,
|
|
918
971
|
source: apmData.source,
|
|
972
|
+
shippingRateId: options?.shippingRateId,
|
|
919
973
|
});
|
|
920
974
|
}
|
|
921
975
|
catch (error) {
|