@tagadapay/plugin-sdk 1.0.2

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 (63) hide show
  1. package/README.md +475 -0
  2. package/dist/data/currencies.json +2410 -0
  3. package/dist/index.d.ts +33 -0
  4. package/dist/index.js +37 -0
  5. package/dist/react/components/DebugDrawer.d.ts +7 -0
  6. package/dist/react/components/DebugDrawer.js +368 -0
  7. package/dist/react/components/OffersDemo.d.ts +1 -0
  8. package/dist/react/components/OffersDemo.js +50 -0
  9. package/dist/react/components/index.d.ts +1 -0
  10. package/dist/react/components/index.js +1 -0
  11. package/dist/react/config/environment.d.ts +22 -0
  12. package/dist/react/config/environment.js +132 -0
  13. package/dist/react/config/payment.d.ts +23 -0
  14. package/dist/react/config/payment.js +52 -0
  15. package/dist/react/hooks/useAuth.d.ts +4 -0
  16. package/dist/react/hooks/useAuth.js +12 -0
  17. package/dist/react/hooks/useCheckout.d.ts +262 -0
  18. package/dist/react/hooks/useCheckout.js +325 -0
  19. package/dist/react/hooks/useCurrency.d.ts +4 -0
  20. package/dist/react/hooks/useCurrency.js +640 -0
  21. package/dist/react/hooks/useCustomer.d.ts +7 -0
  22. package/dist/react/hooks/useCustomer.js +14 -0
  23. package/dist/react/hooks/useEnvironment.d.ts +7 -0
  24. package/dist/react/hooks/useEnvironment.js +18 -0
  25. package/dist/react/hooks/useLocale.d.ts +2 -0
  26. package/dist/react/hooks/useLocale.js +43 -0
  27. package/dist/react/hooks/useOffers.d.ts +99 -0
  28. package/dist/react/hooks/useOffers.js +115 -0
  29. package/dist/react/hooks/useOrder.d.ts +44 -0
  30. package/dist/react/hooks/useOrder.js +77 -0
  31. package/dist/react/hooks/usePayment.d.ts +60 -0
  32. package/dist/react/hooks/usePayment.js +343 -0
  33. package/dist/react/hooks/usePaymentPolling.d.ts +45 -0
  34. package/dist/react/hooks/usePaymentPolling.js +146 -0
  35. package/dist/react/hooks/useProducts.d.ts +95 -0
  36. package/dist/react/hooks/useProducts.js +120 -0
  37. package/dist/react/hooks/useSession.d.ts +10 -0
  38. package/dist/react/hooks/useSession.js +17 -0
  39. package/dist/react/hooks/useThreeds.d.ts +38 -0
  40. package/dist/react/hooks/useThreeds.js +162 -0
  41. package/dist/react/hooks/useThreedsModal.d.ts +16 -0
  42. package/dist/react/hooks/useThreedsModal.js +328 -0
  43. package/dist/react/index.d.ts +26 -0
  44. package/dist/react/index.js +27 -0
  45. package/dist/react/providers/TagadaProvider.d.ts +55 -0
  46. package/dist/react/providers/TagadaProvider.js +471 -0
  47. package/dist/react/services/apiService.d.ts +149 -0
  48. package/dist/react/services/apiService.js +168 -0
  49. package/dist/react/types.d.ts +151 -0
  50. package/dist/react/types.js +4 -0
  51. package/dist/react/utils/__tests__/urlUtils.test.d.ts +1 -0
  52. package/dist/react/utils/__tests__/urlUtils.test.js +189 -0
  53. package/dist/react/utils/deviceInfo.d.ts +39 -0
  54. package/dist/react/utils/deviceInfo.js +163 -0
  55. package/dist/react/utils/jwtDecoder.d.ts +14 -0
  56. package/dist/react/utils/jwtDecoder.js +86 -0
  57. package/dist/react/utils/money.d.ts +2273 -0
  58. package/dist/react/utils/money.js +104 -0
  59. package/dist/react/utils/tokenStorage.d.ts +16 -0
  60. package/dist/react/utils/tokenStorage.js +52 -0
  61. package/dist/react/utils/urlUtils.d.ts +239 -0
  62. package/dist/react/utils/urlUtils.js +449 -0
  63. package/package.json +64 -0
