@tagadapay/plugin-sdk 3.1.8 → 3.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +1129 -1129
  2. package/build-cdn.js +223 -113
  3. package/dist/external-tracker.js +135 -81
  4. package/dist/external-tracker.min.js +2 -2
  5. package/dist/external-tracker.min.js.map +4 -4
  6. package/dist/react/providers/TagadaProvider.js +5 -5
  7. package/dist/tagada-sdk.js +10164 -0
  8. package/dist/tagada-sdk.min.js +45 -0
  9. package/dist/tagada-sdk.min.js.map +7 -0
  10. package/dist/v2/core/funnelClient.d.ts +91 -4
  11. package/dist/v2/core/funnelClient.js +42 -3
  12. package/dist/v2/core/resources/funnel.d.ts +10 -0
  13. package/dist/v2/core/resources/payments.d.ts +21 -1
  14. package/dist/v2/core/resources/payments.js +34 -0
  15. package/dist/v2/core/utils/currency.d.ts +14 -0
  16. package/dist/v2/core/utils/currency.js +40 -0
  17. package/dist/v2/core/utils/index.d.ts +1 -0
  18. package/dist/v2/core/utils/index.js +2 -0
  19. package/dist/v2/core/utils/pluginConfig.d.ts +8 -0
  20. package/dist/v2/core/utils/pluginConfig.js +28 -0
  21. package/dist/v2/core/utils/previewMode.d.ts +4 -0
  22. package/dist/v2/core/utils/previewMode.js +28 -0
  23. package/dist/v2/core/utils/previewModeIndicator.js +101 -101
  24. package/dist/v2/index.d.ts +7 -6
  25. package/dist/v2/index.js +6 -6
  26. package/dist/v2/react/components/ApplePayButton.d.ts +1 -2
  27. package/dist/v2/react/components/ApplePayButton.js +57 -58
  28. package/dist/v2/react/components/FunnelScriptInjector.js +161 -172
  29. package/dist/v2/react/components/GooglePayButton.d.ts +2 -0
  30. package/dist/v2/react/components/GooglePayButton.js +80 -64
  31. package/dist/v2/react/hooks/useFunnel.d.ts +8 -2
  32. package/dist/v2/react/hooks/useFunnel.js +2 -2
  33. package/dist/v2/react/hooks/useGoogleAutocomplete.d.ts +10 -0
  34. package/dist/v2/react/hooks/useGoogleAutocomplete.js +48 -0
  35. package/dist/v2/react/hooks/useGooglePayCheckout.d.ts +21 -0
  36. package/dist/v2/react/hooks/useGooglePayCheckout.js +198 -0
  37. package/dist/v2/react/hooks/usePaymentPolling.d.ts +7 -1
  38. package/dist/v2/react/hooks/usePaymentQuery.d.ts +2 -0
  39. package/dist/v2/react/hooks/usePaymentQuery.js +435 -8
  40. package/dist/v2/react/hooks/usePixelTracking.d.ts +56 -0
  41. package/dist/v2/react/hooks/usePixelTracking.js +508 -0
  42. package/dist/v2/react/hooks/useStepConfig.d.ts +8 -6
  43. package/dist/v2/react/hooks/useStepConfig.js +3 -2
  44. package/dist/v2/react/index.d.ts +6 -2
  45. package/dist/v2/react/index.js +3 -1
  46. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +1 -0
  47. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +33 -13
  48. package/dist/v2/react/providers/TagadaProvider.js +22 -21
  49. package/dist/v2/standalone/index.js +1 -1
  50. package/package.json +112 -112
