@tagadapay/headless-sdk 1.8.0-rc.0 → 1.8.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 +216 -1
- package/dist/core/client.d.ts +68 -0
- package/dist/core/client.js +71 -0
- package/dist/core/errors.d.ts +46 -0
- package/dist/core/errors.js +57 -0
- package/dist/core/helpers/autocomplete.d.ts +89 -0
- package/dist/core/helpers/autocomplete.js +186 -0
- package/dist/core/helpers/countries.d.ts +45 -0
- package/dist/core/helpers/countries.js +65 -0
- package/dist/core/helpers/currency.d.ts +26 -0
- package/dist/core/helpers/currency.js +72 -0
- package/dist/core/helpers/index.d.ts +5 -0
- package/dist/core/helpers/index.js +5 -0
- package/dist/core/helpers/iso3166.d.ts +28 -0
- package/dist/core/helpers/iso3166.js +84 -0
- package/dist/core/http.d.ts +27 -0
- package/dist/core/http.js +116 -0
- package/dist/core/index.d.ts +15 -0
- package/dist/core/index.js +13 -0
- package/dist/core/modules/catalog.d.ts +27 -0
- package/dist/core/modules/catalog.js +38 -0
- package/dist/core/modules/checkout.d.ts +268 -0
- package/dist/core/modules/checkout.js +470 -0
- package/dist/core/modules/customer.d.ts +33 -0
- package/dist/core/modules/customer.js +53 -0
- package/dist/core/modules/funnel.d.ts +38 -0
- package/dist/core/modules/funnel.js +138 -0
- package/dist/core/modules/offers.d.ts +137 -0
- package/dist/core/modules/offers.js +141 -0
- package/dist/core/modules/payment.d.ts +298 -0
- package/dist/core/modules/payment.js +701 -0
- package/dist/core/modules/rx.d.ts +162 -0
- package/dist/core/modules/rx.js +46 -0
- package/dist/core/types.d.ts +505 -0
- package/dist/core/types.js +5 -0
- package/dist/react/hooks/useCatalog.d.ts +25 -0
- package/dist/react/hooks/useCatalog.js +58 -0
- package/dist/react/hooks/useCheckout.d.ts +58 -0
- package/dist/react/hooks/useCheckout.js +177 -0
- package/dist/react/hooks/useCustomer.d.ts +28 -0
- package/dist/react/hooks/useCustomer.js +77 -0
- package/dist/react/hooks/useGoogleAutocomplete.d.ts +26 -0
- package/dist/react/hooks/useGoogleAutocomplete.js +70 -0
- package/dist/react/hooks/useISOData.d.ts +23 -0
- package/dist/react/hooks/useISOData.js +63 -0
- package/dist/react/hooks/useOffers.d.ts +134 -0
- package/dist/react/hooks/useOffers.js +171 -0
- package/dist/react/hooks/usePayment.d.ts +108 -0
- package/dist/react/hooks/usePayment.js +233 -0
- package/dist/react/hooks/useRx.d.ts +64 -0
- package/dist/react/hooks/useRx.js +145 -0
- package/dist/react/index.d.ts +22 -0
- package/dist/react/index.js +12 -0
- package/dist/react/internal/redirectGuard.d.ts +9 -0
- package/dist/react/internal/redirectGuard.js +25 -0
- package/dist/react/provider.d.ts +31 -0
- package/dist/react/provider.js +32 -0
- package/dist/stripe/StripeExpressButton.d.ts +30 -0
- package/dist/stripe/StripeExpressButton.js +32 -0
- package/dist/stripe/StripeExpressCheckout.d.ts +98 -0
- package/dist/stripe/StripeExpressCheckout.js +198 -0
- package/dist/stripe/index.d.ts +8 -0
- package/dist/stripe/index.js +15 -0
- package/dist/stripe/useStripeExpress.d.ts +54 -0
- package/dist/stripe/useStripeExpress.js +126 -0
- package/package.json +2 -3
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { RxCaseSummary, RxQuestionsForProduct, RxRequiredForProduct, RxSubmitCaseInput, RxSubmitCaseResult } from '../../core/modules/rx.js';
|
|
2
|
+
export interface UseRxReturn {
|
|
3
|
+
/** Cases attached to the current order (populated by `pollOrder`). */
|
|
4
|
+
cases: RxCaseSummary[];
|
|
5
|
+
/** Result of the last `submitCase` call, kept for the thank-you page. */
|
|
6
|
+
lastSubmission: RxSubmitCaseResult | null;
|
|
7
|
+
/** True while ANY rx call is in flight. */
|
|
8
|
+
isLoading: boolean;
|
|
9
|
+
error: Error | null;
|
|
10
|
+
/**
|
|
11
|
+
* Ask whether a product needs an Rx case before submitting payment.
|
|
12
|
+
* Storefronts call this at product-page load to decide whether to
|
|
13
|
+
* render the intake step.
|
|
14
|
+
*/
|
|
15
|
+
isRequiredForProduct: (productId: string, opts?: {
|
|
16
|
+
clinicalNetworkId?: string;
|
|
17
|
+
}) => Promise<RxRequiredForProduct>;
|
|
18
|
+
/** Fetch network-authored intake questions for a product. */
|
|
19
|
+
getQuestionsForProduct: (productId: string) => Promise<RxQuestionsForProduct>;
|
|
20
|
+
/**
|
|
21
|
+
* Submit a fresh case after the order is paid. The result is also
|
|
22
|
+
* stored in `lastSubmission` so the thank-you page can read it.
|
|
23
|
+
*/
|
|
24
|
+
submitCase: (input: RxSubmitCaseInput) => Promise<RxSubmitCaseResult>;
|
|
25
|
+
/**
|
|
26
|
+
* Fetch the public summary of every case attached to a paid order.
|
|
27
|
+
* Useful for the thank-you page or order history.
|
|
28
|
+
*/
|
|
29
|
+
fetchCasesForOrder: (input: {
|
|
30
|
+
orderId: string;
|
|
31
|
+
checkoutToken: string;
|
|
32
|
+
}) => Promise<RxCaseSummary[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Auto-poll the cases for an order until they all reach a terminal
|
|
35
|
+
* status (approved / shipped / delivered / declined / cancelled /
|
|
36
|
+
* error). Returns a `stop()` function to cancel the polling.
|
|
37
|
+
*/
|
|
38
|
+
pollOrder: (input: {
|
|
39
|
+
orderId: string;
|
|
40
|
+
checkoutToken: string;
|
|
41
|
+
}, opts?: {
|
|
42
|
+
intervalMs?: number;
|
|
43
|
+
onUpdate?: (cases: RxCaseSummary[]) => void;
|
|
44
|
+
}) => () => void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* React hook for Tagada Rx storefronts.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```tsx
|
|
51
|
+
* const { isRequiredForProduct, submitCase, lastSubmission, pollOrder } = useRx();
|
|
52
|
+
*
|
|
53
|
+
* useEffect(() => {
|
|
54
|
+
* if (orderId && checkoutToken) {
|
|
55
|
+
* const stop = pollOrder({ orderId, checkoutToken }, {
|
|
56
|
+
* onUpdate: (cases) => setCases(cases),
|
|
57
|
+
* });
|
|
58
|
+
* return stop;
|
|
59
|
+
* }
|
|
60
|
+
* }, [orderId, checkoutToken, pollOrder]);
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function useRx(): UseRxReturn;
|
|
64
|
+
//# sourceMappingURL=useRx.d.ts.map
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useHeadlessClient } from '../provider.js';
|
|
3
|
+
const TERMINAL_STATUSES = new Set([
|
|
4
|
+
'approved',
|
|
5
|
+
'shipped',
|
|
6
|
+
'delivered',
|
|
7
|
+
'declined',
|
|
8
|
+
'cancelled',
|
|
9
|
+
'error',
|
|
10
|
+
]);
|
|
11
|
+
/**
|
|
12
|
+
* React hook for Tagada Rx storefronts.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* const { isRequiredForProduct, submitCase, lastSubmission, pollOrder } = useRx();
|
|
17
|
+
*
|
|
18
|
+
* useEffect(() => {
|
|
19
|
+
* if (orderId && checkoutToken) {
|
|
20
|
+
* const stop = pollOrder({ orderId, checkoutToken }, {
|
|
21
|
+
* onUpdate: (cases) => setCases(cases),
|
|
22
|
+
* });
|
|
23
|
+
* return stop;
|
|
24
|
+
* }
|
|
25
|
+
* }, [orderId, checkoutToken, pollOrder]);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function useRx() {
|
|
29
|
+
const client = useHeadlessClient();
|
|
30
|
+
const [cases, setCases] = useState([]);
|
|
31
|
+
const [lastSubmission, setLastSubmission] = useState(null);
|
|
32
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
33
|
+
const [error, setError] = useState(null);
|
|
34
|
+
const pollTimerRef = useRef(null);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
return () => {
|
|
37
|
+
if (pollTimerRef.current)
|
|
38
|
+
clearInterval(pollTimerRef.current);
|
|
39
|
+
};
|
|
40
|
+
}, []);
|
|
41
|
+
const isRequiredForProduct = useCallback(async (productId, opts) => {
|
|
42
|
+
setIsLoading(true);
|
|
43
|
+
setError(null);
|
|
44
|
+
try {
|
|
45
|
+
return await client.rx.isRequiredForProduct(productId, opts);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
49
|
+
setError(e);
|
|
50
|
+
throw e;
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
setIsLoading(false);
|
|
54
|
+
}
|
|
55
|
+
}, [client]);
|
|
56
|
+
const getQuestionsForProduct = useCallback(async (productId) => {
|
|
57
|
+
setIsLoading(true);
|
|
58
|
+
setError(null);
|
|
59
|
+
try {
|
|
60
|
+
return await client.rx.getQuestionsForProduct(productId);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
64
|
+
setError(e);
|
|
65
|
+
throw e;
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
setIsLoading(false);
|
|
69
|
+
}
|
|
70
|
+
}, [client]);
|
|
71
|
+
const submitCase = useCallback(async (input) => {
|
|
72
|
+
setIsLoading(true);
|
|
73
|
+
setError(null);
|
|
74
|
+
try {
|
|
75
|
+
const res = await client.rx.submitCase(input);
|
|
76
|
+
setLastSubmission(res);
|
|
77
|
+
return res;
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
81
|
+
setError(e);
|
|
82
|
+
throw e;
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
setIsLoading(false);
|
|
86
|
+
}
|
|
87
|
+
}, [client]);
|
|
88
|
+
const fetchCasesForOrder = useCallback(async (input) => {
|
|
89
|
+
setIsLoading(true);
|
|
90
|
+
setError(null);
|
|
91
|
+
try {
|
|
92
|
+
const res = await client.rx.getCasesForOrder(input);
|
|
93
|
+
setCases(res.cases);
|
|
94
|
+
return res.cases;
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
98
|
+
setError(e);
|
|
99
|
+
throw e;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
setIsLoading(false);
|
|
103
|
+
}
|
|
104
|
+
}, [client]);
|
|
105
|
+
const pollOrder = useCallback(({ orderId, checkoutToken }, opts) => {
|
|
106
|
+
if (pollTimerRef.current)
|
|
107
|
+
clearInterval(pollTimerRef.current);
|
|
108
|
+
const intervalMs = opts?.intervalMs ?? 5000;
|
|
109
|
+
const tick = async () => {
|
|
110
|
+
try {
|
|
111
|
+
const res = await client.rx.getCasesForOrder({ orderId, checkoutToken });
|
|
112
|
+
setCases(res.cases);
|
|
113
|
+
opts?.onUpdate?.(res.cases);
|
|
114
|
+
if (res.cases.length > 0 && res.cases.every((c) => TERMINAL_STATUSES.has(c.status))) {
|
|
115
|
+
if (pollTimerRef.current)
|
|
116
|
+
clearInterval(pollTimerRef.current);
|
|
117
|
+
pollTimerRef.current = null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
122
|
+
setError(e);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
void tick();
|
|
126
|
+
pollTimerRef.current = setInterval(tick, intervalMs);
|
|
127
|
+
return () => {
|
|
128
|
+
if (pollTimerRef.current)
|
|
129
|
+
clearInterval(pollTimerRef.current);
|
|
130
|
+
pollTimerRef.current = null;
|
|
131
|
+
};
|
|
132
|
+
}, [client]);
|
|
133
|
+
return {
|
|
134
|
+
cases,
|
|
135
|
+
lastSubmission,
|
|
136
|
+
isLoading,
|
|
137
|
+
error,
|
|
138
|
+
isRequiredForProduct,
|
|
139
|
+
getQuestionsForProduct,
|
|
140
|
+
submitCase,
|
|
141
|
+
fetchCasesForOrder,
|
|
142
|
+
pollOrder,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=useRx.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { TagadaHeadlessProvider, useHeadlessClient } from './provider.js';
|
|
2
|
+
export type { TagadaHeadlessProviderProps } from './provider.js';
|
|
3
|
+
export { useCheckout } from './hooks/useCheckout.js';
|
|
4
|
+
export type { UseCheckoutReturn } from './hooks/useCheckout.js';
|
|
5
|
+
export { usePayment } from './hooks/usePayment.js';
|
|
6
|
+
export type { UsePaymentReturn, UsePaymentOptions } from './hooks/usePayment.js';
|
|
7
|
+
export { useOffers } from './hooks/useOffers.js';
|
|
8
|
+
export type { UseOffersReturn } from './hooks/useOffers.js';
|
|
9
|
+
export { useCustomer } from './hooks/useCustomer.js';
|
|
10
|
+
export type { UseCustomerReturn } from './hooks/useCustomer.js';
|
|
11
|
+
export { useCatalog } from './hooks/useCatalog.js';
|
|
12
|
+
export type { UseCatalogReturn } from './hooks/useCatalog.js';
|
|
13
|
+
export { useRx } from './hooks/useRx.js';
|
|
14
|
+
export type { UseRxReturn } from './hooks/useRx.js';
|
|
15
|
+
export { useGoogleAutocomplete } from './hooks/useGoogleAutocomplete.js';
|
|
16
|
+
export type { UseGoogleAutocompleteOptions, UseGoogleAutocompleteReturn } from './hooks/useGoogleAutocomplete.js';
|
|
17
|
+
export { useISOData, useCountryOptions, useRegionOptions } from './hooks/useISOData.js';
|
|
18
|
+
export type { UseISODataReturn } from './hooks/useISOData.js';
|
|
19
|
+
export type { GooglePrediction, GooglePlaceDetails, ExtractedAddress, FormattedAddress, SupportedLanguage, ISOCountry, ISORegion, Currency, } from '../core/helpers/index.js';
|
|
20
|
+
export { formatMoney, CurrencyUtils, ISODataCore, GoogleAutocompleteCore, loadGoogleMapsScript } from '../core/helpers/index.js';
|
|
21
|
+
export type { HeadlessConfig, Environment, CheckoutSession, CheckoutLineItem, CheckoutTotals, CheckoutCustomer, Address, ShippingRate, LineItem, PaymentSetupConfig, PaymentMethodConfig, ExpressMethods, ExpressMethod, StoreConfig, PayResult, PayOptions, PaymentStatus, ProcessPaymentOptions, ProcessPaymentResult, Offer, OfferLineItem, OfferPreview, OfferPreviewItem, OfferPayResult, Customer, Order, Subscription, CatalogProduct, CatalogVariant, CatalogPrice, CurrencyOption, StripeExpressOptions, } from '../core/types.js';
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { TagadaHeadlessProvider, useHeadlessClient } from './provider.js';
|
|
2
|
+
export { useCheckout } from './hooks/useCheckout.js';
|
|
3
|
+
export { usePayment } from './hooks/usePayment.js';
|
|
4
|
+
export { useOffers } from './hooks/useOffers.js';
|
|
5
|
+
export { useCustomer } from './hooks/useCustomer.js';
|
|
6
|
+
export { useCatalog } from './hooks/useCatalog.js';
|
|
7
|
+
export { useRx } from './hooks/useRx.js';
|
|
8
|
+
// Helpers hooks
|
|
9
|
+
export { useGoogleAutocomplete } from './hooks/useGoogleAutocomplete.js';
|
|
10
|
+
export { useISOData, useCountryOptions, useRegionOptions } from './hooks/useISOData.js';
|
|
11
|
+
export { formatMoney, CurrencyUtils, ISODataCore, GoogleAutocompleteCore, loadGoogleMapsScript } from '../core/helpers/index.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Try to claim ownership of resuming a payment. Returns `true` if the
|
|
3
|
+
* caller is the first one to claim it (and should proceed); `false` if
|
|
4
|
+
* another hook has already claimed it.
|
|
5
|
+
*/
|
|
6
|
+
export declare function tryClaimResume(paymentId: string): boolean;
|
|
7
|
+
/** Reset the guard. Useful in tests and on hard refresh logic. */
|
|
8
|
+
export declare function resetResumeGuard(): void;
|
|
9
|
+
//# sourceMappingURL=redirectGuard.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level guard preventing two hooks (`usePayment`, `useOffers`) from
|
|
3
|
+
* both resuming the same payment after a 3DS / processor redirect.
|
|
4
|
+
*
|
|
5
|
+
* Each `paymentId` is processed at most once per page load. The first hook
|
|
6
|
+
* that wins the race calls `client.payment.resumeAfterRedirect` and fires
|
|
7
|
+
* its callback; the other hook becomes a no-op.
|
|
8
|
+
*/
|
|
9
|
+
const RESUMED_PAYMENT_IDS = new Set();
|
|
10
|
+
/**
|
|
11
|
+
* Try to claim ownership of resuming a payment. Returns `true` if the
|
|
12
|
+
* caller is the first one to claim it (and should proceed); `false` if
|
|
13
|
+
* another hook has already claimed it.
|
|
14
|
+
*/
|
|
15
|
+
export function tryClaimResume(paymentId) {
|
|
16
|
+
if (RESUMED_PAYMENT_IDS.has(paymentId))
|
|
17
|
+
return false;
|
|
18
|
+
RESUMED_PAYMENT_IDS.add(paymentId);
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
/** Reset the guard. Useful in tests and on hard refresh logic. */
|
|
22
|
+
export function resetResumeGuard() {
|
|
23
|
+
RESUMED_PAYMENT_IDS.clear();
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=redirectGuard.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { HeadlessClient } from '../core/client.js';
|
|
3
|
+
import type { HeadlessConfig, Environment } from '../core/types.js';
|
|
4
|
+
export interface TagadaHeadlessProviderProps {
|
|
5
|
+
/** Your TagadaPay store ID. */
|
|
6
|
+
storeId: string;
|
|
7
|
+
/** Environment. Defaults to "production". */
|
|
8
|
+
environment?: Environment;
|
|
9
|
+
/** Public API key for authenticated requests. */
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
/** Override the base API URL. */
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
/** Full config object (alternative to individual props). */
|
|
14
|
+
config?: HeadlessConfig;
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Root provider for the TagadaPay Headless SDK React integration.
|
|
19
|
+
* Creates a single HeadlessClient and shares it via context.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <TagadaHeadlessProvider storeId="store_abc123" environment="production">
|
|
24
|
+
* <App />
|
|
25
|
+
* </TagadaHeadlessProvider>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function TagadaHeadlessProvider({ storeId, environment, apiKey, baseUrl, config, children, }: TagadaHeadlessProviderProps): import("react/jsx-runtime.js").JSX.Element;
|
|
29
|
+
/** Access the HeadlessClient from context. Throws if used outside the provider. */
|
|
30
|
+
export declare function useHeadlessClient(): HeadlessClient;
|
|
31
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useMemo } from 'react';
|
|
3
|
+
import { createHeadlessClient } from '../core/client.js';
|
|
4
|
+
const TagadaHeadlessContext = createContext(null);
|
|
5
|
+
/**
|
|
6
|
+
* Root provider for the TagadaPay Headless SDK React integration.
|
|
7
|
+
* Creates a single HeadlessClient and shares it via context.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <TagadaHeadlessProvider storeId="store_abc123" environment="production">
|
|
12
|
+
* <App />
|
|
13
|
+
* </TagadaHeadlessProvider>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function TagadaHeadlessProvider({ storeId, environment, apiKey, baseUrl, config, children, }) {
|
|
17
|
+
const client = useMemo(() => {
|
|
18
|
+
const cfg = config ?? { storeId, environment, apiKey, baseUrl };
|
|
19
|
+
return createHeadlessClient(cfg);
|
|
20
|
+
}, [storeId, environment, apiKey, baseUrl, config]);
|
|
21
|
+
const value = useMemo(() => ({ client }), [client]);
|
|
22
|
+
return (_jsx(TagadaHeadlessContext.Provider, { value: value, children: children }));
|
|
23
|
+
}
|
|
24
|
+
/** Access the HeadlessClient from context. Throws if used outside the provider. */
|
|
25
|
+
export function useHeadlessClient() {
|
|
26
|
+
const ctx = useContext(TagadaHeadlessContext);
|
|
27
|
+
if (!ctx) {
|
|
28
|
+
throw new Error('useHeadlessClient must be used within <TagadaHeadlessProvider>');
|
|
29
|
+
}
|
|
30
|
+
return ctx.client;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { UseStripeExpressOptions } from './useStripeExpress.js';
|
|
3
|
+
export type StripeExpressButtonProps = UseStripeExpressOptions & {
|
|
4
|
+
/** CSS class for the wrapper div. */
|
|
5
|
+
className?: string;
|
|
6
|
+
/** Inline style for the wrapper div. */
|
|
7
|
+
style?: React.CSSProperties;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Drop-in React component that renders Stripe Express Checkout buttons
|
|
11
|
+
* (Apple Pay, Google Pay, Link, etc.).
|
|
12
|
+
*
|
|
13
|
+
* Internally uses `useStripeExpress` which handles the full flow:
|
|
14
|
+
* discover config -> load Stripe -> mount ECE -> confirm -> poll -> callbacks.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* import { StripeExpressButton } from '@tagadapay/headless-sdk/stripe';
|
|
19
|
+
*
|
|
20
|
+
* <StripeExpressButton
|
|
21
|
+
* checkoutSessionId={session.id}
|
|
22
|
+
* amount={totals.total}
|
|
23
|
+
* currency={totals.currency}
|
|
24
|
+
* onSuccess={() => router.push('/confirmation')}
|
|
25
|
+
* onError={(msg) => toast.error(msg)}
|
|
26
|
+
* />
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function StripeExpressButton({ className, style, ...hookOpts }: StripeExpressButtonProps): import("react/jsx-runtime.js").JSX.Element;
|
|
30
|
+
//# sourceMappingURL=StripeExpressButton.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useStripeExpress } from './useStripeExpress.js';
|
|
3
|
+
/**
|
|
4
|
+
* Drop-in React component that renders Stripe Express Checkout buttons
|
|
5
|
+
* (Apple Pay, Google Pay, Link, etc.).
|
|
6
|
+
*
|
|
7
|
+
* Internally uses `useStripeExpress` which handles the full flow:
|
|
8
|
+
* discover config -> load Stripe -> mount ECE -> confirm -> poll -> callbacks.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { StripeExpressButton } from '@tagadapay/headless-sdk/stripe';
|
|
13
|
+
*
|
|
14
|
+
* <StripeExpressButton
|
|
15
|
+
* checkoutSessionId={session.id}
|
|
16
|
+
* amount={totals.total}
|
|
17
|
+
* currency={totals.currency}
|
|
18
|
+
* onSuccess={() => router.push('/confirmation')}
|
|
19
|
+
* onError={(msg) => toast.error(msg)}
|
|
20
|
+
* />
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function StripeExpressButton({ className, style, ...hookOpts }) {
|
|
24
|
+
const { containerRef, isReady } = useStripeExpress(hookOpts);
|
|
25
|
+
return (_jsx("div", { ref: containerRef, className: className, style: {
|
|
26
|
+
visibility: isReady ? 'visible' : 'hidden',
|
|
27
|
+
minHeight: isReady ? undefined : 0,
|
|
28
|
+
overflow: isReady ? undefined : 'hidden',
|
|
29
|
+
...style,
|
|
30
|
+
} }));
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=StripeExpressButton.js.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { HeadlessClient } from '../core/client.js';
|
|
2
|
+
import type { StripeExpressOptions, PaymentStatus } from '../core/types.js';
|
|
3
|
+
type EventMap = {
|
|
4
|
+
ready: {
|
|
5
|
+
availablePaymentMethods: Record<string, boolean> | undefined;
|
|
6
|
+
};
|
|
7
|
+
success: {
|
|
8
|
+
payment: PaymentStatus;
|
|
9
|
+
order?: {
|
|
10
|
+
id: string;
|
|
11
|
+
checkoutSessionId?: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
error: string;
|
|
15
|
+
cancel: void;
|
|
16
|
+
};
|
|
17
|
+
type EventHandler<K extends keyof EventMap> = (data: EventMap[K]) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Session-based Stripe Express Checkout integration.
|
|
20
|
+
*
|
|
21
|
+
* Mounts the Stripe `ExpressCheckoutElement` (Apple Pay, Google Pay, Link,
|
|
22
|
+
* PayPal, Klarna express) into any DOM container, wired to a Tagada
|
|
23
|
+
* checkout session. Drives the full flow:
|
|
24
|
+
* mount → wallet confirm → backend `payDirect` (`processStripeExpress`)
|
|
25
|
+
* → `stripe.confirmPayment` → poll payment status → emit `success`.
|
|
26
|
+
*
|
|
27
|
+
* **Session-free / partner S2S flow?** Use the lower-level primitive
|
|
28
|
+
* `startStripeExpressCheckout` exported from `@tagadapay/core-js`
|
|
29
|
+
* (also re-exported from `@tagadapay/headless-sdk/stripe`). It uses
|
|
30
|
+
* Stripe's older Payment Request API, stops at tokenization, and
|
|
31
|
+
* returns a `paymentMethodId` for partner-server-side processing.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { createHeadlessClient } from '@tagadapay/headless-sdk';
|
|
36
|
+
* import { StripeExpressCheckout } from '@tagadapay/headless-sdk/stripe';
|
|
37
|
+
*
|
|
38
|
+
* const client = createHeadlessClient({ storeId: 'store_xxx' });
|
|
39
|
+
* const session = await client.checkout.loadSession(checkoutToken);
|
|
40
|
+
* const express = await client.payment.getExpressMethods(session.id);
|
|
41
|
+
*
|
|
42
|
+
* const ece = new StripeExpressCheckout({
|
|
43
|
+
* client,
|
|
44
|
+
* publishableKey: express.applePay?.publishableKey!,
|
|
45
|
+
* processorId: express.applePay?.processorId!,
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* ece.on('success', ({ payment }) => console.log('Paid!', payment.id));
|
|
49
|
+
* ece.on('error', (msg) => console.error(msg));
|
|
50
|
+
*
|
|
51
|
+
* await ece.mount(document.getElementById('express-container')!, {
|
|
52
|
+
* checkoutSessionId: session.id,
|
|
53
|
+
* amount: session.totals.total,
|
|
54
|
+
* currency: session.totals.currency,
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare class StripeExpressCheckout {
|
|
59
|
+
private stripe;
|
|
60
|
+
private elements;
|
|
61
|
+
private expressElement;
|
|
62
|
+
private container;
|
|
63
|
+
private isProcessing;
|
|
64
|
+
private listeners;
|
|
65
|
+
private readonly client;
|
|
66
|
+
private readonly publishableKey;
|
|
67
|
+
private readonly processorId;
|
|
68
|
+
private readonly enabledMethods;
|
|
69
|
+
private readonly buttonHeight;
|
|
70
|
+
private readonly buttonType;
|
|
71
|
+
private readonly emailRequired;
|
|
72
|
+
private readonly billingAddressRequired;
|
|
73
|
+
constructor(opts: {
|
|
74
|
+
client: HeadlessClient;
|
|
75
|
+
} & StripeExpressOptions);
|
|
76
|
+
on<K extends keyof EventMap>(event: K, handler: EventHandler<K>): void;
|
|
77
|
+
off<K extends keyof EventMap>(event: K, handler: EventHandler<K>): void;
|
|
78
|
+
/**
|
|
79
|
+
* Load Stripe.js, create Elements, and mount the ExpressCheckoutElement.
|
|
80
|
+
*/
|
|
81
|
+
mount(container: HTMLElement, opts: {
|
|
82
|
+
checkoutSessionId: string;
|
|
83
|
+
amount: number;
|
|
84
|
+
currency: string;
|
|
85
|
+
}): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Update the payment amount (e.g. after a cart change).
|
|
88
|
+
*/
|
|
89
|
+
updateAmount(amount: number, currency?: string): void;
|
|
90
|
+
/**
|
|
91
|
+
* Clean up: unmount the element and release references.
|
|
92
|
+
*/
|
|
93
|
+
unmount(): void;
|
|
94
|
+
private emit;
|
|
95
|
+
private extractClientSecret;
|
|
96
|
+
}
|
|
97
|
+
export {};
|
|
98
|
+
//# sourceMappingURL=StripeExpressCheckout.d.ts.map
|