@tagadapay/plugin-sdk 2.6.2 → 2.6.6

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 (55) hide show
  1. package/README.md +1090 -623
  2. package/dist/react/components/GooglePayButton.d.ts +12 -0
  3. package/dist/react/components/GooglePayButton.js +340 -0
  4. package/dist/react/components/index.d.ts +3 -2
  5. package/dist/react/components/index.js +3 -2
  6. package/dist/react/hooks/useApplePay.js +38 -10
  7. package/dist/react/hooks/{useExpressPayment.d.ts → useExpressPaymentMethods.d.ts} +13 -10
  8. package/dist/react/hooks/{useExpressPayment.js → useExpressPaymentMethods.js} +17 -8
  9. package/dist/react/hooks/useGoogleAutocomplete.d.ts +2 -0
  10. package/dist/react/hooks/useGoogleAutocomplete.js +18 -2
  11. package/dist/react/hooks/useGooglePay.d.ts +22 -0
  12. package/dist/react/hooks/useGooglePay.js +32 -0
  13. package/dist/react/index.d.ts +9 -7
  14. package/dist/react/index.js +8 -5
  15. package/dist/react/providers/TagadaProvider.js +5 -5
  16. package/dist/react/types/apple-pay.d.ts +0 -25
  17. package/dist/v2/core/googleAutocomplete.d.ts +2 -0
  18. package/dist/v2/core/googleAutocomplete.js +23 -4
  19. package/dist/v2/core/resources/checkout.d.ts +70 -2
  20. package/dist/v2/core/resources/discounts.d.ts +53 -0
  21. package/dist/v2/core/resources/discounts.js +29 -0
  22. package/dist/v2/core/resources/expressPaymentMethods.d.ts +56 -0
  23. package/dist/v2/core/resources/expressPaymentMethods.js +27 -0
  24. package/dist/v2/core/resources/index.d.ts +7 -4
  25. package/dist/v2/core/resources/index.js +7 -4
  26. package/dist/v2/core/resources/shippingRates.d.ts +36 -0
  27. package/dist/v2/core/resources/shippingRates.js +23 -0
  28. package/dist/v2/core/resources/vipOffers.d.ts +37 -0
  29. package/dist/v2/core/resources/vipOffers.js +27 -0
  30. package/dist/v2/core/utils/order.d.ts +1 -0
  31. package/dist/v2/core/utils/pluginConfig.d.ts +6 -6
  32. package/dist/v2/index.d.ts +12 -9
  33. package/dist/v2/index.js +3 -3
  34. package/dist/v2/react/components/ApplePayButton.d.ts +141 -0
  35. package/dist/v2/react/components/ApplePayButton.js +320 -0
  36. package/dist/v2/react/components/GooglePayButton.d.ts +19 -0
  37. package/dist/v2/react/components/GooglePayButton.js +355 -0
  38. package/dist/v2/react/hooks/useApiQuery.d.ts +4 -1
  39. package/dist/v2/react/hooks/useApiQuery.js +4 -1
  40. package/dist/v2/react/hooks/useDiscountsQuery.d.ts +30 -0
  41. package/dist/v2/react/hooks/useDiscountsQuery.js +175 -0
  42. package/dist/v2/react/hooks/useExpressPaymentMethods.d.ts +12 -0
  43. package/dist/v2/react/hooks/useExpressPaymentMethods.js +17 -0
  44. package/dist/v2/react/hooks/useGoogleAutocomplete.d.ts +2 -0
  45. package/dist/v2/react/hooks/useGoogleAutocomplete.js +18 -2
  46. package/dist/v2/react/hooks/useShippingRatesQuery.d.ts +22 -0
  47. package/dist/v2/react/hooks/useShippingRatesQuery.js +134 -0
  48. package/dist/v2/react/hooks/useVipOffersQuery.d.ts +72 -0
  49. package/dist/v2/react/hooks/useVipOffersQuery.js +140 -0
  50. package/dist/v2/react/index.d.ts +30 -17
  51. package/dist/v2/react/index.js +18 -10
  52. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +59 -0
  53. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +165 -0
  54. package/dist/v2/react/providers/TagadaProvider.js +5 -5
  55. package/package.json +90 -90