@@ -212,143 +212,143 @@ export function injectPreviewModeIndicator() {
212
212
  // Create container
213
213
  const container = document.createElement('div');
214
214
  container.id = 'tgd-preview-indicator';
215
- container.style.cssText = `
216
- position: fixed;
217
- bottom: 16px;
218
- right: 16px;
219
- z-index: 999999;
220
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
215
+ container.style.cssText = `
216
+ position: fixed;
217
+ bottom: 16px;
218
+ right: 16px;
219
+ z-index: 999999;
220
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
221
221
  `;
222
222
  // Create badge
223
223
  const badge = document.createElement('div');
224
- badge.style.cssText = `
225
- background: ${draftMode ? '#ff9500' : '#007aff'};
226
- color: white;
227
- padding: 8px 12px;
228
- border-radius: 8px;
229
- font-size: 13px;
230
- font-weight: 600;
231
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
232
- cursor: pointer;
233
- transition: all 0.2s ease;
234
- display: flex;
235
- align-items: center;
236
- gap: 6px;
224
+ badge.style.cssText = `
225
+ background: ${draftMode ? '#ff9500' : '#007aff'};
226
+ color: white;
227
+ padding: 8px 12px;
228
+ border-radius: 8px;
229
+ font-size: 13px;
230
+ font-weight: 600;
231
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
232
+ cursor: pointer;
233
+ transition: all 0.2s ease;
234
+ display: flex;
235
+ align-items: center;
236
+ gap: 6px;
237
237
  `;
238
- badge.innerHTML = `
239
- <span style="font-size: 16px;">🔍</span>
240
- <span>${draftMode ? 'Preview Mode' : 'Dev Mode'}</span>
238
+ badge.innerHTML = `
239
+ <span style="font-size: 16px;">🔍</span>
240
+ <span>${draftMode ? 'Preview Mode' : 'Dev Mode'}</span>
241
241
  `;
242
242
  // Create details popup (with padding-top to bridge gap with badge)
243
243
  const details = document.createElement('div');
244
- details.style.cssText = `
245
- position: absolute;
246
- bottom: calc(100% + 8px);
247
- right: 0;
248
- background: white;
249
- border: 1px solid #e5e5e5;
250
- border-radius: 8px;
251
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
252
- padding: 12px;
253
- min-width: 250px;
254
- font-size: 12px;
255
- line-height: 1.5;
256
- display: none;
244
+ details.style.cssText = `
245
+ position: absolute;
246
+ bottom: calc(100% + 8px);
247
+ right: 0;
248
+ background: white;
249
+ border: 1px solid #e5e5e5;
250
+ border-radius: 8px;
251
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
252
+ padding: 12px;
253
+ min-width: 250px;
254
+ font-size: 12px;
255
+ line-height: 1.5;
256
+ display: none;
257
257
  `;
258
258
  details.style.paddingTop = '20px'; // Extra padding to bridge the gap
259
259
  // Add invisible bridge between badge and popup to prevent flickering
260
260
  const bridge = document.createElement('div');
261
- bridge.style.cssText = `
262
- position: absolute;
263
- bottom: 100%;
264
- left: 0;
265
- right: 0;
266
- height: 8px;
267
- display: none;
261
+ bridge.style.cssText = `
262
+ position: absolute;
263
+ bottom: 100%;
264
+ left: 0;
265
+ right: 0;
266
+ height: 8px;
267
+ display: none;
268
268
  `;
269
269
  // Build details content
270
270
  let detailsHTML = '<div style="margin-bottom: 8px; font-weight: 600; color: #1d1d1f;">Current Environment</div>';
271
271
  detailsHTML += '<div style="display: flex; flex-direction: column; gap: 6px;">';
272
272
  if (draftMode) {
273
- detailsHTML += `
274
- <div style="display: flex; justify-content: space-between; color: #86868b;">
275
- <span>Draft Mode:</span>
276
- <span style="color: #ff9500; font-weight: 600;">ON</span>
277
- </div>
273
+ detailsHTML += `
274
+ <div style="display: flex; justify-content: space-between; color: #86868b;">
275
+ <span>Draft Mode:</span>
276
+ <span style="color: #ff9500; font-weight: 600;">ON</span>
277
+ </div>
278
278
  `;
279
279
  }
