@tagadapay/plugin-sdk 2.6.11 → 2.6.12

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.
@@ -0,0 +1,71 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { CheckoutData } from './useCheckout';
3
+ export interface Address {
4
+ address1: string;
5
+ address2?: string;
6
+ lastName?: string;
7
+ firstName?: string;
8
+ city?: string;
9
+ state?: string;
10
+ country?: string;
11
+ postal?: string;
12
+ phone?: string;
13
+ email?: string;
14
+ }
15
+ type PaymentMethod = {
16
+ id: string;
17
+ type: string;
18
+ title: string;
19
+ iconUrl: string;
20
+ default: boolean;
21
+ metadata?: Record<string, unknown>;
22
+ };
23
+ type ExpressOrderLineItem = {
24
+ label: string;
25
+ amount: string;
26
+ };
27
+ type ExpressShippingMethod = {
28
+ label: string;
29
+ amount: string;
30
+ identifier: string;
31
+ detail: string;
32
+ };
33
+ export interface ExpressPaymentContextType {
34
+ applePayPaymentMethod?: PaymentMethod;
35
+ googlePayPaymentMethod?: PaymentMethod;
36
+ reComputeOrderSummary: () => Promise<{
37
+ lineItems: ExpressOrderLineItem[];
38
+ total: {
39
+ label: string;
40
+ amount: string;
41
+ };
42
+ shippingMethods: ExpressShippingMethod[];
43
+ } | undefined>;
44
+ loading?: boolean;
45
+ availableExpressPaymentMethodIds: string[];
46
+ setAvailableExpressPaymentMethodIds: (value: string[]) => void;
47
+ shippingMethods: ExpressShippingMethod[];
48
+ lineItems: ExpressOrderLineItem[];
49
+ handleAddExpressId: (id: string) => void;
50
+ updateCheckoutSessionValues: (input: {
51
+ data: {
52
+ shippingAddress: Address;
53
+ billingAddress?: Address | null;
54
+ };
55
+ }) => Promise<void>;
56
+ updateCustomerEmail: (input: {
57
+ data: {
58
+ email: string;
59
+ };
60
+ }) => Promise<void>;
61
+ error: string | null;
62
+ setError: (error: string | null) => void;
63
+ }
64
+ interface ExpressPaymentProviderProps {
65
+ children: ReactNode;
66
+ customerId?: string;
67
+ checkout?: CheckoutData;
68
+ }
69
+ export declare const ExpressPaymentProvider: React.FC<ExpressPaymentProviderProps>;
70
+ export declare const useExpressPayment: () => ExpressPaymentContextType;
71
+ export {};
@@ -0,0 +1,158 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
3
+ import { useTagadaContext } from '../providers/TagadaProvider';
4
+ import { useOrderSummary } from './useOrderSummary';
5
+ import { useShippingRates } from './useShippingRates';
6
+ const ExpressPaymentContext = createContext(undefined);
7
+ export const ExpressPaymentProvider = ({ children, customerId, checkout, }) => {
8
+ const { apiService } = useTagadaContext();
9
+ const [availableExpressPaymentMethodIds, setAvailableExpressPaymentMethodIds] = useState([]);
10
+ const [error, setError] = useState(null);
11
+ const [paymentMethods, setPaymentMethods] = useState(null);
12
+ const [isLoadingPaymentMethods, setIsLoadingPaymentMethods] = useState(false);
13
+ const checkoutSessionId = checkout?.checkoutSession.id;
14
+ // Fetch enabled payment methods for this checkout session
15
+ React.useEffect(() => {
16
+ let mounted = true;
17
+ const fetchPaymentMethods = async () => {
18
+ try {
19
+ if (!checkoutSessionId)
20
+ return;
21
+ setIsLoadingPaymentMethods(true);
22
+ const response = await apiService.fetch(`/api/v1/payment-methods?checkoutSessionId=${encodeURIComponent(checkoutSessionId)}`);
23
+ if (mounted)
24
+ setPaymentMethods(response);
25
+ }
26
+ catch (e) {
27
+ if (mounted)
28
+ setPaymentMethods([]);
29
+ }
30
+ finally {
31
+ if (mounted)
32
+ setIsLoadingPaymentMethods(false);
33
+ }
34
+ };
35
+ if (checkout)
36
+ void fetchPaymentMethods();
37
+ return () => {
38
+ mounted = false;
39
+ };
40
+ }, [apiService, checkoutSessionId]);
41
+ const handleAddExpressId = (id) => {
42
+ setAvailableExpressPaymentMethodIds((prev) => (prev.includes(id) ? prev : [...prev, id]));
43
+ };
44
+ // Base data hooks
45
+ const { orderSummary, isLoading: isLoadingOrderSummary, isRefetching: isRefetchingOrderSummary, refetch: refetchOrderSummary, } = useOrderSummary({ sessionId: checkoutSessionId });
46
+ const { shippingRates, refetch: refetchRates } = useShippingRates({ checkout });
47
+ const minorUnitsToCurrencyString = (amountMinor, currency) => {
48
+ if (!amountMinor || !currency)
49
+ return '0.00';
50
+ return (amountMinor / 100).toFixed(2);
51
+ };
52
+ const shippingMethods = useMemo(() => (shippingRates || []).map((rate) => ({
53
+ label: rate.shippingRateName,
54
+ amount: minorUnitsToCurrencyString(rate.amount, rate.currency),
55
+ identifier: rate.id,
56
+ detail: rate.description || '',
57
+ })), [shippingRates]);
58
+ const lineItems = useMemo(() => [
59
+ {
60
+ label: 'Subtotal',
61
+ amount: minorUnitsToCurrencyString(orderSummary?.subtotalAdjustedAmount, orderSummary?.currency),
62
+ },
63
+ {
64
+ label: 'Shipping',
65
+ amount: minorUnitsToCurrencyString(orderSummary?.shippingCost ?? 0, orderSummary?.currency),
66
+ },
67
+ {
68
+ label: 'Tax',
69
+ amount: minorUnitsToCurrencyString(orderSummary?.totalTaxAmount, orderSummary?.currency),
70
+ },
71
+ ], [
72
+ orderSummary?.subtotalAdjustedAmount,
73
+ orderSummary?.shippingCost,
74
+ orderSummary?.totalTaxAmount,
75
+ orderSummary?.currency,
76
+ ]);
77
+ const reComputeOrderSummary = useCallback(async () => {
78
+ try {
79
+ await refetchOrderSummary();
80
+ await refetchRates();
81
+ if (!orderSummary || !shippingRates)
82
+ return;
83
+ const recomputedLineItems = [
84
+ {
85
+ label: 'Subtotal',
86
+ amount: minorUnitsToCurrencyString(orderSummary.subtotalAdjustedAmount, orderSummary.currency),
87
+ },
88
+ {
89
+ label: 'Shipping',
90
+ amount: minorUnitsToCurrencyString(orderSummary.shippingCost ?? 0, orderSummary.currency),
91
+ },
92
+ {
93
+ label: 'Tax',
94
+ amount: minorUnitsToCurrencyString(orderSummary.totalTaxAmount, orderSummary.currency),
95
+ },
96
+ ];
97
+ const total = {
98
+ label: 'Order Total',
99
+ amount: minorUnitsToCurrencyString(orderSummary.totalAdjustedAmount, orderSummary.currency),
100
+ };
101
+ const recomputedShippingMethods = (shippingRates || []).map((rate) => ({
102
+ label: rate.shippingRateName,
103
+ amount: minorUnitsToCurrencyString(rate.amount, rate.currency),
104
+ identifier: rate.id,
105
+ detail: rate.description || '',
106
+ }));
107
+ return {
108
+ lineItems: recomputedLineItems,
109
+ total,
110
+ shippingMethods: recomputedShippingMethods,
111
+ };
112
+ }
113
+ catch (e) {
114
+ return undefined;
115
+ }
116
+ }, [orderSummary, shippingRates, refetchOrderSummary, refetchRates]);
117
+ const updateCheckoutSessionValues = useCallback(async (input) => {
118
+ await apiService.fetch(`/api/v1/checkout-sessions/${checkoutSessionId}/address`, {
119
+ method: 'POST',
120
+ body: input,
121
+ });
122
+ }, [apiService, checkoutSessionId]);
123
+ const updateCustomerEmail = useCallback(async (input) => {
124
+ if (!customerId)
125
+ return;
126
+ await apiService.fetch(`/api/v1/customers/${customerId}`, {
127
+ method: 'POST',
128
+ body: input,
129
+ });
130
+ }, [apiService, customerId]);
131
+ const enabledApplePayPaymentMethod = useMemo(() => paymentMethods?.find((p) => p.type === 'apple_pay'), [paymentMethods]);
132
+ const enabledGooglePayPaymentMethod = useMemo(() => paymentMethods?.find((p) => p.type === 'google_pay'), [paymentMethods]);
133
+ const loading = !paymentMethods || isLoadingPaymentMethods || isLoadingOrderSummary;
134
+ const contextValue = {
135
+ availableExpressPaymentMethodIds,
136
+ setAvailableExpressPaymentMethodIds,
137
+ applePayPaymentMethod: enabledApplePayPaymentMethod,
138
+ googlePayPaymentMethod: enabledGooglePayPaymentMethod,
139
+ shippingMethods,
140
+ lineItems,
141
+ reComputeOrderSummary,
142
+ loading,
143
+ handleAddExpressId,
144
+ updateCheckoutSessionValues,
145
+ updateCustomerEmail,
146
+ error,
147
+ setError,
148
+ };
149
+ const hasAnyEnabled = Boolean(enabledApplePayPaymentMethod || enabledGooglePayPaymentMethod);
150
+ return (_jsx(ExpressPaymentContext.Provider, { value: contextValue, children: hasAnyEnabled ? _jsx(_Fragment, { children: children }) : _jsx(_Fragment, {}) }));
151
+ };
152
+ export const useExpressPayment = () => {
153
+ const context = useContext(ExpressPaymentContext);
154
+ if (context === undefined) {
155
+ throw new Error('useExpressPayment must be used within an ExpressPaymentProvider');
156
+ }
157
+ return context;
158
+ };
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Funnel Resource - API client for funnel navigation and session management
3
+ */
4
+ import { ApiClient } from './apiClient';
5
+ export interface FunnelEvent {
6
+ type: string;
7
+ data?: any;
8
+ timestamp?: string;
9
+ }
10
+ export interface FunnelNavigationAction {
11
+ type: 'redirect' | 'replace' | 'push' | 'external' | 'none';
12
+ url?: string;
13
+ data?: any;
14
+ }
15
+ export interface FunnelNavigationResult {
16
+ stepId: string;
17
+ action: FunnelNavigationAction;
18
+ context: SimpleFunnelContext;
19
+ tracking?: {
20
+ from: string;
21
+ to: string;
22
+ event: string;
23
+ timestamp: string;
24
+ };
25
+ }
26
+ export interface SimpleFunnelContext {
27
+ customerId: string;
28
+ storeId: string;
29
+ sessionId: string;
30
+ funnelId: string;
31
+ currentStepId: string;
32
+ previousStepId?: string;
33
+ startedAt: number;
34
+ lastActivityAt: number;
35
+ metadata?: Record<string, any>;
36
+ }
37
+ export interface FunnelInitializeRequest {
38
+ cmsSession: {
39
+ customerId: string;
40
+ storeId: string;
41
+ sessionId: string;
42
+ accountId: string;
43
+ };
44
+ funnelId?: string;
45
+ entryStepId?: string;
46
+ existingSessionId?: string;
47
+ }
48
+ export interface FunnelInitializeResponse {
49
+ success: boolean;
50
+ context?: SimpleFunnelContext;
51
+ error?: string;
52
+ }
53
+ export interface FunnelNavigateRequest {
54
+ sessionId: string;
55
+ event: FunnelEvent;
56
+ contextUpdates?: Partial<SimpleFunnelContext>;
57
+ }
58
+ export interface FunnelNavigateResponse {
59
+ success: boolean;
60
+ result?: {
61
+ stepId: string;
62
+ url?: string;
63
+ tracking?: {
64
+ from: string;
65
+ to: string;
66
+ event: string;
67
+ timestamp: string;
68
+ };
69
+ };
70
+ error?: string;
71
+ }
72
+ export interface FunnelContextUpdateRequest {
73
+ contextUpdates: Partial<SimpleFunnelContext>;
74
+ }
75
+ export interface FunnelContextUpdateResponse {
76
+ success: boolean;
77
+ error?: string;
78
+ }
79
+ export declare class FunnelResource {
80
+ private apiClient;
81
+ constructor(apiClient: ApiClient);
82
+ /**
83
+ * Initialize a funnel session
84
+ */
85
+ initialize(request: FunnelInitializeRequest): Promise<FunnelInitializeResponse>;
86
+ /**
87
+ * Navigate to next step in funnel
88
+ */
89
+ navigate(request: FunnelNavigateRequest): Promise<FunnelNavigateResponse>;
90
+ /**
91
+ * Update funnel context
92
+ */
93
+ updateContext(sessionId: string, request: FunnelContextUpdateRequest): Promise<FunnelContextUpdateResponse>;
94
+ /**
95
+ * End funnel session
96
+ */
97
+ endSession(sessionId: string): Promise<{
98
+ success: boolean;
99
+ error?: string;
100
+ }>;
101
+ /**
102
+ * Get funnel session by ID
103
+ */
104
+ getSession(sessionId: string): Promise<{
105
+ success: boolean;
106
+ context?: SimpleFunnelContext;
107
+ error?: string;
108
+ }>;
109
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Funnel Resource - API client for funnel navigation and session management
3
+ */
4
+ export class FunnelResource {
5
+ constructor(apiClient) {
6
+ this.apiClient = apiClient;
7
+ }
8
+ /**
9
+ * Initialize a funnel session
10
+ */
11
+ async initialize(request) {
12
+ return this.apiClient.post('/api/v1/funnel/initialize', request);
13
+ }
14
+ /**
15
+ * Navigate to next step in funnel
16
+ */
17
+ async navigate(request) {
18
+ return this.apiClient.post('/api/v1/funnel/navigate', request);
19
+ }
20
+ /**
21
+ * Update funnel context
22
+ */
23
+ async updateContext(sessionId, request) {
24
+ return this.apiClient.patch(`/api/v1/funnel/context/${sessionId}`, request);
25
+ }
26
+ /**
27
+ * End funnel session
28
+ */
29
+ async endSession(sessionId) {
30
+ return this.apiClient.delete(`/api/v1/funnel/session/${sessionId}`);
31
+ }
32
+ /**
33
+ * Get funnel session by ID
34
+ */
35
+ async getSession(sessionId) {
36
+ return this.apiClient.get(`/api/v1/funnel/session/${sessionId}`);
37
+ }
38
+ }
@@ -15,3 +15,4 @@ export * from './shippingRates';
15
15
  export * from './storeConfig';
16
16
  export * from './threeds';
17
17
  export * from './vipOffers';
18
+ export * from './funnel';
@@ -15,3 +15,4 @@ export * from './shippingRates';
15
15
  export * from './storeConfig';
16
16
  export * from './threeds';
17
17
  export * from './vipOffers';
18
+ export * from './funnel';
@@ -20,4 +20,6 @@ export type { ShippingRate, ShippingRatesResponse } from './core/resources/shipp
20
20
  export type { ApplyDiscountResponse, Discount, DiscountCodeValidation, RemoveDiscountResponse } from './core/resources/discounts';
21
21
  export type { ToggleOrderBumpResponse, VipOffer, VipPreviewResponse } from './core/resources/vipOffers';
22
22
  export type { StoreConfig } from './core/resources/storeConfig';
23
- export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useCheckout, useCheckoutToken, useCountryOptions, useCurrency, useDiscounts, useExpressPaymentMethods, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useShippingRates, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useVipOffers } from './react';
23
+ export type { FunnelContextUpdateRequest, FunnelContextUpdateResponse, FunnelEvent, FunnelInitializeRequest, FunnelInitializeResponse, FunnelNavigateRequest, FunnelNavigateResponse, FunnelNavigationAction, FunnelNavigationResult, SimpleFunnelContext } from './core/resources/funnel';
24
+ export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useCheckout, useCheckoutToken, useCountryOptions, useCurrency, useDiscountQuery, useDiscounts, useExpressPaymentMethods, useFunnel, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useShippingRates, useSimpleFunnel, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useVipOffers } from './react';
25
+ export type { StoreDiscount } from './react';
package/dist/v2/index.js CHANGED
@@ -12,4 +12,4 @@ export * from './core/utils/currency';
12
12
  export * from './core/utils/pluginConfig';
