@idealyst/payments 1.2.108 → 1.2.109

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.
@@ -1,90 +1,149 @@
1
1
  import { useState, useCallback, useEffect, useRef } from 'react';
2
2
  import type {
3
- UsePaymentsOptions,
4
- UsePaymentsResult,
5
- PaymentProviderStatus,
6
- PaymentConfig,
7
- PaymentError,
8
- PaymentMethodAvailability,
9
- PaymentSheetRequest,
10
- PaymentResult,
3
+ UseIAPOptions,
4
+ UseIAPResult,
5
+ IAPProviderStatus,
6
+ IAPConfig,
7
+ IAPError,
8
+ IAPProduct,
9
+ IAPSubscription,
10
+ IAPPurchase,
11
11
  } from './types';
12
- import { INITIAL_PROVIDER_STATUS } from './constants';
13
12
 
14
13
  /**
15
- * Factory that creates a usePayments hook bound to platform-specific functions.
14
+ * Factory that creates a useIAP hook bound to platform-specific functions.
16
15
  * Each platform entry point calls this with the correct implementations.
17
16
  */
18
- export function createUsePaymentsHook(fns: {
19
- initializePayments: (config: PaymentConfig) => Promise<void>;
20
- checkPaymentAvailability: () => Promise<PaymentMethodAvailability[]>;
21
- confirmPayment: (request: PaymentSheetRequest) => Promise<PaymentResult>;
22
- createPaymentMethod: (request: PaymentSheetRequest) => Promise<PaymentResult>;
23
- getPaymentStatus: () => PaymentProviderStatus;
17
+ export function createUseIAPHook(fns: {
18
+ initializeIAP: (config?: IAPConfig) => Promise<void>;
19
+ getProducts: (skus: string[]) => Promise<IAPProduct[]>;
20
+ getSubscriptions: (skus: string[]) => Promise<IAPSubscription[]>;
21
+ purchaseProduct: (sku: string) => Promise<IAPPurchase>;
22
+ purchaseSubscription: (sku: string, offerToken?: string) => Promise<IAPPurchase>;
23
+ finishTransaction: (purchase: IAPPurchase, isConsumable?: boolean) => Promise<void>;
24
+ restorePurchases: () => Promise<IAPPurchase[]>;
25
+ getIAPStatus: () => IAPProviderStatus;
26
+ endConnection: () => Promise<void>;
24
27
  }) {
25
- return function usePayments(
26
- options: UsePaymentsOptions = {},
27
- ): UsePaymentsResult {
28
- const { config, autoCheckAvailability = true } = options;
28
+ return function useIAP(options: UseIAPOptions = {}): UseIAPResult {
29
+ const { config, productSkus, subscriptionSkus } = options;
29
30
 
30
- const [status, setStatus] = useState<PaymentProviderStatus>(
31
- INITIAL_PROVIDER_STATUS,
32
- );
31
+ const [isReady, setIsReady] = useState(false);
33
32
  const [isProcessing, setIsProcessing] = useState(false);
34
- const [error, setError] = useState<PaymentError | null>(null);
33
+ const [error, setError] = useState<IAPError | null>(null);
34
+ const [products, setProducts] = useState<IAPProduct[]>([]);
35
+ const [subscriptions, setSubscriptions] = useState<IAPSubscription[]>([]);
36
+ const [currentPurchase, setCurrentPurchase] = useState<IAPPurchase | null>(null);
35
37
  const initializedRef = useRef(false);
36
38
 
37
- // Auto-initialize if config provided
39
+ // Auto-initialize and fetch products/subscriptions
38
40
  useEffect(() => {
39
- if (!config || initializedRef.current) return;
41
+ if (initializedRef.current) return;
42
+ if (config === undefined && !productSkus && !subscriptionSkus) return;
40
43
  initializedRef.current = true;
41
44
 
42
45
  const init = async () => {
43
- await fns.initializePayments(config);
44
- const currentStatus = fns.getPaymentStatus();
45
- setStatus(currentStatus);
46
- setError(currentStatus.error ?? null);
47
-
48
- if (autoCheckAvailability && currentStatus.state === 'ready') {
49
- await fns.checkPaymentAvailability();
50
- setStatus(fns.getPaymentStatus());
46
+ try {
47
+ await fns.initializeIAP(config);
48
+ const status = fns.getIAPStatus();
49
+
50
+ if (status.state === 'ready') {
51
+ setIsReady(true);
52
+
53
+ if (productSkus?.length) {
54
+ const prods = await fns.getProducts(productSkus);
55
+ setProducts(prods);
56
+ }
57
+ if (subscriptionSkus?.length) {
58
+ const subs = await fns.getSubscriptions(subscriptionSkus);
59
+ setSubscriptions(subs);
60
+ }
61
+ } else if (status.error) {
62
+ setError(status.error);
63
+ }
64
+ } catch (err) {
65
+ setError(err as IAPError);
51
66
  }
52
67
  };
53
68
  init();
54
- }, [config, autoCheckAvailability]);
55
69
 
56
- const initialize = useCallback(
57
- async (initConfig: PaymentConfig) => {
58
- setError(null);
59
- await fns.initializePayments(initConfig);
60
- const currentStatus = fns.getPaymentStatus();
61
- setStatus(currentStatus);
62
- setError(currentStatus.error ?? null);
63
-
64
- if (autoCheckAvailability && currentStatus.state === 'ready') {
65
- await fns.checkPaymentAvailability();
66
- setStatus(fns.getPaymentStatus());
67
- }
68
- },
69
- [autoCheckAvailability],
70
- );
70
+ return () => {
71
+ fns.endConnection();
72
+ };
73
+ }, [config, productSkus, subscriptionSkus]);
74
+
75
+ const initialize = useCallback(async (initConfig?: IAPConfig) => {
76
+ setError(null);
77
+ try {
78
+ await fns.initializeIAP(initConfig);
79
+ const status = fns.getIAPStatus();
80
+ setIsReady(status.state === 'ready');
81
+ if (status.error) setError(status.error);
82
+ } catch (err) {
83
+ setError(err as IAPError);
84
+ }
85
+ }, []);
71
86
 
72
- const checkAvailability = useCallback(async () => {
73
- const result = await fns.checkPaymentAvailability();
74
- setStatus(fns.getPaymentStatus());
75
- return result;
87
+ const getProductsAction = useCallback(async (skus: string[]) => {
88
+ setIsProcessing(true);
89
+ setError(null);
90
+ try {
91
+ const result = await fns.getProducts(skus);
92
+ setProducts(result);
93
+ return result;
94
+ } catch (err) {
95
+ const iapError = err as IAPError;
96
+ setError(iapError);
97
+ throw iapError;
98
+ } finally {
99
+ setIsProcessing(false);
100
+ }
76
101
  }, []);
77
102
 
78
- const confirmPaymentAction = useCallback(
79
- async (request: PaymentSheetRequest) => {
103
+ const getSubscriptionsAction = useCallback(async (skus: string[]) => {
104
+ setIsProcessing(true);
105
+ setError(null);
106
+ try {
107
+ const result = await fns.getSubscriptions(skus);
108
+ setSubscriptions(result);
109
+ return result;
110
+ } catch (err) {
111
+ const iapError = err as IAPError;
112
+ setError(iapError);
113
+ throw iapError;
114
+ } finally {
115
+ setIsProcessing(false);
116
+ }
117
+ }, []);
118
+
119
+ const purchaseProductAction = useCallback(async (sku: string) => {
120
+ setIsProcessing(true);
121
+ setError(null);
122
+ try {
123
+ const purchase = await fns.purchaseProduct(sku);
124
+ setCurrentPurchase(purchase);
125
+ return purchase;
126
+ } catch (err) {
127
+ const iapError = err as IAPError;
128
+ setError(iapError);
129
+ throw iapError;
130
+ } finally {
131
+ setIsProcessing(false);
132
+ }
133
+ }, []);
134
+
135
+ const purchaseSubscriptionAction = useCallback(
136
+ async (sku: string, offerToken?: string) => {
80
137
  setIsProcessing(true);
81
138
  setError(null);
82
139
  try {
83
- return await fns.confirmPayment(request);
140
+ const purchase = await fns.purchaseSubscription(sku, offerToken);
141
+ setCurrentPurchase(purchase);
142
+ return purchase;
84
143
  } catch (err) {
85
- const paymentError = err as PaymentError;
86
- setError(paymentError);
87
- throw paymentError;
144
+ const iapError = err as IAPError;
145
+ setError(iapError);
146
+ throw iapError;
88
147
  } finally {
89
148
  setIsProcessing(false);
90
149
  }
@@ -92,45 +151,50 @@ export function createUsePaymentsHook(fns: {
92
151
  [],
93
152
  );
94
153
 
95
- const createPaymentMethodAction = useCallback(
96
- async (request: PaymentSheetRequest) => {
97
- setIsProcessing(true);
98
- setError(null);
154
+ const finishTransactionAction = useCallback(
155
+ async (purchase: IAPPurchase, isConsumable?: boolean) => {
99
156
  try {
100
- return await fns.createPaymentMethod(request);
157
+ await fns.finishTransaction(purchase, isConsumable);
101
158
  } catch (err) {
102
- const paymentError = err as PaymentError;
103
- setError(paymentError);
104
- throw paymentError;
105
- } finally {
106
- setIsProcessing(false);
159
+ const iapError = err as IAPError;
160
+ setError(iapError);
161
+ throw iapError;
107
162
  }
108
163
  },
109
164
  [],
110
165
  );
111
166
 
112
- const clearError = useCallback(() => setError(null), []);
167
+ const restorePurchasesAction = useCallback(async () => {
168
+ setIsProcessing(true);
169
+ setError(null);
170
+ try {
171
+ return await fns.restorePurchases();
172
+ } catch (err) {
173
+ const iapError = err as IAPError;
174
+ setError(iapError);
175
+ throw iapError;
176
+ } finally {
177
+ setIsProcessing(false);
178
+ }
179
+ }, []);
113
180
 
114
- const { availablePaymentMethods } = status;
181
+ const clearError = useCallback(() => setError(null), []);
115
182
 
116
183
  return {
117
- status,
118
- isReady: status.state === 'ready',
184
+ isReady,
119
185
  isProcessing,
120
- availablePaymentMethods,
121
- isApplePayAvailable: availablePaymentMethods.some(
122
- (m) => m.type === 'apple_pay' && m.isAvailable,
123
- ),
124
- isGooglePayAvailable: availablePaymentMethods.some(
125
- (m) => m.type === 'google_pay' && m.isAvailable,
126
- ),
127
- isPaymentAvailable: status.isPaymentAvailable,
128
186
  error,
187
+ products,
188
+ subscriptions,
189
+ currentPurchase,
129
190
 
130
191
  initialize,
131
- checkAvailability,
132
- confirmPayment: confirmPaymentAction,
133
- createPaymentMethod: createPaymentMethodAction,
192
+ getProducts: getProductsAction,
193
+ getSubscriptions: getSubscriptionsAction,
194
+ purchaseProduct: purchaseProductAction,
195
+ purchaseSubscription: purchaseSubscriptionAction,
196
+ finishTransaction: finishTransactionAction,
197
+ restorePurchases: restorePurchasesAction,
134
198
  clearError,
135
199
  };
136
200
  };