280
280
  if (trackingDisabled) {
281
- detailsHTML += `
282
- <div style="display: flex; justify-content: space-between; color: #86868b;">
283
- <span>Tracking:</span>
284
- <span style="color: #ff3b30; font-weight: 600;">DISABLED</span>
285
- </div>
281
+ detailsHTML += `
282
+ <div style="display: flex; justify-content: space-between; color: #86868b;">
283
+ <span>Tracking:</span>
284
+ <span style="color: #ff3b30; font-weight: 600;">DISABLED</span>
285
+ </div>
286
286
  `;
287
287
  }
288
288
  if (params.funnelEnv) {
289
- detailsHTML += `
290
- <div style="display: flex; justify-content: space-between; color: #86868b;">
291
- <span>Funnel Env:</span>
292
- <span style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 11px;">
293
- ${params.funnelEnv}
294
- </span>
295
- </div>
289
+ detailsHTML += `
290
+ <div style="display: flex; justify-content: space-between; color: #86868b;">
291
+ <span>Funnel Env:</span>
292
+ <span style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 11px;">
293
+ ${params.funnelEnv}
294
+ </span>
295
+ </div>
296
296
  `;
297
297
  }
298
298
  if (params.tagadaClientEnv) {
299
- detailsHTML += `
300
- <div style="display: flex; justify-content: space-between; color: #86868b;">
301
- <span>API Env:</span>
302
- <span style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 11px;">
303
- ${params.tagadaClientEnv}
304
- </span>
305
- </div>
299
+ detailsHTML += `
300
+ <div style="display: flex; justify-content: space-between; color: #86868b;">
301
+ <span>API Env:</span>
302
+ <span style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 11px;">
303
+ ${params.tagadaClientEnv}
304
+ </span>
305
+ </div>
306
306
  `;
307
307
  }
308
308
  if (params.tagadaClientBaseUrl) {
309
- detailsHTML += `
310
- <div style="color: #86868b;">
311
- <div style="margin-bottom: 4px;">API URL:</div>
312
- <div style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 10px; word-break: break-all; background: #f5f5f7; padding: 4px 6px; border-radius: 4px;">
313
- ${params.tagadaClientBaseUrl}
314
- </div>
315
- </div>
309
+ detailsHTML += `
310
+ <div style="color: #86868b;">
311
+ <div style="margin-bottom: 4px;">API URL:</div>
312
+ <div style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 10px; word-break: break-all; background: #f5f5f7; padding: 4px 6px; border-radius: 4px;">
313
+ ${params.tagadaClientBaseUrl}
314
+ </div>
315
+ </div>
316
316
  `;
317
317
  }