@@ -0,0 +1,43 @@
1
+ 'use client';
2
+ /**
3
+ * useLocale - Hook to access locale data
4
+ * Only provides locale information, no translation functionality
5
+ */
6
+ import { useEffect, useState } from 'react';
7
+ import { useTagadaContext } from '../providers/TagadaProvider';
8
+ export function useLocale() {
9
+ const { locale: contextLocale } = useTagadaContext();
10
+ const [detectedLocale, setDetectedLocale] = useState('en-US');
11
+ const [detectedLanguageCode, setDetectedLanguageCode] = useState('en');
12
+ useEffect(() => {
13
+ // Client-side cookie access
14
+ const getCookie = (name) => {
15
+ const value = `; ${document.cookie}`;
16
+ const parts = value.split(`; ${name}=`);
17
+ if (parts.length === 2)
18
+ return parts.pop()?.split(';').shift();
19
+ return undefined;
20
+ };
21
+ // Get URL search parameters
22
+ const getUrlParam = (name) => {
23
+ const urlParams = new URLSearchParams(window.location.search);
24
+ return urlParams.get(name);
25
+ };
26
+ const localeFromCookies = getCookie('locale');
27
+ const localeFromQueryParams = getUrlParam('locale') || getUrlParam('lang');
28
+ const localeFromBrowser = navigator.language;
29
+ const finalLocale = localeFromCookies || localeFromQueryParams || localeFromBrowser || 'en-US';
30
+ // Extract language code from locale (e.g., "en-US" -> "en")
31
+ const finalLanguageCode = finalLocale?.split('-')[0] || navigator.language?.split('-')[0] || 'en';
32
+ setDetectedLocale(finalLocale);
33
+ setDetectedLanguageCode(finalLanguageCode);
34
+ }, []);
35
+ // Merge detected locale with context locale
36
+ const mergedLocale = {
37
+ ...contextLocale,
38
+ locale: detectedLocale,
39
+ language: detectedLanguageCode,
40
+ region: detectedLocale.split('-')[1] || 'US',
41
+ };
42
+ return mergedLocale;
43
+ }
@@ -0,0 +1,99 @@
1
+ export interface OfferItem {
2
+ id: string;
3
+ product: {
4
+ name: string;
5
+ description: string;
6
+ };
7
+ variant: {
8
+ name: string;
9
+ imageUrl: string;
10
+ };
11
+ quantity: number;
12
+ unitAmount: number;
13
+ amount: number;
14
+ adjustedAmount: number;
15
+ currency: string;
16
+ }
17
+ export interface OfferSummary {
18
+ items: OfferItem[];
19
+ totalAmount: number;
20
+ totalAdjustedAmount: number;
21
+ totalPromotionAmount: number;
22
+ currency: string;
23
+ adjustments: {
24
+ type: string;
25
+ description: string;
26
+ amount: number;
27
+ }[];
28
+ }
29
+ export interface Offer {
30
+ id: string;
31
+ titleTrans: Record<string, string>;
32
+ summaries: OfferSummary[];
33
+ }
34
+ export interface UseOffersOptions {
35
+ /**
36
+ * Array of offer IDs to fetch
37
+ */
38
+ offerIds: string[];
39
+ /**
40
+ * Whether to fetch offers automatically on mount
41
+ * @default true
42
+ */
43
+ enabled?: boolean;
44
+ /**
45
+ * Return URL for checkout sessions
46
+ */
47
+ returnUrl?: string;
48
+ }
49
+ export interface UseOffersResult {
50
+ /**
51
+ * Array of fetched offers
52
+ */
53
+ offers: Offer[];
54
+ /**
55
+ * Loading state
56
+ */
57
+ isLoading: boolean;
58
+ /**
59
+ * Error state
60
+ */
61
+ error: Error | null;
62
+ /**
63
+ * Refetch offers
64
+ */
65
+ refetch: () => Promise<void>;
66
+ /**
67
+ * Generate checkout session for a specific offer
68
+ */
69
+ createCheckoutSession: (offerId: string, options?: {
70
+ returnUrl?: string;
71
+ }) => Promise<{
72
+ checkoutUrl: string;
73
+ }>;
74
+ /**
75
+ * Pay for an offer directly
76
+ */
77
+ payOffer: (offerId: string) => Promise<void>;
78
+ /**
79
+ * Transform offer to checkout session with dynamic variant selection
80
+ */
81
+ transformToCheckout: (offerId: string, options?: {
82
+ returnUrl?: string;
83
+ }) => Promise<{
84
+ checkoutUrl: string;
85
+ }>;
86
+ /**
87
+ * Get offer by ID from the loaded offers
88
+ */
89
+ getOffer: (offerId: string) => Offer | undefined;
90
+ /**
91
+ * Get total value of all offers
92
+ */
93
+ getTotalValue: () => number;
94
+ /**
95
+ * Get total savings across all offers
96
+ */
97
+ getTotalSavings: () => number;
98
+ }
99
+ export declare function useOffers(options: UseOffersOptions): UseOffersResult;
@@ -0,0 +1,115 @@
1
+ import { useState, useCallback, useEffect } from 'react';
2
+ import { useTagadaContext } from '../providers/TagadaProvider';
3
+ export function useOffers(options) {
4
+ const { apiService, environment } = useTagadaContext();
5
+ const [offers, setOffers] = useState([]);
6
+ const [isLoading, setIsLoading] = useState(false);
7
+ const [error, setError] = useState(null);
8
+ const { offerIds, enabled = true, returnUrl } = options;
9
+ const fetchOffers = useCallback(async () => {
10
+ if (!offerIds.length || !enabled)
11
+ return;
12
+ setIsLoading(true);
13
+ setError(null);
14
+ try {
15
+ const fetchPromises = offerIds.map(async (offerId) => {
16
+ const response = await fetch(`${environment.apiConfig.baseUrl}/api/v1/offers/${offerId}`, {
17
+ method: 'GET',
18
+ headers: {
19
+ 'Content-Type': 'application/json',
20
+ 'X-Store-ID': apiService.getStoredStoreId() || '',
21
+ },
22
+ });
23
+ if (!response.ok) {
24
+ throw new Error(`Failed to fetch offer ${offerId}: ${response.statusText}`);
25
+ }
26
+ return response.json();
27
+ });
28
+ const fetchedOffers = await Promise.all(fetchPromises);
29
+ setOffers(fetchedOffers);
30
+ }
31
+ catch (err) {
32
+ const error = err instanceof Error ? err : new Error('Failed to fetch offers');
33
+ setError(error);
34
+ console.error('Error fetching offers:', error);
35
+ }
36
+ finally {
37
+ setIsLoading(false);
38
+ }
39
+ }, [apiService, environment.apiConfig.baseUrl, offerIds, enabled]);
40
+ const createCheckoutSession = useCallback(async (offerId, sessionOptions) => {
41
+ const response = await fetch(`${environment.apiConfig.baseUrl}/api/v1/offers/${offerId}/checkout`, {
42
+ method: 'POST',
43
+ headers: {
44
+ 'Content-Type': 'application/json',
45
+ 'X-Store-ID': apiService.getStoredStoreId() || '',
46
+ },
47
+ body: JSON.stringify({
48
+ returnUrl: sessionOptions?.returnUrl || returnUrl || window.location.origin,
49
+ }),
50
+ });
51
+ if (!response.ok) {
52
+ throw new Error(`Failed to create checkout session: ${response.statusText}`);
53
+ }
54
+ return response.json();
55
+ }, [apiService, environment.apiConfig.baseUrl, returnUrl]);
56
+ const payOffer = useCallback(async (offerId) => {
57
+ const response = await fetch(`${environment.apiConfig.baseUrl}/api/v1/offers/${offerId}/pay`, {
58
+ method: 'POST',
59
+ headers: {
60
+ 'Content-Type': 'application/json',
61
+ 'X-Store-ID': apiService.getStoredStoreId() || '',
62
+ },
63
+ });
64
+ if (!response.ok) {
65
+ throw new Error(`Failed to pay offer: ${response.statusText}`);
66
+ }
67
+ return response.json();
68
+ }, [apiService, environment.apiConfig.baseUrl]);
69
+ const transformToCheckout = useCallback(async (offerId, sessionOptions) => {
70
+ const response = await fetch(`${environment.apiConfig.baseUrl}/api/v1/offers/${offerId}/transform-to-checkout`, {
71
+ method: 'POST',
72
+ headers: {
73
+ 'Content-Type': 'application/json',
74
+ 'X-Store-ID': apiService.getStoredStoreId() || '',
75
+ },
76
+ body: JSON.stringify({
77
+ returnUrl: sessionOptions?.returnUrl || returnUrl || window.location.origin,
78
+ }),
79
+ });
80
+ if (!response.ok) {
81
+ throw new Error(`Failed to transform offer to checkout: ${response.statusText}`);
82
+ }
83
+ return response.json();
84
+ }, [apiService, environment.apiConfig.baseUrl, returnUrl]);
85
+ const getOffer = useCallback((offerId) => {
86
+ return offers.find((offer) => offer.id === offerId);
87
+ }, [offers]);
88
+ const getTotalValue = useCallback(() => {
89
+ return offers.reduce((total, offer) => {
90
+ const firstSummary = offer.summaries[0];
91
+ return total + (firstSummary?.totalAdjustedAmount || 0);
92
+ }, 0);
93
+ }, [offers]);
94
+ const getTotalSavings = useCallback(() => {
95
+ return offers.reduce((total, offer) => {
96
+ const firstSummary = offer.summaries[0];
97
+ return total + (firstSummary?.totalPromotionAmount || 0);
98
+ }, 0);
99
+ }, [offers]);
100
+ useEffect(() => {
101
+ void fetchOffers();
102
+ }, [fetchOffers]);
103
+ return {
104
+ offers,
105
+ isLoading,
106
+ error,
107
+ refetch: fetchOffers,
108
+ createCheckoutSession,
109
+ payOffer,
110
+ transformToCheckout,
111
+ getOffer,
112
+ getTotalValue,
113
+ getTotalSavings,
114
+ };
115
+ }
@@ -0,0 +1,44 @@
1
+ import { Order } from '../types';
2
+ export interface UseOrderOptions {
3
+ /**
4
+ * Whether to automatically fetch order data when orderId is provided
5
+ * @default true
6
+ */
7
+ autoFetch?: boolean;
8
+ /**
9
+ * Order ID to fetch
10
+ */
11
+ orderId?: string;
12
+ /**
13
+ * Whether the hook is enabled/should run
14
+ * @default true
15
+ */
16
+ enabled?: boolean;
17
+ }
18
+ export interface UseOrderResult {
19
+ /**
20
+ * Order data
21
+ */
22
+ order: Order | null;
23
+ /**
24
+ * Loading state
25
+ */
26
+ isLoading: boolean;
27
+ /**
28
+ * Error state
29
+ */
30
+ error: Error | null;
31
+ /**
32
+ * Fetch order by ID
33
+ */
34
+ fetchOrder: (orderId: string) => Promise<Order>;
35
+ /**
36
+ * Refetch the current order
37
+ */
38
+ refetch: () => Promise<void>;
39
+ /**
40
+ * Clear order data
41
+ */
42
+ clear: () => void;
43
+ }
44
+ export declare function useOrder(options?: UseOrderOptions): UseOrderResult;
@@ -0,0 +1,77 @@
1
+ 'use client';
2
+ import React, { useState, useCallback, useRef } from 'react';
3
+ import { useTagadaContext } from '../providers/TagadaProvider';
4
+ export function useOrder(options = {}) {
5
+ const { autoFetch = true, orderId, enabled = true } = options;
6
+ const { apiService, session } = useTagadaContext();
7
+ const [order, setOrder] = useState(null);
8
+ const [isLoading, setIsLoading] = useState(false);
9
+ const [error, setError] = useState(null);
10
+ const currentOrderIdRef = useRef(null);
11
+ const fetchOrder = useCallback(async (orderIdToFetch) => {
12
+ if (!orderIdToFetch) {
13
+ throw new Error('Order ID is required');
14
+ }
15
+ if (!session?.storeId) {
16
+ throw new Error('Store session is required');
17
+ }
18
+ if (!apiService) {
19
+ throw new Error('API service not available');
20
+ }
21
+ setIsLoading(true);
22
+ setError(null);
23
+ currentOrderIdRef.current = orderIdToFetch;
24
+ try {
25
+ console.log('🔍 Fetching order:', orderIdToFetch);
26
+ const response = await apiService.fetch(`/api/v1/orders/${encodeURIComponent(orderIdToFetch)}`, {
27
+ method: 'GET',
28
+ params: {
29
+ storeId: session.storeId,
30
+ },
31
+ });
32
+ const fetchedOrder = response.order;
33
+ if (!fetchedOrder) {
34
+ throw new Error('Order not found');
35
+ }
36
+ console.log('✅ Order fetched successfully:', fetchedOrder.id);
37
+ setOrder(fetchedOrder);
38
+ return fetchedOrder;
39
+ }
40
+ catch (err) {
41
+ const error = err instanceof Error ? err : new Error('Failed to fetch order');
42
+ console.error('❌ Failed to fetch order:', error);
43
+ setError(error);
44
+ throw error;
45
+ }
46
+ finally {
47
+ setIsLoading(false);
48
+ }
49
+ }, [apiService, session?.storeId]);
50
+ const refetch = useCallback(async () => {
51
+ if (!currentOrderIdRef.current) {
52
+ throw new Error('No order ID to refetch');
53
+ }
54
+ await fetchOrder(currentOrderIdRef.current);
55
+ }, [fetchOrder]);
56
+ const clear = useCallback(() => {
57
+ setOrder(null);
58
+ setError(null);
59
+ currentOrderIdRef.current = null;
60
+ }, []);
61
+ // Auto-fetch when orderId is provided and options allow it
62
+ React.useEffect(() => {
63
+ if (autoFetch && orderId && enabled && session?.storeId) {
64
+ fetchOrder(orderId).catch((err) => {
65
+ console.warn('Auto-fetch failed:', err);
66
+ });
67
+ }
68
+ }, [autoFetch, orderId, enabled, session?.storeId, fetchOrder]);
69
+ return {
70
+ order,
71
+ isLoading,
72
+ error,
73
+ fetchOrder,
74
+ refetch,
75
+ clear,
76
+ };
77
+ }
@@ -0,0 +1,60 @@
1
+ import { Payment } from './usePaymentPolling';
2
+ import { ThreedsProvider } from './useThreeds';
3
+ export interface ApplePayToken {
4
+ id: string;
5
+ type: string;
6
+ card: {
7
+ bin: string;
8
+ last4: string;
9
+ expiration_month: number;
10
+ expiration_year: number;
11
+ brand: string;
12
+ };
13
+ }
14
+ export interface CardPaymentMethod {
15
+ cardNumber: string;
16
+ expiryDate: string;
17
+ cvc: string;
18
+ cardholderName?: string;
19
+ }
20
+ export interface Order {
21
+ id: string;
22
+ status: string;
23
+ totalAmount: number;
24
+ currency: string;
25
+ }
26
+ export interface PaymentResponse {
27
+ paymentId: string;
28
+ payment: Payment;
29
+ order?: Order;
30
+ }
31
+ export interface PaymentOptions {
32
+ enableThreeds?: boolean;
33
+ threedsProvider?: ThreedsProvider;
34
+ onSuccess?: (payment: Payment) => void;
35
+ onFailure?: (error: string) => void;
36
+ onRequireAction?: (payment: Payment) => void;
37
+ }
38
+ export interface PaymentInstrumentResponse {
39
+ id: string;
40
+ token: string;
41
+ type: string;
42
+ card?: {
43
+ maskedCardNumber?: string;
44
+ expirationMonth?: number;
45
+ expirationYear?: number;
46
+ brand?: string;
47
+ };
48
+ }
49
+ export interface PaymentHook {
50
+ processCardPayment: (checkoutSessionId: string, cardData: CardPaymentMethod, options?: PaymentOptions) => Promise<PaymentResponse>;
51
+ processApplePayPayment: (checkoutSessionId: string, applePayToken: ApplePayToken, options?: PaymentOptions) => Promise<PaymentResponse>;
52
+ processPaymentWithInstrument: (checkoutSessionId: string, paymentInstrumentId: string, options?: PaymentOptions) => Promise<PaymentResponse>;
53
+ createCardPaymentInstrument: (cardData: CardPaymentMethod) => Promise<PaymentInstrumentResponse>;
54
+ createApplePayPaymentInstrument: (applePayToken: ApplePayToken) => Promise<PaymentInstrumentResponse>;
55
+ isLoading: boolean;
56
+ error: string | null;
57
+ clearError: () => void;
58
+ currentPaymentId: string | null;
59
+ }
60
+ export declare function usePayment(): PaymentHook;