13
13
  export * from './core/utils/products';
14
14
  // React exports (hooks and components only, types are exported above)
15
- export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useCheckout, useCheckoutToken, useCountryOptions, useCurrency, useDiscounts, useExpressPaymentMethods, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useShippingRates, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useVipOffers } from './react';
15
+ export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useCheckout, useCheckoutToken, useCountryOptions, useCurrency, useDiscountQuery, useDiscounts, useExpressPaymentMethods, useFunnel, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useShippingRates, useSimpleFunnel, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useVipOffers } from './react';
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Single Discount Hook using TanStack Query
3
+ * Fetches a specific discount for a given store
4
+ */
5
+ import { UseQueryResult } from '@tanstack/react-query';
6
+ export interface StoreDiscountRuleAmount {
7
+ rate: number;
8
+ amount: number;
9
+ lock: boolean;
10
+ date: string;
11
+ }
12
+ export interface StoreDiscountRule {
13
+ id: string;
14
+ createdAt: string;
15
+ updatedAt: string;
16
+ promotionId: string;
17
+ type: string;
18
+ productId: string | null;
19
+ minimumQuantity: number | null;
20
+ minimumAmount: Record<string, StoreDiscountRuleAmount> | null;
21
+ variantIds: string[] | null;
22
+ }
23
+ export interface StoreDiscountAction {
24
+ id: string;
25
+ createdAt: string;
26
+ updatedAt: string;
27
+ promotionId: string;
28
+ type: string;
29
+ adjustmentAmount: number | null;
30
+ adjustmentPercentage: number | null;
31
+ adjustmentType: string | null;
32
+ freeShipping: boolean | null;
33
+ priceIdToAdd: string | null;
34
+ productIdToAdd: string | null;
35
+ variantIdToAdd: string | null;
36
+ subscriptionFreeTrialDuration: number | null;
37
+ subscriptionFreeTrialDurationType: string | null;
38
+ targetProductId: string | null;
39
+ targetVariantIds: string[] | null;
40
+ maxQuantityDiscounted: number | null;
41
+ appliesOnEachItem: boolean | null;
42
+ }
43
+ export interface StoreDiscount {
44
+ id: string;
45
+ createdAt: string;
46
+ updatedAt: string;
47
+ storeId: string;
48
+ accountId: string;
49
+ name: string;
50
+ code: string;
51
+ automatic: boolean;
52
+ usageLimit: number | null;
53
+ usageCount: number;
54
+ startDate: string;
55
+ endDate: string | null;
56
+ enabled: boolean;
57
+ archived: boolean;
58
+ ruleOperator: string;
59
+ externalId: string | null;
60
+ combinesWithOrderLevelDiscounts: boolean;
61
+ combinesWithLineItemDiscounts: boolean;
62
+ combinesWithShippingDiscounts: boolean;
63
+ forceCombine: boolean;
64
+ isTemporary: boolean;
65
+ rules: StoreDiscountRule[];
66
+ actions: StoreDiscountAction[];
67
+ }
68
+ export interface UseDiscountQueryOptions {
69
+ storeId?: string;
70
+ discountId?: string;
71
+ enabled?: boolean;
72
+ }
73
+ export interface UseDiscountQueryResult<TData = StoreDiscount> {
74
+ discount: TData | undefined;
75
+ isLoading: boolean;
76
+ error: Error | null;
77
+ refetch: UseQueryResult<TData>['refetch'];
78
+ }
79
+ export declare function useDiscountQuery<TData = StoreDiscount>(options: UseDiscountQueryOptions): UseDiscountQueryResult<TData>;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Single Discount Hook using TanStack Query
3
+ * Fetches a specific discount for a given store
4
+ */
5
+ import { useMemo } from 'react';
6
+ import { useApiQuery } from './useApiQuery';
7
+ import { usePluginConfig } from './usePluginConfig';
8
+ export function useDiscountQuery(options) {
9
+ const { storeId: storeIdFromConfig } = usePluginConfig();
10
+ const { storeId = storeIdFromConfig, discountId, enabled = true } = options;
11
+ const key = useMemo(() => ['discount', storeId, discountId], [storeId, discountId]);
12
+ const url = useMemo(() => {
13
+ if (!storeId || !discountId)
14
+ return null;
15
+ return `/api/v1/stores/${storeId}/discounts/${discountId}`;
16
+ }, [storeId, discountId]);
17
+ const query = useApiQuery(key, url, { enabled });
18
+ return {
19
+ discount: query.data,
20
+ isLoading: query.isLoading,
21
+ error: query.error || null,
22
+ refetch: query.refetch,
23
+ };
24
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * useFunnel Hook (v2) - TanStack Query-based funnel navigation
3
+ *
4
+ * Modern implementation using TanStack Query for state management
5
+ * and the v2 ApiClient for API calls.
6
+ */
7
+ import { FunnelEvent, FunnelNavigationResult, SimpleFunnelContext } from '../../core/resources/funnel';
8
+ export interface UseFunnelOptions {
9
+ funnelId?: string;
10
+ currentStepId?: string;
11
+ onNavigate?: (result: FunnelNavigationResult) => void | boolean;
12
+ onError?: (error: Error) => void;
13
+ autoInitialize?: boolean;
14
+ enabled?: boolean;
15
+ }
16
+ export interface UseFunnelResult {
17
+ next: (event: FunnelEvent) => Promise<any>;
18
+ goToStep: (stepId: string) => Promise<any>;
19
+ updateContext: (updates: Partial<SimpleFunnelContext>) => Promise<void>;
20
+ currentStep: {
21
+ id: string;
22
+ };
23
+ context: SimpleFunnelContext | null;
24
+ isLoading: boolean;
25
+ isInitialized: boolean;
26
+ initializeSession: (entryStepId?: string) => Promise<void>;
27
+ endSession: () => Promise<void>;
28
+ retryInitialization: () => Promise<void>;
29
+ initializationError: Error | null;
30
+ isSessionLoading: boolean;
31
+ sessionError: Error | null;
32
+ refetch: () => void;
33
+ }
34
+ /**
35
+ * React Hook for Funnel Navigation (Plugin SDK v2)
36
+ *
37
+ * Modern funnel navigation using TanStack Query for state management
38
+ * and the v2 ApiClient architecture.
39
+ */
40
+ export declare function useFunnel(options: UseFunnelOptions): UseFunnelResult;
41
+ /**
42
+ * Simplified funnel hook for basic step tracking (v2)
43
+ */
44
+ export declare function useSimpleFunnel(funnelId: string, initialStepId?: string): {
45
+ currentStepId: string;
46
+ next: (event: FunnelEvent) => Promise<any>;
47
+ goToStep: (stepId: string) => Promise<any>;
48
+ isLoading: boolean;
49
+ context: SimpleFunnelContext | null;
50
+ };
51
+ export type { FunnelEvent, FunnelNavigationAction, FunnelNavigationResult, SimpleFunnelContext } from '../../core/resources/funnel';
@@ -0,0 +1,432 @@
1
+ /**
2
+ * useFunnel Hook (v2) - TanStack Query-based funnel navigation
3
+ *
4
+ * Modern implementation using TanStack Query for state management
5
+ * and the v2 ApiClient for API calls.
6
+ */
7
+ import { useState, useCallback, useEffect, useMemo } from 'react';
8
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
9
+ import { useTagadaContext } from '../providers/TagadaProvider';
10
+ import { FunnelResource } from '../../core/resources/funnel';
11
+ import { getGlobalApiClient } from './useApiQuery';
12
+ // Query keys for funnel operations
13
+ const funnelQueryKeys = {
14
+ session: (sessionId) => ['funnel', 'session', sessionId],
15
+ context: (sessionId) => ['funnel', 'context', sessionId],
16
+ };
17
+ /**
18
+ * React Hook for Funnel Navigation (Plugin SDK v2)
19
+ *
20
+ * Modern funnel navigation using TanStack Query for state management
21
+ * and the v2 ApiClient architecture.
22
+ */
23
+ export function useFunnel(options) {
24
+ const { auth, store } = useTagadaContext();
25
+ const queryClient = useQueryClient();
26
+ const apiClient = getGlobalApiClient();
27
+ const funnelResource = useMemo(() => new FunnelResource(apiClient), [apiClient]);
28
+ // Local state
29
+ const [context, setContext] = useState(null);
30
+ const [initializationAttempted, setInitializationAttempted] = useState(false);
31
+ const [initializationError, setInitializationError] = useState(null);
32
+ const currentStepId = options.currentStepId || context?.currentStepId;
33
+ // Check for URL parameter overrides
34
+ const urlParams = typeof window !== 'undefined' ? new URLSearchParams(window.location.search) : new URLSearchParams();
35
+ const urlFunnelId = urlParams.get('funnelId') || undefined;
36
+ const effectiveFunnelId = urlFunnelId || options.funnelId;
37
+ // Session query - only enabled when we have a session ID
38
+ const { data: sessionData, isLoading: isSessionLoading, error: sessionError, refetch: refetchSession } = useQuery({
39
+ queryKey: funnelQueryKeys.session(context?.sessionId || ''),
40
+ queryFn: async () => {
41
+ if (!context?.sessionId) {
42
+ console.warn('🍪 Funnel: No session ID available for query');
43
+ return null;
44
+ }
45
+ console.log(`🍪 Funnel: Fetching session data for ID: ${context.sessionId}`);
46
+ const response = await funnelResource.getSession(context.sessionId);
47
+ console.log(`🍪 Funnel: Session fetch response:`, response);
48
+ if (response.success && response.context) {
49
+ return response.context;
50
+ }
51
+ throw new Error(response.error || 'Failed to fetch session');
52
+ },
53
+ enabled: !!context?.sessionId && (options.enabled !== false),
54
+ staleTime: 30000, // 30 seconds
55
+ gcTime: 5 * 60 * 1000, // 5 minutes
56
+ refetchOnWindowFocus: false,
57
+ });
58
+ // Initialize session mutation
59
+ const initializeMutation = useMutation({
60
+ mutationFn: async (entryStepId) => {
61
+ if (!auth.session?.customerId || !store?.id) {
62
+ throw new Error('Authentication required for funnel session');
63
+ }
64
+ // Check for existing session ID in URL parameters
65
+ let existingSessionId = urlParams.get('funnelSessionId') || undefined;
66
+ if (existingSessionId) {
67
+ console.log(`🍪 Funnel: Found session ID in URL params: ${existingSessionId}`);
68
+ }
69
+ else {
70
+ // Fallback to cookie for same-domain scenarios
71
+ const funnelSessionCookie = document.cookie
72
+ .split('; ')
73
+ .find(row => row.startsWith('tgd-funnel-session-id='));
74
+ existingSessionId = funnelSessionCookie ? funnelSessionCookie.split('=')[1] : undefined;
75
+ if (existingSessionId) {
76
+ console.log(`🍪 Funnel: Found session in cookie: ${existingSessionId}`);
77
+ }
78
+ }
79
+ if (!existingSessionId) {
80
+ console.log(`🍪 Funnel: No existing session found in URL params or cookie`);
81
+ }
82
+ // Send minimal CMS session data
83
+ const cmsSessionData = {
84
+ customerId: auth.session.customerId,
85
+ storeId: store.id,
86
+ sessionId: auth.session.sessionId,
87
+ accountId: auth.session.accountId
88
+ };
89
+ // Call API to initialize session - backend will restore existing or create new
90
+ const requestBody = {
91
+ cmsSession: cmsSessionData,
92
+ entryStepId, // Optional override
93
+ existingSessionId // Pass existing session ID from URL or cookie
94
+ };
95
+ // Only include funnelId if it's provided (for backend fallback)
96
+ if (effectiveFunnelId) {
97
+ requestBody.funnelId = effectiveFunnelId;
98
+ }
99
+ const response = await funnelResource.initialize(requestBody);
100
+ if (response.success && response.context) {
101
+ return response.context;
102
+ }
103
+ else {
104
+ throw new Error(response.error || 'Failed to initialize funnel session');
105
+ }
106
+ },
107
+ onSuccess: (newContext) => {
108
+ setContext(newContext);
109
+ setInitializationError(null);
110
+ // Set session cookie for persistence across page reloads
111
+ setSessionCookie(newContext.sessionId);
112
+ console.log(`🍪 Funnel: Initialized session for funnel ${effectiveFunnelId || 'default'}`, newContext);
113
+ // Invalidate session query to refetch with new session ID
114
+ void queryClient.invalidateQueries({
115
+ queryKey: funnelQueryKeys.session(newContext.sessionId)
116
+ });
117
+ },
118
+ onError: (error) => {
119
+ const errorObj = error instanceof Error ? error : new Error(String(error));
120
+ setInitializationError(errorObj);
121
+ console.error('Error initializing funnel session:', error);
122
+ if (options.onError) {
123
+ options.onError(errorObj);
124
+ }
125
+ }
126
+ });
127
+ // Navigate mutation
128
+ const navigateMutation = useMutation({
129
+ mutationFn: async (event) => {
130
+ if (!context) {
131
+ throw new Error('Funnel session not initialized');
132
+ }
133
+ if (!context.sessionId) {
134
+ throw new Error('Funnel session ID missing - session may be corrupted');
135
+ }
136
+ console.log(`🍪 Funnel: Navigating with session ID: ${context.sessionId}`);
137
+ const requestBody = {
138
+ sessionId: context.sessionId,
139
+ event: {
140
+ type: event.type,
141
+ data: event.data,
142
+ timestamp: event.timestamp || new Date().toISOString()
143
+ },
144
+ contextUpdates: {
145
+ lastActivityAt: Date.now()
146
+ }
147
+ };
148
+ const response = await funnelResource.navigate(requestBody);
149
+ if (response.success && response.result) {
150
+ return response.result;
151
+ }
152
+ else {
153
+ throw new Error(response.error || 'Navigation failed');
154
+ }
155
+ },
156
+ onSuccess: (result) => {
157
+ if (!context)
158
+ return;
159
+ // Update local context
160
+ const newContext = {
161
+ ...context,
162
+ currentStepId: result.stepId,
163
+ previousStepId: context.currentStepId,
164
+ lastActivityAt: Date.now(),
165
+ metadata: {
166
+ ...context.metadata,
167
+ lastEvent: 'navigation',
168
+ lastTransition: new Date().toISOString()
169
+ }
170
+ };
171
+ setContext(newContext);
172
+ // Create typed navigation result
173
+ const navigationResult = {
174
+ stepId: result.stepId,
175
+ action: {
176
+ type: 'redirect', // Default action type
177
+ url: result.url
178
+ },
179
+ context: newContext,
180
+ tracking: result.tracking
181
+ };
182
+ // Handle navigation callback with override capability
183
+ let shouldPerformDefaultNavigation = true;
184
+ if (options.onNavigate) {
185
+ const callbackResult = options.onNavigate(navigationResult);
186
+ if (callbackResult === false) {
187
+ shouldPerformDefaultNavigation = false;
188
+ }
189
+ }
190
+ // Perform default navigation if not overridden
191
+ if (shouldPerformDefaultNavigation && navigationResult.action.url) {
192
+ // Add URL parameters for cross-domain session continuity
193
+ const urlWithParams = addSessionParams(navigationResult.action.url, newContext.sessionId, effectiveFunnelId || options.funnelId);
194
+ const updatedAction = { ...navigationResult.action, url: urlWithParams };
195
+ performNavigation(updatedAction);
196
+ }
197
+ console.log(`🍪 Funnel: Navigated from ${context.currentStepId} to ${result.stepId}`);
198
+ // Invalidate and refetch session data
199
+ void queryClient.invalidateQueries({
200
+ queryKey: funnelQueryKeys.session(newContext.sessionId)
201
+ });
202
+ },
203
+ onError: (error) => {
204
+ console.error('Funnel navigation error:', error);
205
+ if (options.onError) {
206
+ options.onError(error instanceof Error ? error : new Error(String(error)));
207
+ }
208
+ }
209
+ });
210
+ // Update context mutation
211
+ const updateContextMutation = useMutation({
212
+ mutationFn: async (updates) => {
213
+ if (!context) {
214
+ throw new Error('Funnel session not initialized');
215
+ }
216
+ const requestBody = {
217
+ contextUpdates: updates
218
+ };
219
+ const response = await funnelResource.updateContext(context.sessionId, requestBody);
220
+ if (response.success) {
221
+ return updates;
222
+ }
223
+ else {
224
+ throw new Error(response.error || 'Context update failed');
225
+ }
226
+ },
227
+ onSuccess: (updates) => {
228
+ if (!context)
229
+ return;
230
+ const updatedContext = {
231
+ ...context,
232
+ ...updates,
233
+ lastActivityAt: Date.now()
234
+ };
235
+ setContext(updatedContext);
236
+ console.log(`🍪 Funnel: Updated context for step ${context.currentStepId}`);
237
+ // Invalidate session query
238
+ void queryClient.invalidateQueries({
239
+ queryKey: funnelQueryKeys.session(context.sessionId)
240
+ });
241
+ },
242
+ onError: (error) => {
243
+ console.error('Error updating funnel context:', error);
244
+ if (options.onError) {
245
+ options.onError(error instanceof Error ? error : new Error(String(error)));
246
+ }
247
+ }
248
+ });
249
+ // End session mutation
250
+ const endSessionMutation = useMutation({
251
+ mutationFn: async () => {
252
+ if (!context)
253
+ return;
254
+ await funnelResource.endSession(context.sessionId);
255
+ },
256
+ onSuccess: () => {
257
+ if (!context)
258
+ return;
259
+ console.log(`🍪 Funnel: Ended session ${context.sessionId}`);
260
+ setContext(null);
261
+ // Clear queries
262
+ queryClient.removeQueries({
263
+ queryKey: funnelQueryKeys.session(context.sessionId)
264
+ });
265
+ },
266
+ onError: (error) => {
267
+ console.error('Error ending funnel session:', error);
268
+ // Don't throw here - session ending is best effort
269
+ }
270
+ });
271
+ /**
272
+ * Set funnel session cookie
273
+ */
274
+ const setSessionCookie = useCallback((sessionId) => {
275
+ const maxAge = 24 * 60 * 60; // 24 hours
276
+ const expires = new Date(Date.now() + maxAge * 1000).toUTCString();
277
+ // Set cookie for same-domain scenarios
278
+ document.cookie = `tgd-funnel-session-id=${sessionId}; path=/; expires=${expires}; SameSite=Lax`;
279
+ console.log(`🍪 Funnel: Set session cookie: ${sessionId}`);
280
+ }, []);
281
+ /**
282
+ * Add session parameters to URL for cross-domain continuity
283
+ */
284
+ const addSessionParams = useCallback((url, sessionId, funnelId) => {
285
+ try {
286
+ const urlObj = new URL(url);
287
+ urlObj.searchParams.set('funnelSessionId', sessionId);
288
+ if (funnelId) {
289
+ urlObj.searchParams.set('funnelId', funnelId);
290
+ }
291
+ const urlWithParams = urlObj.toString();
292
+ console.log(`🍪 Funnel: Added session params to URL: ${url} → ${urlWithParams}`);
293
+ return urlWithParams;
294
+ }
295
+ catch (error) {
296
+ console.warn('Failed to add session params to URL:', error);
297
+ return url; // Return original URL if parsing fails
298
+ }
299
+ }, []);
300
+ /**
301
+ * Perform navigation based on action type
302
+ */
303
+ const performNavigation = useCallback((action) => {
304
+ if (!action.url)
305
+ return;
306
+ // Handle relative URLs by making them absolute
307
+ let targetUrl = action.url;
308
+ if (targetUrl.startsWith('/') && !targetUrl.startsWith('//')) {
309
+ // Relative URL - use current origin
310
+ targetUrl = window.location.origin + targetUrl;
311
+ }
312
+ switch (action.type) {
313
+ case 'redirect':
314
+ console.log(`🍪 Funnel: Redirecting to ${targetUrl}`);
315
+ window.location.href = targetUrl;
316
+ break;
317
+ case 'replace':
318
+ console.log(`🍪 Funnel: Replacing current page with ${targetUrl}`);
319
+ window.location.replace(targetUrl);
320
+ break;
321
+ case 'push':
322
+ console.log(`🍪 Funnel: Pushing to history: ${targetUrl}`);
323
+ window.history.pushState({}, '', targetUrl);
324
+ // Trigger a popstate event to update React Router
325
+ window.dispatchEvent(new PopStateEvent('popstate'));
326
+ break;
327
+ case 'external':
328
+ console.log(`🍪 Funnel: Opening external URL: ${targetUrl}`);
329
+ window.open(targetUrl, '_blank');
330
+ break;
331
+ case 'none':
332
+ console.log(`🍪 Funnel: No navigation action required`);
333
+ break;
334
+ default:
335
+ console.warn(`🍪 Funnel: Unknown navigation action type: ${action.type}`);
336
+ break;
337
+ }
338
+ }, []);
339
+ // Public API methods
340
+ const initializeSession = useCallback(async (entryStepId) => {
341
+ setInitializationAttempted(true);
342
+ await initializeMutation.mutateAsync(entryStepId);
343
+ }, [initializeMutation]);
344
+ const next = useCallback(async (event) => {
345
+ return navigateMutation.mutateAsync(event);
346
+ }, [navigateMutation]);
347
+ const goToStep = useCallback(async (stepId) => {
348
+ return next({
349
+ type: 'direct_navigation',
350
+ data: { targetStepId: stepId },
351
+ timestamp: new Date().toISOString()
352
+ });
353
+ }, [next]);
354
+ const updateContext = useCallback(async (updates) => {
355
+ await updateContextMutation.mutateAsync(updates);
356
+ }, [updateContextMutation]);
357
+ const endSession = useCallback(async () => {
358
+ await endSessionMutation.mutateAsync();
359
+ }, [endSessionMutation]);
360
+ const retryInitialization = useCallback(async () => {
361
+ setInitializationAttempted(false);
362
+ setInitializationError(null);
363
+ await initializeSession();
364
+ }, [initializeSession]);
365
+ // Auto-initialize if requested and not already initialized
366
+ useEffect(() => {
367
+ if (options.autoInitialize &&
368
+ !context &&
369
+ !initializationAttempted &&
370
+ !initializationError &&
371
+ auth.session?.customerId &&
372
+ store?.id &&
373
+ !initializeMutation.isPending) {
374
+ console.log('🍪 Funnel: Auto-initializing session...');
375
+ initializeSession().catch(error => {
376
+ console.error('Auto-initialization failed - will not retry:', error);
377
+ });
378
+ }
379
+ }, [
380
+ options.autoInitialize,
381
+ context,
382
+ initializationAttempted,
383
+ initializationError,
384
+ auth.session?.customerId,
385
+ store?.id,
386
+ initializeMutation.isPending,
387
+ initializeSession
388
+ ]);
389
+ // Sync session data from query to local state
390
+ useEffect(() => {
391
+ if (sessionData && sessionData !== context) {
392
+ setContext(sessionData);
393
+ }
394
+ }, [sessionData, context]);
395
+ const isLoading = initializeMutation.isPending || navigateMutation.isPending || updateContextMutation.isPending;
396
+ const isInitialized = !!context;
397
+ return {
398
+ next,
399
+ goToStep,
400
+ updateContext,
401
+ currentStep: {
402
+ id: currentStepId || 'unknown'
403
+ },
404
+ context,
405
+ isLoading,
406
+ isInitialized,
407
+ initializeSession,
408
+ endSession,
409
+ retryInitialization,
410
+ initializationError,
411
+ isSessionLoading,
412
+ sessionError,
413
+ refetch: () => void refetchSession()
414
+ };
415
+ }
416
+ /**
417
+ * Simplified funnel hook for basic step tracking (v2)
418
+ */
419
+ export function useSimpleFunnel(funnelId, initialStepId) {
420
+ const funnel = useFunnel({
421
+ funnelId,
422
+ currentStepId: initialStepId,
423
+ autoInitialize: true
424
+ });
425
+ return {
426
+ currentStepId: funnel.currentStep.id,
427
+ next: funnel.next,
428
+ goToStep: funnel.goToStep,
429
+ isLoading: funnel.isLoading,
430
+ context: funnel.context
431
+ };
432
+ }
@@ -2,8 +2,8 @@
2
2
  * Order Hook using TanStack Query
3
3
  * Handles order creation and management with automatic caching
4
4
  */
5
+ import { useMutation, useQuery } from '@tanstack/react-query';
5
6
  import { useMemo } from 'react';
6
- import { useQuery, useMutation } from '@tanstack/react-query';
7
7
  import { OrdersResource } from '../../core/resources/orders';
8
8
  import { getGlobalApiClient } from './useApiQuery';
9
9
  export function useOrderQuery(options = {}) {
@@ -2,7 +2,7 @@
2
2
  * Post Purchases Hook using TanStack Query
3
3
  * Handles post-purchase offers with automatic caching
4
4
  */
5
- import { PostPurchaseOffer, PostPurchaseOfferItem, PostPurchaseOfferSummary, CheckoutSessionState, OrderSummary, CurrencyOptions } from '../../core/resources/postPurchases';
5
+ import { CheckoutSessionState, CurrencyOptions, OrderSummary, PostPurchaseOffer, PostPurchaseOfferItem, PostPurchaseOfferSummary } from '../../core/resources/postPurchases';
6
6
  export interface UsePostPurchasesQueryOptions {
7
7
  orderId: string;
8
8
  enabled?: boolean;
@@ -2,8 +2,8 @@
2
2
  * Post Purchases Hook using TanStack Query
3
3
  * Handles post-purchase offers with automatic caching
4
4
  */
5
- import { useMemo, useEffect, useState, useCallback } from 'react';
6
- import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
5
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
6
+ import { useCallback, useEffect, useMemo, useState } from 'react';
7
7
  import { PostPurchasesResource } from '../../core/resources/postPurchases';
8
8
  import { useTagadaContext } from '../providers/TagadaProvider';
9
9
  import { getGlobalApiClient } from './useApiQuery';
@@ -15,6 +15,7 @@ export { usePluginConfig } from './hooks/usePluginConfig';
15
15
  export { queryKeys, useApiMutation, useApiQuery, useInvalidateQuery, usePreloadQuery } from './hooks/useApiQuery';
16
16
  export { useCheckoutQuery as useCheckout } from './hooks/useCheckoutQuery';
17
17
  export { useCurrency } from './hooks/useCurrency';
18
+ export { useDiscountQuery } from './hooks/useDiscountQuery';
18
19
  export { useDiscountsQuery as useDiscounts } from './hooks/useDiscountsQuery';
19
20
  export { useOffersQuery as useOffers } from './hooks/useOffersQuery';
20
21
  export { useOrderBumpQuery as useOrderBump } from './hooks/useOrderBumpQuery';
@@ -28,6 +29,7 @@ export { useStoreConfigQuery as useStoreConfig } from './hooks/useStoreConfigQue
28
29
  export { useThreeds } from './hooks/useThreeds';
29
30
  export { useThreedsModal } from './hooks/useThreedsModal';
30
31
  export { useVipOffersQuery as useVipOffers } from './hooks/useVipOffersQuery';
32
+ export { useFunnel, useSimpleFunnel } from './hooks/useFunnel';
31
33
  export type { UseCheckoutTokenOptions, UseCheckoutTokenResult } from './hooks/useCheckoutToken';
32
34
  export type { ExpressPaymentMethodsContextType, ExpressPaymentMethodsProviderProps } from './hooks/useExpressPaymentMethods';
33
35
  export type { ApplePayButtonProps } from './components/ApplePayButton';
@@ -37,7 +39,9 @@ export type { ExtractedAddress, GooglePlaceDetails, GooglePrediction, UseGoogleA
37
39
  export type { ISOCountry, ISORegion, UseISODataResult } from './hooks/useISOData';
38
40
  export type { UsePluginConfigOptions, UsePluginConfigResult } from './hooks/usePluginConfig';
39
41
  export type { UseCheckoutQueryOptions as UseCheckoutOptions, UseCheckoutQueryResult as UseCheckoutResult } from './hooks/useCheckoutQuery';
42
+ export type { StoreDiscount, UseDiscountQueryOptions as UseDiscountOptions, UseDiscountQueryResult as UseDiscountResult } from './hooks/useDiscountQuery';
40
43
  export type { UseDiscountsQueryOptions as UseDiscountsOptions, UseDiscountsQueryResult as UseDiscountsResult } from './hooks/useDiscountsQuery';
44
+ export type { FunnelEvent, FunnelNavigationAction, FunnelNavigationResult, SimpleFunnelContext, UseFunnelOptions, UseFunnelResult } from './hooks/useFunnel';
41
45
  export type { UseOffersQueryOptions as UseOffersOptions, UseOffersQueryResult as UseOffersResult } from './hooks/useOffersQuery';
42
46
  export type { UseOrderBumpQueryOptions as UseOrderBumpOptions, UseOrderBumpQueryResult as UseOrderBumpResult } from './hooks/useOrderBumpQuery';
43
47
  export type { UseOrderQueryOptions as UseOrderOptions, UseOrderQueryResult as UseOrderResult } from './hooks/useOrderQuery';
@@ -19,6 +19,7 @@ export { usePluginConfig } from './hooks/usePluginConfig';
19
19
  export { queryKeys, useApiMutation, useApiQuery, useInvalidateQuery, usePreloadQuery } from './hooks/useApiQuery';
20
20
  export { useCheckoutQuery as useCheckout } from './hooks/useCheckoutQuery';
21
21
  export { useCurrency } from './hooks/useCurrency';
22
+ export { useDiscountQuery } from './hooks/useDiscountQuery';
22
23
  export { useDiscountsQuery as useDiscounts } from './hooks/useDiscountsQuery';
23
24
  export { useOffersQuery as useOffers } from './hooks/useOffersQuery';
24
25
  export { useOrderBumpQuery as useOrderBump } from './hooks/useOrderBumpQuery';
@@ -32,5 +33,7 @@ export { useStoreConfigQuery as useStoreConfig } from './hooks/useStoreConfigQue
32
33
  export { useThreeds } from './hooks/useThreeds';
33
34
  export { useThreedsModal } from './hooks/useThreedsModal';
34
35
  export { useVipOffersQuery as useVipOffers } from './hooks/useVipOffersQuery';
36
+ // Funnel hooks
37
+ export { useFunnel, useSimpleFunnel } from './hooks/useFunnel';
35
38
  // Re-export utilities from main react
36
39
  export { formatMoney } from '../../react/utils/money';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tagadapay/plugin-sdk",
3
- "version": "2.6.11",
3
+ "version": "2.6.12",
4
4
  "description": "Modern React SDK for building Tagada Pay plugins",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",