318
318
  if (params.funnelId) {
319
- detailsHTML += `
320
- <div style="color: #86868b; margin-top: 4px; padding-top: 8px; border-top: 1px solid #e5e5e5;">
321
- <div style="margin-bottom: 4px;">Funnel ID:</div>
322
- <div style="color: #1d1d1f; font-family: monospace; font-size: 10px; word-break: break-all; background: #f5f5f7; padding: 4px 6px; border-radius: 4px;">
323
- ${params.funnelId}
324
- </div>
325
- </div>
319
+ detailsHTML += `
320
+ <div style="color: #86868b; margin-top: 4px; padding-top: 8px; border-top: 1px solid #e5e5e5;">
321
+ <div style="margin-bottom: 4px;">Funnel ID:</div>
322
+ <div style="color: #1d1d1f; font-family: monospace; font-size: 10px; word-break: break-all; background: #f5f5f7; padding: 4px 6px; border-radius: 4px;">
323
+ ${params.funnelId}
324
+ </div>
325
+ </div>
326
326
  `;
327
327
  }
328
328
  detailsHTML += '</div>';
329
- detailsHTML += `
330
- <div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #e5e5e5; font-size: 11px; color: #86868b; text-align: center;">
331
- Add <code style="background: #f5f5f7; padding: 2px 4px; border-radius: 3px;">?forceReset=true</code> to reset
332
- </div>
329
+ detailsHTML += `
330
+ <div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #e5e5e5; font-size: 11px; color: #86868b; text-align: center;">
331
+ Add <code style="background: #f5f5f7; padding: 2px 4px; border-radius: 3px;">?forceReset=true</code> to reset
332
+ </div>
333
333
  `;
334
334
  // Add action button
335
- detailsHTML += `
336
- <div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #e5e5e5;">
337
- <button id="tgd-leave-preview" style="
338
- background: #ff3b30;
339
- color: white;
340
- border: none;
341
- border-radius: 6px;
342
- padding: 10px 12px;
343
- font-size: 13px;
344
- font-weight: 600;
345
- cursor: pointer;
346
- transition: opacity 0.2s;
347
- width: 100%;
348
- ">
349
- 🚪 Leave Preview Mode
350
- </button>
351
- </div>
335
+ detailsHTML += `
336
+ <div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #e5e5e5;">
337
+ <button id="tgd-leave-preview" style="
338
+ background: #ff3b30;
339
+ color: white;
340
+ border: none;
341
+ border-radius: 6px;
342
+ padding: 10px 12px;
343
+ font-size: 13px;
344
+ font-weight: 600;
345
+ cursor: pointer;
346
+ transition: opacity 0.2s;
347
+ width: 100%;
348
+ ">
349
+ 🚪 Leave Preview Mode
350
+ </button>
351
+ </div>
352
352
  `;
353
353
  details.innerHTML = detailsHTML;
354
354
  // Hover behavior - keep popup visible when hovering over badge, bridge, or popup
@@ -7,14 +7,14 @@
7
7
  */
8
8
  export * from './core/googleAutocomplete';
9
9
  export * from './core/isoData';
10
+ export * from './core/utils/configHotReload';
10
11
  export * from './core/utils/currency';
11
12
  export * from './core/utils/pluginConfig';
12
- export * from './core/utils/products';
13
13
  export * from './core/utils/previewMode';
14
- export * from './core/utils/configHotReload';
15
- export { injectPreviewModeIndicator, removePreviewModeIndicator, isIndicatorInjected } from './core/utils/previewModeIndicator';
16
- export { getAssignedStepConfig, getAssignedPaymentFlowId, getAssignedStaticResources, getAssignedScripts, loadLocalFunnelConfig, getLocalFunnelConfig, } from './core/funnelClient';
17
- export type { RuntimeStepConfig, LocalFunnelConfig } from './core/funnelClient';
14
+ export { injectPreviewModeIndicator, isIndicatorInjected, removePreviewModeIndicator } from './core/utils/previewModeIndicator';
15
+ export * from './core/utils/products';
16
+ export { getAssignedPaymentFlowId, getAssignedScripts, getAssignedStaticResources, getAssignedStepConfig, getLocalFunnelConfig, loadLocalFunnelConfig } from './core/funnelClient';
17
+ export type { LocalFunnelConfig, RuntimeStepConfig } from './core/funnelClient';
18
18
  export * from './core/pathRemapping';
19
19
  export type { CheckoutData, CheckoutInitParams, CheckoutLineItem, CheckoutSession, CheckoutSessionPreview, Promotion } from './core/resources/checkout';
20
20
  export type { Order, OrderLineItem } from './core/utils/order';
@@ -28,13 +28,14 @@ export type { ToggleOrderBumpResponse, VipOffer, VipPreviewResponse } from './co
28
28
  export type { StoreConfig } from './core/resources/storeConfig';
29
29
  export { FunnelActionType } from './core/resources/funnel';
30
30
  export type { BackNavigationActionData, CartUpdatedActionData, DirectNavigationActionData, FormSubmitActionData, FunnelContextUpdateRequest, FunnelContextUpdateResponse, FunnelAction as FunnelEvent, FunnelInitializeRequest, FunnelInitializeResponse, FunnelNavigateRequest, FunnelNavigateResponse, FunnelNavigationAction, FunnelNavigationResult, NextAction, OfferAcceptedActionData, OfferDeclinedActionData, PaymentFailedActionData, PaymentSuccessActionData, SimpleFunnelContext } from './core/resources/funnel';
31
- export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, PreviewModeIndicator, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useApplePayCheckout, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCredits, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useFunnelLegacy, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useLogin, useOffer, useOrder, useOrderBump, usePayment, usePaymentRetrieve, usePluginConfig, usePostPurchases, usePreloadQuery, usePreviewOffer, useProducts, usePromotions, useRegionOptions, useRemappableParams, useShippingRates, useSimpleFunnel, useStepConfig, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers } from './react';
31
+ export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, PreviewModeIndicator, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useApplePayCheckout, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCredits, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useFunnelLegacy, useGeoLocation, useGoogleAutocomplete, useGooglePayCheckout, useInvalidateQuery, useISOData, useLanguageImport, useLogin, useOffer, useOrder, useOrderBump, usePayment, usePaymentRetrieve, usePixelTracking, usePluginConfig, usePostPurchases, usePreloadQuery, usePreviewOffer, useProducts, usePromotions, useRegionOptions, useRemappableParams, useShippingRates, useSimpleFunnel, useStepConfig, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers } from './react';
32
32
  export type { DebugScript } from './react';
33
33
  export type { TranslateFunction, TranslationText, UseTranslationOptions, UseTranslationResult } from './react/hooks/useTranslation';
34
34
  export type { FunnelContextValue } from './react/hooks/useFunnel';
35
35
  export type { UseApplePayCheckoutOptions } from './react/hooks/useApplePayCheckout';
36
36
  export type { ClubOffer, ClubOfferItem, ClubOfferLineItem, ClubOfferSummary, UseClubOffersOptions, UseClubOffersResult } from './react/hooks/useClubOffers';
37
37
  export type { UseCreditsOptions, UseCreditsResult } from './react/hooks/useCredits';
38
+ export type { UseGooglePayCheckoutOptions } from './react/hooks/useGooglePayCheckout';
38
39
  export type { UseLoginOptions, UseLoginResult } from './react/hooks/useLogin';
39
40
  export type { CustomerAddress, CustomerInfos, CustomerOrderSummary, OrderWithRelations, Subscription, SubscriptionsResponse } from './core/resources/customer';
40
41
  export type { UseCustomerResult } from './react/hooks/useCustomer';
package/dist/v2/index.js CHANGED
@@ -8,18 +8,18 @@
8
8
  // Core exports (selective to avoid conflicts)
9
9
  export * from './core/googleAutocomplete';
10
10
  export * from './core/isoData';
11
+ export * from './core/utils/configHotReload';
11
12
  export * from './core/utils/currency';
12
13
  export * from './core/utils/pluginConfig';
13
- export * from './core/utils/products';
14
14
  export * from './core/utils/previewMode';
15
- export * from './core/utils/configHotReload';
16
- export { injectPreviewModeIndicator, removePreviewModeIndicator, isIndicatorInjected } from './core/utils/previewModeIndicator';
15
+ export { injectPreviewModeIndicator, isIndicatorInjected, removePreviewModeIndicator } from './core/utils/previewModeIndicator';
16
+ export * from './core/utils/products';
17
17
  // Step config utilities (for reading runtime configuration from HTML)
18
- export { getAssignedStepConfig, getAssignedPaymentFlowId, getAssignedStaticResources, getAssignedScripts,
18
+ export { getAssignedPaymentFlowId, getAssignedScripts, getAssignedStaticResources, getAssignedStepConfig, getLocalFunnelConfig,
19
19
  // Local development helpers
20
- loadLocalFunnelConfig, getLocalFunnelConfig, } from './core/funnelClient';
20
+ loadLocalFunnelConfig } from './core/funnelClient';
21
21
  // Path remapping helpers (framework-agnostic)
22
22
  export * from './core/pathRemapping';
23
23
  export { FunnelActionType } from './core/resources/funnel';
24
24
  // React exports (hooks and components only, types are exported above)
25
- export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, PreviewModeIndicator, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useApplePayCheckout, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCredits, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useFunnelLegacy, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useLogin, useOffer, useOrder, useOrderBump, usePayment, usePaymentRetrieve, usePluginConfig, usePostPurchases, usePreloadQuery, usePreviewOffer, useProducts, usePromotions, useRegionOptions, useRemappableParams, useShippingRates, useSimpleFunnel, useStepConfig, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers } from './react';
25
+ export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, PreviewModeIndicator, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useApplePayCheckout, useAuth, useCheckout, useCheckoutToken, useClubOffers, useCountryOptions, useCredits, useCurrency, useCustomer, useCustomerInfos, useCustomerOrders, useCustomerSubscriptions, useDiscounts, useExpressPaymentMethods, useFunnel, useFunnelLegacy, useGeoLocation, useGoogleAutocomplete, useGooglePayCheckout, useInvalidateQuery, useISOData, useLanguageImport, useLogin, useOffer, useOrder, useOrderBump, usePayment, usePaymentRetrieve, usePixelTracking, usePluginConfig, usePostPurchases, usePreloadQuery, usePreviewOffer, useProducts, usePromotions, useRegionOptions, useRemappableParams, useShippingRates, useSimpleFunnel, useStepConfig, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers } from './react';
@@ -10,10 +10,9 @@ declare global {
10
10
  }
11
11
  }
12
12
  declare class ApplePaySession {
13
- static canMakePayments(): boolean;
14
- static canMakePaymentsWithActiveCard(merchantId: string): Promise<boolean>;
15
13
  static STATUS_SUCCESS: number;
16
14
  static STATUS_FAILURE: number;
15
+ static canMakePayments(): boolean;
17
16
  constructor(version: number, request: any);
18
17
  begin(): void;
19
18
  abort(): void;
@@ -4,10 +4,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  * Clean rewrite based on working CMS implementation
5
5
  */
6
6
  import { useCallback, useEffect, useMemo, useState } from 'react';
7
- import { useExpressPaymentMethods } from '../hooks/useExpressPaymentMethods';
8
- import { usePaymentQuery } from '../hooks/usePaymentQuery';
9
7
  import { getBasisTheoryApiKey } from '../../../react/config/payment';
10
8
  import { getCurrencyInfo, minorUnitsToMajorUnits } from '../../../react/utils/money';
9
+ import { useExpressPaymentMethods } from '../hooks/useExpressPaymentMethods';
10
+ import { usePaymentQuery } from '../hooks/usePaymentQuery';
11
+ import { useShippingRatesQuery } from '../hooks/useShippingRatesQuery';
11
12
  // Helper function to convert Apple Pay contact to Address (matches CMS)
12
13
  const applePayContactToAddress = (contact) => {
13
14
  return {
@@ -31,38 +32,23 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
31
32
  const basistheoryPublicKey = useMemo(() => getBasisTheoryApiKey(), []);
32
33
  // Use payment hook for proper payment processing
33
34
  const { processApplePayPayment } = usePaymentQuery();
35
+ // Use shipping rates hook for selecting shipping rates
36
+ const { selectRate } = useShippingRatesQuery({ checkout });
34
37
  // Don't render if no Apple Pay payment method is enabled
35
38
  if (!applePayPaymentMethod) {
36
39
  return null;
37
40
  }
38
- // Check Apple Pay availability (matches CMS pattern)
41
+ // Check Apple Pay availability (matches CMS pattern - useApplePayAvailable hook)
39
42
  useEffect(() => {
40
- const checkApplePayAvailability = async () => {
41
- if (typeof window === 'undefined' || !window.ApplePaySession) {
42
- setIsApplePayAvailable(false);
43
- return;
44
- }
45
- try {
46
- const canMakePayments = window.ApplePaySession.canMakePayments();
47
- if (canMakePayments) {
48
- const merchantId = applePayPaymentMethod?.metadata?.merchantId || '';
49
- const canMakePaymentsWithActiveCard = await window.ApplePaySession.canMakePaymentsWithActiveCard(merchantId);
50
- setIsApplePayAvailable(canMakePaymentsWithActiveCard);
51
- if (canMakePaymentsWithActiveCard) {
52
- handleAddExpressId('apple_pay');
53
- }
54
- }
55
- else {
56
- setIsApplePayAvailable(false);
57
- }
58
- }
59
- catch (error) {
60
- // Silently fail - Apple Pay just won't be available
61
- setIsApplePayAvailable(false);
62
- }
63
- };
64
- checkApplePayAvailability();
65
- }, [applePayPaymentMethod, handleAddExpressId]);
43
+ const addExpress = () => handleAddExpressId('apple_pay');
44
+ if (window?.ApplePaySession && ApplePaySession.canMakePayments()) {
45
+ setIsApplePayAvailable(true);
46
+ addExpress();
47
+ }
48
+ else {
49
+ setIsApplePayAvailable(false);
50
+ }
51
+ }, [handleAddExpressId]);
66
52
  // Helper to convert minor units to currency string
67
53
  const minorUnitsToCurrencyString = useCallback((amountMinor, currency) => {
68
54
  // Fail safely - don't allow invalid data to become '0.00'
@@ -93,14 +79,14 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
93
79
  }),
94
80
  });
95
81
  if (!response.ok) {
96
- throw new Error(`Failed to validate merchant: ${response.status}`);
82
+ throw new Error(`HTTP error! Status: ${response.status}`);
97
83
  }
98
84
  const merchantSession = await response.json();
99
85
  return merchantSession;
100
86
  }
101
- catch (error) {
102
- console.error('Merchant validation failed:', error);
103
- throw error;
87
+ catch (err) {
88
+ console.error('[ApplePay] Merchant validation failed:', err);
89
+ throw err;
104
90
  }
105
91
  }, [basistheoryPublicKey, checkout.checkoutSession.store?.name]);
106
92
  // Tokenize Apple Pay payment with Basis Theory (matches CMS)
@@ -123,7 +109,7 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
123
109
  return result.apple_pay; // Basis Theory returns the Apple Pay token in the apple_pay field
124
110
  }
125
111
  catch (error) {
126
- console.error('Tokenizing Apple Pay failed:', error);
112
+ console.error('[ApplePay] Tokenizing Apple Pay failed:', error);
127
113
  throw error;
128
114
  }
129
115
  }, [basistheoryPublicKey]);
@@ -139,6 +125,7 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
139
125
  // The hook already returns the response, we just need to return it
140
126
  },
141
127
  onPaymentFailed: (error) => {
128
+ console.error('[ApplePay] Payment failed:', error);
142
129
  setProcessingPayment(false);
143
130
  throw new Error(error.message);
144
131
  },
@@ -147,7 +134,7 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
147
134
  return result;
148
135
  }
149
136
  catch (error) {
150
- console.error('Payment processing failed:', error);
137
+ console.error('[ApplePay] Payment processing failed:', error);
151
138
  setProcessingPayment(false);
152
139
  throw error;
153
140
  }
@@ -184,7 +171,7 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
184
171
  session.completeMerchantValidation(merchantSession);
185
172
  }
186
173
  catch (error) {
187
- console.error('Merchant validation failed:', error);
174
+ console.error('[ApplePay] Merchant validation failed:', error);
188
175
  session.abort();
189
176
  }
190
177
  })();
@@ -220,7 +207,7 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
220
207
  }
221
208
  }
222
209
  catch (error) {
223
- console.error('Payment processing failed:', error);
210
+ console.error('[ApplePay] Payment processing failed:', error);
224
211
  session.completePayment(ApplePaySession.STATUS_FAILURE);
225
212
  const errorMessage = 'Payment Failed';
226
213
  setContextError(errorMessage);
@@ -234,26 +221,28 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
234
221
  session.onshippingmethodselected = (event) => {
235
222
  void (async () => {
236
223
  try {
237
- // Update shipping method via API
238
- await fetch(`/api/v1/checkout-sessions/${checkout.checkoutSession.id}/shipping-rate`, {
239
- method: 'PUT',
240
- headers: {
241
- 'Content-Type': 'application/json',
242
- },
243
- body: JSON.stringify({
244
- shippingRateId: event.shippingMethod.identifier,
245
- }),
246
- });
224
+ // Update shipping method via client
225
+ await selectRate(event.shippingMethod.identifier);
247
226
  const newOrderSummary = await reComputeOrderSummary();
248
227
  if (!newOrderSummary) {
228
+ console.error('[ApplePay] No order summary returned, aborting session');
249
229
  session.abort();
250
230
  return;
251
231
  }
252
232
  const { lineItems: newLineItems, total: newTotal } = newOrderSummary;
253
- session.completeShippingMethodSelection(ApplePaySession.STATUS_SUCCESS, newTotal, newLineItems);
233
+ // Ensure type: 'final' is present for Apple Pay (matches CMS)
234
+ const formattedTotal = {
235
+ ...newTotal,
236
+ type: 'final',
237
+ };
238
+ const formattedLineItems = newLineItems.map((item) => ({
239
+ ...item,
240
+ type: 'final',
241
+ }));
242
+ session.completeShippingMethodSelection(ApplePaySession.STATUS_SUCCESS, formattedTotal, formattedLineItems);
254
243
  }
255
244
  catch (error) {
256
- console.error('Shipping method selection failed:', error);
245
+ console.error('[ApplePay] Shipping method selection failed:', error);
257
246
  session.abort();
258
247
  }
259
248
  })();
@@ -270,24 +259,33 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
270
259
  });
271
260
  const newOrderSummary = await reComputeOrderSummary();
272
261
  if (!newOrderSummary) {
262
+ console.error('[ApplePay] No order summary returned, aborting session');
273
263
  session.abort();
274
264
  setContextError('Payment Failed');
275
265
  return;
276
266
  }
277
267
  const { lineItems: newLineItems, total: newTotal, shippingMethods: newShippingMethods, } = newOrderSummary;
278
- session.completeShippingContactSelection(ApplePaySession.STATUS_SUCCESS, newShippingMethods, newTotal, newLineItems);
268
+ // Ensure type: 'final' is present for Apple Pay (matches CMS)
269
+ const formattedTotal = {
270
+ ...newTotal,
271
+ type: 'final',
272
+ };
273
+ const formattedLineItems = newLineItems.map((item) => ({
274
+ ...item,
275
+ type: 'final',
276
+ }));
277
+ session.completeShippingContactSelection(ApplePaySession.STATUS_SUCCESS, newShippingMethods, formattedTotal, formattedLineItems);
279
278
  }
280
279
  catch (error) {
281
- console.error('Shipping contact selection failed:', error);
280
+ console.error('[ApplePay] Shipping contact selection failed:', error);
282
281
  session.abort();
283
282
  }
284
283
  })();
285
284
  };
286
285
  session.onerror = (event) => {
287
- console.error('Apple Pay Session Error:', event);
286
+ console.error('[ApplePay] Session Error:', event);
288
287
  };
289
288
  session.oncancel = () => {
290
- console.log('Payment cancelled by user');
291
289
  if (onCancel) {
292
290
  onCancel();
293
291
  }
@@ -295,7 +293,7 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
295
293
  session.begin();
296
294
  }
297
295
  catch (error) {
298
- console.error('Failed to start Apple Pay session:', error);
296
+ console.error('[ApplePay] Failed to start Apple Pay session:', error);
299
297
  }
300
298
  }, [
301
299
  isApplePayAvailable,
@@ -312,13 +310,14 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
312
310
  updateCustomerEmail,
313
311
  reComputeOrderSummary,
314
312
  setContextError,
313
+ selectRate,
315
314
  onSuccess,
316
315
  onError,
317
316
  onCancel,
318
317
  ]);
319
- // if (!isApplePayAvailable) {
320
- // return null;
321
- // }
318
+ if (!isApplePayAvailable) {
319
+ return null;
320
+ }
322
321
  return (_jsxs("button", { onClick: handleApplePayClick, disabled: processingPayment, style: {
323
322
  backgroundColor: '#000',
324
323
  color: '#fff',
@@ -334,6 +333,6 @@ export const ApplePayButton = ({ checkout, onSuccess, onError, onCancel }) => {
334
333
  alignItems: 'center',
335
334
  justifyContent: 'center',
336
335
  gap: '8px',
337
- }, children: [_jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z" }) }), processingPayment ? 'Processing...' : 'Pay with Apple Pay'] }));
336
+ }, type: "button", children: [_jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z" }) }), processingPayment ? 'Processing...' : 'Pay with Apple Pay'] }));
338
337
  };
339
338
  export default ApplePayButton;