@@ -0,0 +1,27 @@
1
+ /**
2
+ * VIP Offers Resource Client
3
+ * Axios-based API client for VIP offer endpoints
4
+ */
5
+ export class VipOffersResource {
6
+ constructor(apiClient) {
7
+ this.apiClient = apiClient;
8
+ }
9
+ /**
10
+ * Get VIP preview showing potential savings
11
+ */
12
+ async getVipPreview(sessionId, vipOfferIds) {
13
+ return this.apiClient.post(`/api/v1/checkout-sessions/${sessionId}/vip-preview`, {
14
+ orderBumpOfferIds: vipOfferIds,
15
+ orderBumpType: 'vip',
16
+ });
17
+ }
18
+ /**
19
+ * Toggle an order bump (used for VIP offers)
20
+ */
21
+ async toggleOrderBump(sessionId, orderBumpOfferId, selected) {
22
+ return this.apiClient.post(`/api/v1/checkout-sessions/${sessionId}/toggle-order-bump`, {
23
+ orderBumpOfferId,
24
+ selected,
25
+ });
26
+ }
27
+ }
@@ -77,6 +77,7 @@ export interface Order {
77
77
  firstName: string;
78
78
  lastName: string;
79
79
  address1: string;
80
+ address2: string;
80
81
  city: string;
81
82
  country: string;
82
83
  state: string;
@@ -2,11 +2,11 @@
2
2
  * Plugin Configuration Utility Functions
3
3
  * Pure functions for plugin configuration management
4
4
  */
5
- export interface PluginConfig<TConfig = Record<string, any>> {
5
+ export type PluginConfig<TConfig = Record<string, any>> = {
6
6
  storeId?: string;
7
7
  accountId?: string;
8
8
  basePath?: string;
9
- config?: TConfig;
9
+ config?: any;
10
10
  productId?: string;
11
11
  variants?: Record<string, string>;
12
12
  prices?: Record<string, any>;
@@ -15,13 +15,13 @@ export interface PluginConfig<TConfig = Record<string, any>> {
15
15
  upsellId?: string;
16
16
  googleApiKey?: string;
17
17
  branding?: any;
18
- }
19
- export interface RawPluginConfig<TConfig = Record<string, any>> {
18
+ } & TConfig;
19
+ export type RawPluginConfig<TConfig = Record<string, any>> = {
20
20
  storeId?: string;
21
21
  accountId?: string;
22
22
  basePath?: string;
23
- config?: TConfig;
24
- }
23
+ config?: any;
24
+ } & TConfig;
25
25
  /**
26
26
  * Core plugin config loading function
27
27
  * Handles local dev, production, and raw config
@@ -5,15 +5,18 @@
5
5
  * - core: Pure functions without React dependencies
6
6
  * - react: React hooks and components using core functions
7
7
  */
8
- export * from './core/utils/pluginConfig';
9
- export * from './core/utils/products';
10
8
  export * from './core/googleAutocomplete';
11
9
  export * from './core/isoData';
12
10
  export * from './core/utils/currency';
13
- export type { CheckoutData, CheckoutSession, CheckoutLineItem, CheckoutInitParams, Promotion, } from './core/resources/checkout';
14
- export type { Order, OrderLineItem, } from './core/utils/order';
15
- export type { PostPurchaseOffer, PostPurchaseOfferItem, PostPurchaseOfferSummary, } from './core/resources/postPurchases';
16
- export type { Offer, OfferItem, OfferSummary, } from './core/resources/offers';
17
- export type { OrderBumpOffer, OrderBumpPreview, } from './core/utils/orderBump';
18
- export type { Payment, PaymentResponse, PaymentOptions, CardPaymentMethod, ApplePayToken, PaymentInstrumentResponse, PaymentInstrumentCustomerResponse, PaymentInstrumentCustomer } from './core/resources/payments';
19
- export { TagadaProvider, useTagadaContext, useCheckoutToken, usePluginConfig, useGoogleAutocomplete, useGeoLocation, useISOData, getAvailableLanguages, useLanguageImport, useCountryOptions, useRegionOptions, useCheckout, useOrderBump, usePromotions, useProducts, useOrder, usePostPurchases, useOffers, usePayment, useThreeds, useThreedsModal, useCurrency, useApiQuery, useApiMutation, useInvalidateQuery, usePreloadQuery, queryKeys, formatMoney } from './react';
11
+ export * from './core/utils/pluginConfig';
12
+ export * from './core/utils/products';
13
+ export type { CheckoutData, CheckoutInitParams, CheckoutLineItem, CheckoutSession, Promotion } from './core/resources/checkout';
14
+ export type { Order, OrderLineItem } from './core/utils/order';
15
+ export type { PostPurchaseOffer, PostPurchaseOfferItem, PostPurchaseOfferSummary } from './core/resources/postPurchases';
16
+ export type { Offer, OfferItem, OfferSummary } from './core/resources/offers';
17
+ export type { OrderBumpOffer, OrderBumpPreview } from './core/utils/orderBump';
18
+ export type { ApplePayToken, CardPaymentMethod, Payment, PaymentInstrumentCustomer, PaymentInstrumentCustomerResponse, PaymentInstrumentResponse, PaymentOptions, PaymentResponse } from './core/resources/payments';
19
+ export type { ShippingRate, ShippingRatesResponse } from './core/resources/shippingRates';
20
+ export type { ApplyDiscountResponse, Discount, DiscountCodeValidation, RemoveDiscountResponse } from './core/resources/discounts';
21
+ export type { ToggleOrderBumpResponse, VipOffer, VipPreviewResponse } from './core/resources/vipOffers';
22
+ 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, useTagadaContext, useThreeds, useThreedsModal, useVipOffers } from './react';
package/dist/v2/index.js CHANGED
@@ -6,10 +6,10 @@
6
6
  * - react: React hooks and components using core functions
7
7
  */
8
8
  // Core exports (selective to avoid conflicts)
9
- export * from './core/utils/pluginConfig';
10
- export * from './core/utils/products';
11
9
  export * from './core/googleAutocomplete';
12
10
  export * from './core/isoData';
13
11
  export * from './core/utils/currency';
12
+ export * from './core/utils/pluginConfig';
13
+ export * from './core/utils/products';
14
14
  // React exports (hooks and components only, types are exported above)
15
- export { TagadaProvider, useTagadaContext, useCheckoutToken, usePluginConfig, useGoogleAutocomplete, useGeoLocation, useISOData, getAvailableLanguages, useLanguageImport, useCountryOptions, useRegionOptions, useCheckout, useOrderBump, usePromotions, useProducts, useOrder, usePostPurchases, useOffers, usePayment, useThreeds, useThreedsModal, useCurrency, useApiQuery, useApiMutation, useInvalidateQuery, usePreloadQuery, queryKeys, formatMoney } from './react';
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, useTagadaContext, useThreeds, useThreedsModal, useVipOffers } from './react';
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Apple Pay Button Component for v2 Architecture
3
+ * Uses v2 useExpressPaymentMethods hook and follows clean architecture principles
4
+ */
5
+ import React from 'react';
6
+ import { CheckoutData } from '../../core/resources/checkout';
7
+ declare class ApplePaySession {
8
+ static canMakePayments(): boolean;
9
+ static canMakePaymentsWithActiveCard(merchantId: string): Promise<boolean>;
10
+ static STATUS_SUCCESS: number;
11
+ static STATUS_FAILURE: number;
12
+ static STATUS_INVALID_BILLING_POSTAL_ADDRESS: number;
13
+ static STATUS_INVALID_SHIPPING_POSTAL_ADDRESS: number;
14
+ static STATUS_INVALID_SHIPPING_CONTACT: number;
15
+ static STATUS_PIN_REQUIRED: number;
16
+ static STATUS_PIN_INCORRECT: number;
17
+ static STATUS_PIN_LOCKOUT: number;
18
+ constructor(version: number, paymentRequest: ApplePayPaymentRequest);
19
+ begin(): void;
20
+ abort(): void;
21
+ completeMerchantValidation(merchantSession: any): void;
22
+ completePayment(result: ApplePayPaymentAuthorizationResult): void;
23
+ completeShippingContactSelection(update: ApplePayShippingContactUpdate): void;
24
+ completeShippingMethodSelection(update: ApplePayShippingMethodUpdate): void;
25
+ completePaymentMethodSelection(update: ApplePayPaymentMethodUpdate): void;
26
+ onvalidatemerchant: ((event: ApplePayValidateMerchantEvent) => void) | null;
27
+ onpaymentauthorized: ((event: ApplePayPaymentAuthorizedEvent) => void) | null;
28
+ onshippingcontactselected: ((event: ApplePayShippingContactSelectionEvent) => void) | null;
29
+ onshippingmethodselected: ((event: ApplePayShippingMethodSelectionEvent) => void) | null;
30
+ onpaymentmethodselected: ((event: ApplePayPaymentMethodSelectionEvent) => void) | null;
31
+ oncancel: ((event: Event) => void) | null;
32
+ }
33
+ interface ApplePayPaymentRequest {
34
+ countryCode: string;
35
+ currencyCode: string;
36
+ supportedNetworks: string[];
37
+ merchantCapabilities: string[];
38
+ total: ApplePayLineItem;
39
+ lineItems?: ApplePayLineItem[];
40
+ shippingType?: 'shipping' | 'delivery' | 'storePickup' | 'servicePickup';
41
+ shippingMethods?: ApplePayShippingMethod[];
42
+ requiredBillingContactFields?: string[];
43
+ requiredShippingContactFields?: string[];
44
+ applicationData?: string;
45
+ }
46
+ interface ApplePayLineItem {
47
+ label: string;
48
+ amount: string;
49
+ type?: 'final' | 'pending';
50
+ }
51
+ interface ApplePayShippingMethod {
52
+ label: string;
53
+ amount: string;
54
+ detail?: string;
55
+ identifier: string;
56
+ }
57
+ interface ApplePayPaymentToken {
58
+ paymentData: any;
59
+ paymentMethod: {
60
+ displayName: string;
61
+ network: string;
62
+ type: string;
63
+ paymentPass: any;
64
+ billingContact?: ApplePayPaymentContact;
65
+ };
66
+ transactionIdentifier: string;
67
+ }
68
+ interface ApplePayPaymentContact {
69
+ phoneNumber?: string;
70
+ emailAddress?: string;
71
+ givenName?: string;
72
+ familyName?: string;
73
+ phoneticGivenName?: string;
74
+ phoneticFamilyName?: string;
75
+ addressLines?: string[];
76
+ locality?: string;
77
+ administrativeArea?: string;
78
+ postalCode?: string;
79
+ countryCode?: string;
80
+ }
81
+ interface ApplePayValidateMerchantEvent {
82
+ validationURL: string;
83
+ }
84
+ interface ApplePayPaymentAuthorizedEvent {
85
+ payment: {
86
+ token: ApplePayPaymentToken;
87
+ billingContact?: ApplePayPaymentContact;
88
+ shippingContact?: ApplePayPaymentContact;
89
+ };
90
+ }
91
+ interface ApplePayShippingContactSelectionEvent {
92
+ shippingContact: ApplePayPaymentContact;
93
+ }
94
+ interface ApplePayShippingMethodSelectionEvent {
95
+ shippingMethod: ApplePayShippingMethod;
96
+ }
97
+ interface ApplePayPaymentMethodSelectionEvent {
98
+ paymentMethod: any;
99
+ }
100
+ interface ApplePayPaymentAuthorizationResult {
101
+ status: number;
102
+ errors?: ApplePayError[];
103
+ }
104
+ interface ApplePayShippingContactUpdate {
105
+ errors?: ApplePayError[];
106
+ newShippingMethods?: ApplePayShippingMethod[];
107
+ newTotal?: ApplePayLineItem;
108
+ newLineItems?: ApplePayLineItem[];
109
+ }
110
+ interface ApplePayShippingMethodUpdate {
111
+ newTotal?: ApplePayLineItem;
112
+ newLineItems?: ApplePayLineItem[];
113
+ }
114
+ interface ApplePayPaymentMethodUpdate {
115
+ newTotal?: ApplePayLineItem;
116
+ newLineItems?: ApplePayLineItem[];
117
+ }
118
+ interface ApplePayError {
119
+ code: string;
120
+ message: string;
121
+ contactField?: string;
122
+ }
123
+ declare global {
124
+ interface Window {
125
+ ApplePaySession: typeof ApplePaySession;
126
+ }
127
+ }
128
+ export interface ApplePayButtonProps {
129
+ className?: string;
130
+ disabled?: boolean;
131
+ onSuccess?: (payment: any) => void;
132
+ onError?: (error: string) => void;
133
+ onCancel?: () => void;
134
+ storeName?: string;
135
+ currencyCode?: string;
136
+ variant?: 'default' | 'outline' | 'ghost';
137
+ size?: 'sm' | 'md' | 'lg';
138
+ checkout: CheckoutData;
139
+ }
140
+ export declare const ApplePayButton: React.FC<ApplePayButtonProps>;
141
+ export default ApplePayButton;
@@ -0,0 +1,320 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Apple Pay Button Component for v2 Architecture
4
+ * Uses v2 useExpressPaymentMethods hook and follows clean architecture principles
5
+ */
6
+ import { useCallback, useEffect, useState } from 'react';
7
+ import { useExpressPaymentMethods } from '../hooks/useExpressPaymentMethods';
8
+ export const ApplePayButton = ({ className = '', disabled = false, onSuccess, onError, onCancel, storeName, currencyCode = 'USD', variant = 'outline', size = 'lg', checkout, }) => {
9
+ const { applePayPaymentMethod, shippingMethods, lineItems, handleAddExpressId, updateCheckoutSessionValues, updateCustomerEmail, reComputeOrderSummary, setError: setContextError, } = useExpressPaymentMethods();
10
+ const [processingPayment, setProcessingPayment] = useState(false);
11
+ const [isApplePayAvailable, setIsApplePayAvailable] = useState(false);
12
+ const [applePayError, setApplePayError] = useState(null);
13
+ // Don't render if no Apple Pay payment method is enabled
14
+ if (!applePayPaymentMethod) {
15
+ return null;
16
+ }
17
+ // Check Apple Pay availability
18
+ useEffect(() => {
19
+ const checkApplePayAvailability = async () => {
20
+ if (typeof window === 'undefined' || !window.ApplePaySession) {
21
+ setIsApplePayAvailable(false);
22
+ return;
23
+ }
24
+ try {
25
+ const canMakePayments = window.ApplePaySession.canMakePayments();
26
+ if (canMakePayments) {
27
+ const merchantId = applePayPaymentMethod?.metadata?.merchantId || '';
28
+ const canMakePaymentsWithActiveCard = await window.ApplePaySession.canMakePaymentsWithActiveCard(merchantId);
29
+ setIsApplePayAvailable(canMakePaymentsWithActiveCard);
30
+ if (canMakePaymentsWithActiveCard) {
31
+ handleAddExpressId('apple_pay');
32
+ }
33
+ }
34
+ else {
35
+ setIsApplePayAvailable(false);
36
+ }
37
+ }
38
+ catch (error) {
39
+ console.error('Error checking Apple Pay availability:', error);
40
+ setIsApplePayAvailable(false);
41
+ }
42
+ };
43
+ checkApplePayAvailability();
44
+ }, [applePayPaymentMethod, handleAddExpressId]);
45
+ // Convert Apple Pay contact to internal Address format
46
+ const applePayContactToAddress = useCallback((contact) => {
47
+ return {
48
+ address1: contact.addressLines?.[0] || '',
49
+ address2: contact.addressLines?.[1] || '',
50
+ lastName: contact.familyName || '',
51
+ firstName: contact.givenName || '',
52
+ city: contact.locality || '',
53
+ state: contact.administrativeArea || '',
54
+ country: contact.countryCode || '',
55
+ postal: contact.postalCode || '',
56
+ phone: contact.phoneNumber || '',
57
+ email: contact.emailAddress || '',
58
+ };
59
+ }, []);
60
+ // Validate merchant with backend
61
+ const validateMerchant = useCallback(async (validationURL) => {
62
+ const response = await fetch('/api/v1/apple-pay/validate-merchant', {
63
+ method: 'POST',
64
+ headers: {
65
+ 'Content-Type': 'application/json',
66
+ },
67
+ body: JSON.stringify({
68
+ validationURL,
69
+ checkoutSessionId: checkout.checkoutSession.id,
70
+ }),
71
+ });
72
+ if (!response.ok) {
73
+ throw new Error('Failed to validate Apple Pay merchant');
74
+ }
75
+ return response.json();
76
+ }, [checkout.checkoutSession.id]);
77
+ // Process Apple Pay payment
78
+ const processApplePayPayment = useCallback(async (token, billingContact, shippingContact) => {
79
+ try {
80
+ setProcessingPayment(true);
81
+ // Update addresses before processing payment
82
+ if (shippingContact) {
83
+ const shippingAddress = applePayContactToAddress(shippingContact);
84
+ const billingAddress = billingContact ? applePayContactToAddress(billingContact) : null;
85
+ await updateCheckoutSessionValues({
86
+ data: {
87
+ shippingAddress,
88
+ billingAddress,
89
+ },
90
+ });
91
+ }
92
+ // Update customer email
93
+ if (shippingContact?.emailAddress) {
94
+ await updateCustomerEmail({
95
+ data: {
96
+ email: shippingContact.emailAddress,
97
+ },
98
+ });
99
+ }
100
+ // Process payment with backend API
101
+ const response = await fetch('/api/v1/apple-pay/process-payment', {
102
+ method: 'POST',
103
+ headers: {
104
+ 'Content-Type': 'application/json',
105
+ },
106
+ body: JSON.stringify({
107
+ checkoutSessionId: checkout.checkoutSession.id,
108
+ paymentToken: token,
109
+ billingContact,
110
+ shippingContact,
111
+ }),
112
+ });
113
+ if (!response.ok) {
114
+ throw new Error('Failed to process Apple Pay payment');
115
+ }
116
+ const paymentResult = await response.json();
117
+ if (onSuccess) {
118
+ onSuccess(paymentResult);
119
+ }
120
+ return paymentResult;
121
+ }
122
+ catch (error) {
123
+ console.error('Error processing Apple Pay payment:', error);
124
+ const errorMessage = error instanceof Error ? error.message : 'Apple Pay payment failed';
125
+ setApplePayError(errorMessage);
126
+ setContextError(errorMessage);
127
+ if (onError) {
128
+ onError(errorMessage);
129
+ }
130
+ throw error;
131
+ }
132
+ finally {
133
+ setProcessingPayment(false);
134
+ }
135
+ }, [
136
+ checkout.checkoutSession.id,
137
+ applePayContactToAddress,
138
+ updateCheckoutSessionValues,
139
+ updateCustomerEmail,
140
+ onSuccess,
141
+ onError,
142
+ setContextError,
143
+ ]);
144
+ // Handle Apple Pay button click
145
+ const handleApplePayClick = useCallback(() => {
146
+ if (!isApplePayAvailable || processingPayment || !checkout.summary) {
147
+ return;
148
+ }
149
+ const paymentRequest = {
150
+ countryCode: 'US', // TODO: Get from checkout session
151
+ currencyCode: currencyCode,
152
+ supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
153
+ merchantCapabilities: ['supports3DS'],
154
+ total: {
155
+ label: storeName || checkout.checkoutSession.store?.name || 'Total',
156
+ amount: (checkout.summary.totalAdjustedAmount / 100).toFixed(2),
157
+ type: 'final',
158
+ },
159
+ lineItems: lineItems.map((item) => ({
160
+ label: item.label,
161
+ amount: item.amount,
162
+ type: 'final',
163
+ })),
164
+ shippingType: 'shipping',
165
+ shippingMethods: shippingMethods.map((method) => ({
166
+ label: method.label,
167
+ amount: method.amount,
168
+ detail: method.detail,
169
+ identifier: method.identifier,
170
+ })),
171
+ requiredBillingContactFields: ['postalAddress', 'name', 'phone', 'email'],
172
+ requiredShippingContactFields: ['postalAddress', 'name', 'phone', 'email'],
173
+ };
174
+ const session = new window.ApplePaySession(3, paymentRequest);
175
+ session.onvalidatemerchant = async (event) => {
176
+ try {
177
+ const merchantSession = await validateMerchant(event.validationURL);
178
+ session.completeMerchantValidation(merchantSession);
179
+ }
180
+ catch (error) {
181
+ console.error('Merchant validation failed:', error);
182
+ session.abort();
183
+ const errorMessage = 'Apple Pay setup failed';
184
+ setApplePayError(errorMessage);
185
+ setContextError(errorMessage);
186
+ if (onError) {
187
+ onError(errorMessage);
188
+ }
189
+ }
190
+ };
191
+ session.onshippingcontactselected = async (event) => {
192
+ try {
193
+ const shippingAddress = applePayContactToAddress(event.shippingContact);
194
+ await updateCheckoutSessionValues({
195
+ data: { shippingAddress },
196
+ });
197
+ const newOrderSummary = await reComputeOrderSummary();
198
+ const update = {
199
+ newShippingMethods: newOrderSummary?.shippingMethods.map((method) => ({
200
+ label: method.label,
201
+ amount: method.amount,
202
+ detail: method.detail,
203
+ identifier: method.identifier,
204
+ })) || [],
205
+ newTotal: {
206
+ label: storeName || checkout.checkoutSession.store?.name || 'Total',
207
+ amount: newOrderSummary?.total.amount || '0.00',
208
+ type: 'final',
209
+ },
210
+ newLineItems: newOrderSummary?.lineItems.map((item) => ({
211
+ label: item.label,
212
+ amount: item.amount,
213
+ type: 'final',
214
+ })) || [],
215
+ };
216
+ session.completeShippingContactSelection(update);
217
+ }
218
+ catch (error) {
219
+ console.error('Shipping contact selection failed:', error);
220
+ session.completeShippingContactSelection({
221
+ errors: [
222
+ {
223
+ code: 'shippingContactInvalid',
224
+ message: 'Unable to ship to this address',
225
+ },
226
+ ],
227
+ });
228
+ }
229
+ };
230
+ session.onshippingmethodselected = async (event) => {
231
+ try {
232
+ // Update shipping method via API
233
+ const response = await fetch('/api/v1/shipping-rates/select', {
234
+ method: 'POST',
235
+ headers: {
236
+ 'Content-Type': 'application/json',
237
+ },
238
+ body: JSON.stringify({
239
+ checkoutSessionId: checkout.checkoutSession.id,
240
+ shippingRateId: event.shippingMethod.identifier,
241
+ }),
242
+ });
243
+ if (!response.ok) {
244
+ throw new Error('Failed to update shipping method');
245
+ }
246
+ const newOrderSummary = await reComputeOrderSummary();
247
+ const update = {
248
+ newTotal: {
249
+ label: storeName || checkout.checkoutSession.store?.name || 'Total',
250
+ amount: newOrderSummary?.total.amount || '0.00',
251
+ type: 'final',
252
+ },
253
+ newLineItems: newOrderSummary?.lineItems.map((item) => ({
254
+ label: item.label,
255
+ amount: item.amount,
256
+ type: 'final',
257
+ })) || [],
258
+ };
259
+ session.completeShippingMethodSelection(update);
260
+ }
261
+ catch (error) {
262
+ console.error('Shipping method selection failed:', error);
263
+ session.completeShippingMethodSelection({});
264
+ }
265
+ };
266
+ session.onpaymentauthorized = async (event) => {
267
+ try {
268
+ await processApplePayPayment(event.payment.token, event.payment.billingContact, event.payment.shippingContact);
269
+ session.completePayment({
270
+ status: window.ApplePaySession.STATUS_SUCCESS,
271
+ });
272
+ }
273
+ catch (error) {
274
+ console.error('Payment authorization failed:', error);
275
+ session.completePayment({
276
+ status: window.ApplePaySession.STATUS_FAILURE,
277
+ });
278
+ }
279
+ };
280
+ session.oncancel = () => {
281
+ if (onCancel) {
282
+ onCancel();
283
+ }
284
+ };
285
+ session.begin();
286
+ }, [
287
+ isApplePayAvailable,
288
+ processingPayment,
289
+ checkout,
290
+ currencyCode,
291
+ storeName,
292
+ lineItems,
293
+ shippingMethods,
294
+ validateMerchant,
295
+ applePayContactToAddress,
296
+ updateCheckoutSessionValues,
297
+ reComputeOrderSummary,
298
+ processApplePayPayment,
299
+ onCancel,
300
+ onError,
301
+ setContextError,
302
+ ]);
303
+ // Button size classes
304
+ const sizeClasses = {
305
+ sm: 'h-8 px-3 text-sm',
306
+ md: 'h-10 px-4 text-base',
307
+ lg: 'h-12 px-6 text-lg',
308
+ };
309
+ // Button variant classes
310
+ const variantClasses = {
311
+ default: 'bg-black text-white hover:bg-black/90',
312
+ outline: 'border border-black bg-white text-black hover:bg-black hover:text-white',
313
+ ghost: 'text-black hover:bg-black/10',
314
+ };
315
+ if (!isApplePayAvailable) {
316
+ return null;
317
+ }
318
+ return (_jsxs("div", { className: "w-full", children: [_jsx("button", { type: "button", onClick: handleApplePayClick, disabled: disabled || processingPayment, className: `relative w-full rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${sizeClasses[size]} ${variantClasses[variant]} ${className} `, children: processingPayment ? (_jsxs("div", { className: "flex items-center justify-center gap-2", children: [_jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" }), _jsx("span", { children: "Processing..." })] })) : (_jsxs("span", { className: "flex items-center justify-center gap-2", children: [_jsx("svg", { className: "h-6 w-6", 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" }) }), "Pay with Apple Pay"] })) }), applePayError && (_jsx("div", { className: "mt-2 rounded border border-red-200 bg-red-50 p-2 text-sm text-red-600", children: applePayError }))] }));
319
+ };
320
+ export default ApplePayButton;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Google Pay Button Component for v2 Architecture
3
+ * Uses v2 useExpressPaymentMethods hook and follows clean architecture principles
4
+ */
5
+ import React from 'react';
6
+ import { CheckoutData } from '../../core/resources/checkout';
7
+ export interface GooglePayButtonProps {
8
+ className?: string;
9
+ disabled?: boolean;
10
+ onSuccess?: (payment: any) => void;
11
+ onError?: (error: string) => void;
12
+ onCancel?: () => void;
13
+ checkout: CheckoutData;
14
+ size?: 'sm' | 'md' | 'lg';
15
+ buttonColor?: 'default' | 'black' | 'white';
16
+ buttonType?: 'buy' | 'plain' | 'donate' | 'pay';
17
+ }
18
+ export declare const GooglePayButton: React.FC<GooglePayButtonProps>;
19
+ export default GooglePayButton;