@tagadapay/plugin-sdk 1.0.10 → 1.0.11

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.
@@ -273,6 +273,12 @@ export interface UseCheckoutResult {
273
273
  shippingCountryChanged?: boolean;
274
274
  billingCountryChanged?: boolean;
275
275
  }>;
276
+ previewOrderSummary: (orderBumpOfferIds: string[], orderBumpType?: 'primary' | 'secondary' | 'vip') => Promise<{
277
+ savings: number;
278
+ savingsPct: number;
279
+ currency: string;
280
+ error?: any;
281
+ }>;
276
282
  clear: () => void;
277
283
  }
278
284
  export declare function useCheckout(options?: UseCheckoutOptions): UseCheckoutResult;
@@ -3,7 +3,7 @@ import { useTagadaContext } from '../providers/TagadaProvider';
3
3
  import { getCheckoutToken } from '../utils/urlUtils';
4
4
  import { useCurrency } from '../hooks/useCurrency';
5
5
  export function useCheckout(options = {}) {
6
- const { apiService } = useTagadaContext();
6
+ const { apiService, updateCheckoutDebugData } = useTagadaContext();
7
7
  const { code: currentCurrency } = useCurrency();
8
8
  const [checkout, setCheckout] = useState(null);
9
9
  const [isLoading, setIsLoading] = useState(false);
@@ -21,6 +21,38 @@ export function useCheckout(options = {}) {
21
21
  }
22
22
  };
23
23
  }, []);
24
+ // Update debug data whenever checkout state changes with comprehensive information
25
+ useEffect(() => {
26
+ const debugData = checkout
27
+ ? {
28
+ checkout,
29
+ sessionId: checkout.checkoutSession?.id,
30
+ checkoutToken: currentCheckoutTokenRef.current,
31
+ currency: checkout.summary?.currency,
32
+ totalAmount: checkout.summary?.totalAmount,
33
+ totalAdjustedAmount: checkout.summary?.totalAdjustedAmount,
34
+ promotionAmount: checkout.summary?.totalPromotionAmount,
35
+ itemsCount: checkout.summary?.items?.length || 0,
36
+ orderBumps: checkout.checkoutSession?.sessionLineItems?.filter((item) => item.isOrderBump) || [],
37
+ adjustments: checkout.summary?.adjustments || [],
38
+ isInitialized,
39
+ lastUpdated: new Date().toISOString(),
40
+ }
41
+ : null;
42
+ updateCheckoutDebugData(debugData, error, isLoading);
43
+ if (debugData) {
44
+ console.log('🐛 [useCheckout] Debug data updated for debug drawer', {
45
+ sessionId: debugData.sessionId,
46
+ totalAmount: debugData.totalAmount,
47
+ totalAdjustedAmount: debugData.totalAdjustedAmount,
48
+ promotionAmount: debugData.promotionAmount,
49
+ itemsCount: debugData.itemsCount,
50
+ orderBumpsCount: debugData.orderBumps?.length || 0,
51
+ adjustmentsCount: debugData.adjustments?.length || 0,
52
+ lastUpdated: debugData.lastUpdated,
53
+ });
54
+ }
55
+ }, [checkout, error, isLoading, isInitialized]); // Removed updateCheckoutDebugData from deps to prevent infinite loop
24
56
  const init = useCallback(async (params) => {
25
57
  // Don't allow init if we already have a checkout token
26
58
  if (providedToken) {
@@ -85,6 +117,14 @@ export function useCheckout(options = {}) {
85
117
  setCheckout(response);
86
118
  currentCheckoutTokenRef.current = checkoutToken;
87
119
  setIsInitialized(true);
120
+ console.log('📊 [useCheckout] Checkout data updated', {
121
+ sessionId: response.checkoutSession?.id,
122
+ totalAmount: response.summary?.totalAmount,
123
+ promotionAmount: response.summary?.totalPromotionAmount,
124
+ itemsCount: response.summary?.items?.length || 0,
125
+ orderBumpsCount: response.checkoutSession?.sessionLineItems?.filter((item) => item.isOrderBump)?.length || 0,
126
+ timestamp: new Date().toISOString(),
127
+ });
88
128
  return response;
89
129
  }
90
130
  catch (err) {
@@ -100,7 +140,12 @@ export function useCheckout(options = {}) {
100
140
  if (!currentCheckoutTokenRef.current) {
101
141
  throw new Error('No checkout session to refresh');
102
142
  }
143
+ console.log('🔄 [useCheckout] Refreshing checkout data...', {
144
+ checkoutToken: currentCheckoutTokenRef.current.substring(0, 8) + '...',
145
+ timestamp: new Date().toISOString(),
146
+ });
103
147
  await getCheckout(currentCheckoutTokenRef.current);
148
+ console.log('✅ [useCheckout] Refresh completed, debug data will be updated automatically');
104
149
  }, [getCheckout]);
105
150
  const updateAddress = useCallback(async (data) => {
106
151
  if (!checkout?.checkoutSession.id) {
@@ -280,7 +325,13 @@ export function useCheckout(options = {}) {
280
325
  body: { orderBumpOfferId, selected },
281
326
  });
282
327
  if (response.success) {
328
+ console.log('🎯 [useCheckout] Order bump toggled successfully, refreshing checkout data...', {
329
+ orderBumpOfferId,
330
+ selected,
331
+ timestamp: new Date().toISOString(),
332
+ });
283
333
  await refresh();
334
+ console.log('✅ [useCheckout] Order bump refresh completed, debug drawer should now show updated data');
284
335
  }
285
336
  return response;
286
337
  }
@@ -325,6 +376,30 @@ export function useCheckout(options = {}) {
325
376
  throw error;
326
377
  }
327
378
  }, [apiService, checkout?.checkoutSession.id, refresh]);
379
+ const previewOrderSummary = useCallback(async (orderBumpOfferIds, orderBumpType = 'vip') => {
380
+ if (!checkout?.checkoutSession.id) {
381
+ throw new Error('No checkout session available');
382
+ }
383
+ try {
384
+ const response = await apiService.fetch(`/api/v1/checkout-sessions/${checkout.checkoutSession.id}/vip-preview`, {
385
+ method: 'POST',
386
+ body: {
387
+ orderBumpOfferIds,
388
+ orderBumpType,
389
+ },
390
+ });
391
+ return response;
392
+ }
393
+ catch (err) {
394
+ const error = err instanceof Error ? err : new Error('Failed to preview order summary');
395
+ return {
396
+ savings: 0,
397
+ savingsPct: 0,
398
+ currency: checkout?.summary?.currency ?? 'EUR',
399
+ error: error.message,
400
+ };
401
+ }
402
+ }, [apiService, checkout?.checkoutSession.id, checkout?.summary?.currency]);
328
403
  const clear = useCallback(() => {
329
404
  setCheckout(null);
330
405
  setError(null);
@@ -380,6 +455,7 @@ export function useCheckout(options = {}) {
380
455
  toggleOrderBump,
381
456
  updateCustomer,
382
457
  updateCustomerAndSessionInfo,
458
+ previewOrderSummary,
383
459
  clear,
384
460
  };
385
461
  }
@@ -0,0 +1,30 @@
1
+ export interface OrderBumpPreview {
2
+ savings: number;
3
+ savingsPct: number;
4
+ currency: string;
5
+ selectedOffers: {
6
+ productId: string | null;
7
+ variantId: string | null;
8
+ isSelected: boolean;
9
+ }[];
10
+ }
11
+ export interface UseOrderBumpOptions {
12
+ checkoutSessionId?: string;
13
+ offerId: string;
14
+ orderBumpType?: 'primary' | 'secondary' | 'vip';
15
+ autoPreview?: boolean;
16
+ }
17
+ export interface UseOrderBumpResult {
18
+ isSelected: boolean;
19
+ preview: OrderBumpPreview | null;
20
+ savings: number | null;
21
+ isLoading: boolean;
22
+ isToggling: boolean;
23
+ error: Error | null;
24
+ toggle: (selected?: boolean) => Promise<{
25
+ success: boolean;
26
+ error?: any;
27
+ }>;
28
+ refreshPreview: () => Promise<void>;
29
+ }
30
+ export declare function useOrderBump(options: UseOrderBumpOptions): UseOrderBumpResult;
@@ -0,0 +1,97 @@
1
+ import { useState, useCallback, useEffect } from 'react';
2
+ import { useTagadaContext } from '../providers/TagadaProvider';
3
+ export function useOrderBump(options) {
4
+ const { apiService } = useTagadaContext();
5
+ const { checkoutSessionId, offerId, orderBumpType = 'vip', autoPreview = true } = options;
6
+ const [isSelected, setIsSelected] = useState(false);
7
+ const [preview, setPreview] = useState(null);
8
+ const [isLoading, setIsLoading] = useState(false);
9
+ const [isToggling, setIsToggling] = useState(false);
10
+ const [error, setError] = useState(null);
11
+ const refreshPreview = useCallback(async () => {
12
+ if (!checkoutSessionId)
13
+ return;
14
+ setIsLoading(true);
15
+ setError(null);
16
+ try {
17
+ const response = await apiService.fetch(`/api/v1/checkout-sessions/${checkoutSessionId}/vip-preview`, {
18
+ method: 'POST',
19
+ body: {
20
+ orderBumpOfferIds: [offerId],
21
+ orderBumpType,
22
+ },
23
+ });
24
+ setPreview(response);
25
+ // Update isSelected based on preview data
26
+ const offerSelected = response.selectedOffers?.some((offer) => offer.isSelected);
27
+ setIsSelected(offerSelected ?? false);
28
+ }
29
+ catch (err) {
30
+ const error = err instanceof Error ? err : new Error('Failed to fetch preview');
31
+ setError(error);
32
+ console.error('Order bump preview failed:', error);
33
+ }
34
+ finally {
35
+ setIsLoading(false);
36
+ }
37
+ }, [checkoutSessionId, offerId, orderBumpType, apiService]);
38
+ const toggle = useCallback(async (selected) => {
39
+ if (!checkoutSessionId) {
40
+ throw new Error('No checkout session available');
41
+ }
42
+ const targetState = selected ?? !isSelected;
43
+ // Optimistic update
44
+ setIsSelected(targetState);
45
+ setIsToggling(true);
46
+ setError(null);
47
+ try {
48
+ const response = await apiService.fetch(`/api/v1/checkout-sessions/${checkoutSessionId}/toggle-order-bump`, {
49
+ method: 'POST',
50
+ body: {
51
+ orderBumpOfferId: offerId,
52
+ selected: targetState,
53
+ },
54
+ });
55
+ if (response.success) {
56
+ // Refresh preview to get updated savings
57
+ await refreshPreview();
58
+ return { success: true };
59
+ }
60
+ else {
61
+ // Revert optimistic update
62
+ setIsSelected(!targetState);
63
+ return { success: false, error: response.error };
64
+ }
65
+ }
66
+ catch (err) {
67
+ // Revert optimistic update
68
+ setIsSelected(!targetState);
69
+ const error = err instanceof Error ? err : new Error('Failed to toggle order bump');
70
+ setError(error);
71
+ return { success: false, error: error.message };
72
+ }
73
+ finally {
74
+ setIsToggling(false);
75
+ }
76
+ }, [checkoutSessionId, offerId, isSelected, apiService, refreshPreview]);
77
+ // Auto-fetch preview on mount and when dependencies change
78
+ useEffect(() => {
79
+ if (autoPreview && checkoutSessionId) {
80
+ refreshPreview().catch((error) => {
81
+ console.error('Auto-preview failed:', error);
82
+ });
83
+ }
84
+ }, [autoPreview, refreshPreview]);
85
+ // Calculate current savings
86
+ const savings = isSelected && preview?.savings ? preview.savings : preview?.savings || null;
87
+ return {
88
+ isSelected,
89
+ preview,
90
+ savings,
91
+ isLoading,
92
+ isToggling,
93
+ error,
94
+ toggle,
95
+ refreshPreview,
96
+ };
97
+ }
@@ -5,6 +5,7 @@ export { TagadaProvider } from './providers/TagadaProvider';
5
5
  export { useCheckout } from './hooks/useCheckout';
6
6
  export { useProducts } from './hooks/useProducts';
7
7
  export { useOffers } from './hooks/useOffers';
8
+ export { useOrderBump } from './hooks/useOrderBump';
8
9
  export { useSession } from './hooks/useSession';
9
10
  export { useCurrency } from './hooks/useCurrency';
10
11
  export { useCustomer } from './hooks/useCustomer';
@@ -19,6 +20,7 @@ export { useThreeds } from './hooks/useThreeds';
19
20
  export { useThreedsModal } from './hooks/useThreedsModal';
20
21
  export type { Customer, Session, AuthState, Locale, Currency, Store, Environment, EnvironmentConfig, Order, OrderItem, OrderSummary, OrderAddress, PickupPoint, } from './types';
21
22
  export type { UseCheckoutOptions, UseCheckoutResult, CheckoutInitParams, CheckoutLineItem, CheckoutSession, CheckoutData, Promotion, } from './hooks/useCheckout';
23
+ export type { UseOrderBumpOptions, UseOrderBumpResult, OrderBumpPreview } from './hooks/useOrderBump';
22
24
  export type { Payment, PollingOptions, PaymentPollingHook } from './hooks/usePaymentPolling';
23
25
  export type { PaymentInstrument, ThreedsSession, ThreedsChallenge, ThreedsOptions, ThreedsHook, ThreedsProvider, } from './hooks/useThreeds';
24
26
  export type { ApplePayToken, CardPaymentMethod, PaymentResponse, PaymentOptions, PaymentInstrumentResponse, PaymentHook, } from './hooks/usePayment';
@@ -8,6 +8,7 @@ export { TagadaProvider } from './providers/TagadaProvider';
8
8
  export { useCheckout } from './hooks/useCheckout';
9
9
  export { useProducts } from './hooks/useProducts';
10
10
  export { useOffers } from './hooks/useOffers';
11
+ export { useOrderBump } from './hooks/useOrderBump';
11
12
  export { useSession } from './hooks/useSession';
12
13
  export { useCurrency } from './hooks/useCurrency';
13
14
  export { useCustomer } from './hooks/useCustomer';
@@ -39,17 +39,11 @@ interface TagadaProviderProps {
39
39
  children: ReactNode;
40
40
  environment?: Environment;
41
41
  customApiConfig?: Partial<EnvironmentConfig>;
42
- developmentMode?: boolean;
43
42
  debugMode?: boolean;
44
43
  storeId?: string;
45
44
  accountId?: string;
46
- mockData?: {
47
- customer?: Partial<Customer>;
48
- session?: Partial<Session>;
49
- store?: Partial<Store>;
50
- };
51
45
  }
52
- export declare function TagadaProvider({ children, environment, customApiConfig, developmentMode, debugMode, // Remove default, will be set based on environment
53
- storeId, accountId, mockData, }: TagadaProviderProps): import("react/jsx-runtime").JSX.Element;
46
+ export declare function TagadaProvider({ children, environment, customApiConfig, debugMode, // Remove default, will be set based on environment
47
+ storeId, accountId, }: TagadaProviderProps): import("react/jsx-runtime").JSX.Element;
54
48
  export declare function useTagadaContext(): TagadaContextValue;
55
49
  export {};
@@ -29,8 +29,8 @@ const InitializationLoader = () => (_jsx("div", { style: {
29
29
  }
30
30
  ` }) }));
31
31
  const TagadaContext = createContext(null);
32
- export function TagadaProvider({ children, environment, customApiConfig, developmentMode = false, debugMode, // Remove default, will be set based on environment
33
- storeId, accountId, mockData, }) {
32
+ export function TagadaProvider({ children, environment, customApiConfig, debugMode, // Remove default, will be set based on environment
33
+ storeId, accountId, }) {
34
34
  const [isLoading, setIsLoading] = useState(true);
35
35
  const [isInitialized, setIsInitialized] = useState(false);
36
36
  const [token, setToken] = useState(null);
@@ -284,49 +284,6 @@ storeId, accountId, mockData, }) {
284
284
  try {
285
285
  console.debug('[SDK] Initializing token...');
286
286
  setIsLoading(true);
287
- if (developmentMode) {
288
- console.debug('[SDK] Development mode: Using mock data');
289
- // Use mock data in development mode
290
- if (mockData?.customer) {
291
- setCustomer({
292
- id: 'dev-customer-123',
293
- email: 'dev@example.com',
294
- firstName: 'John',
295
- lastName: 'Doe',
296
- phone: '+1234567890',
297
- isAuthenticated: true,
298
- role: 'authenticated',
299
- ...mockData.customer,
300
- });
301
- }
302
- if (mockData?.session) {
303
- setSession({
304
- sessionId: 'dev-session-123',
305
- storeId: 'dev-store-123',
306
- accountId: 'dev-account-123',
307
- customerId: 'dev-customer-123',
308
- role: 'authenticated',
309
- isValid: true,
310
- isLoading: false,
311
- ...mockData.session,
312
- });
313
- }
314
- if (mockData?.store) {
315
- setStore({
316
- id: 'dev-store-123',
317
- name: 'Development Store',
318
- domain: 'dev.localhost',
319
- currency: 'USD',
320
- locale: 'en-US',
321
- presentmentCurrencies: ['USD'],
322
- chargeCurrencies: ['USD'],
323
- ...mockData.store,
324
- });
325
- }
326
- setIsInitialized(true);
327
- setIsLoading(false);
328
- return;
329
- }
330
287
  // Check for existing token
331
288
  const existingToken = getClientToken();
332
289
  let tokenToUse = null;
@@ -374,7 +331,7 @@ storeId, accountId, mockData, }) {
374
331
  }
375
332
  };
376
333
  void initializeToken();
377
- }, [developmentMode, mockData, storeId, createAnonymousToken, initializeSession]);
334
+ }, [storeId, createAnonymousToken, initializeSession]);
378
335
  // Update auth state when customer/session changes
379
336
  useEffect(() => {
380
337
  setAuth({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tagadapay/plugin-sdk",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "Modern React SDK for building Tagada Pay plugins",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",