@umituz/react-native-subscription 2.44.1 → 2.45.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-subscription",
3
- "version": "2.44.1",
3
+ "version": "2.45.1",
4
4
  "description": "Complete subscription management with RevenueCat, paywall UI, and credits system for React Native apps",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -1,14 +1,19 @@
1
+ /**
2
+ * Paywall Actions Hook
3
+ *
4
+ * Handles purchase and restore operations with premium verification.
5
+ * Ref management and success checking extracted to utilities.
6
+ */
7
+
1
8
  import { useState, useCallback, useRef, useMemo } from "react";
2
9
  import type { PurchasesPackage } from "react-native-purchases";
3
- import type { PurchaseSource } from "../../subscription/core/SubscriptionConstants";
4
- import { useSubscriptionStatus } from "../../subscription/presentation/useSubscriptionStatus";
5
- import { useCredits } from "../../credits/presentation/useCredits";
10
+ import { usePremiumVerification } from "./usePaywallActions.utils";
6
11
 
7
12
  interface UsePaywallActionsParams {
8
13
  packages?: PurchasesPackage[];
9
14
  purchasePackage: (pkg: PurchasesPackage) => Promise<boolean>;
10
15
  restorePurchase: () => Promise<boolean>;
11
- source?: PurchaseSource;
16
+ source?: string; // PurchaseSource
12
17
  onPurchaseSuccess?: () => void;
13
18
  onPurchaseError?: (error: Error | string) => void;
14
19
  onAuthRequired?: () => void;
@@ -30,34 +35,42 @@ export function usePaywallActions({
30
35
  const isProcessingRef = useRef(isProcessing);
31
36
  isProcessingRef.current = isProcessing;
32
37
 
33
- const { refetch: refetchStatus } = useSubscriptionStatus();
34
- const { refetch: refetchCredits } = useCredits();
35
-
36
- const purchasePackageRef = useRef(purchasePackage);
37
- const restorePurchaseRef = useRef(restorePurchase);
38
- const onPurchaseSuccessRef = useRef(onPurchaseSuccess);
39
- const onPurchaseErrorRef = useRef(onPurchaseError);
40
- const onAuthRequiredRef = useRef(onAuthRequired);
41
- const onCloseRef = useRef(onClose);
42
- const packagesRef = useRef(packages);
43
-
44
- purchasePackageRef.current = purchasePackage;
45
- restorePurchaseRef.current = restorePurchase;
46
- onPurchaseSuccessRef.current = onPurchaseSuccess;
47
- onPurchaseErrorRef.current = onPurchaseError;
48
- onAuthRequiredRef.current = onAuthRequired;
49
- onCloseRef.current = onClose;
50
- packagesRef.current = packages;
38
+ const { verifyPremiumStatus } = usePremiumVerification();
39
+
40
+ // Ref management
41
+ const callbacksRef = useRef({
42
+ purchasePackage,
43
+ restorePurchase,
44
+ onPurchaseSuccess,
45
+ onPurchaseError,
46
+ onAuthRequired,
47
+ onClose,
48
+ packages,
49
+ });
50
+
51
+ // Update refs
52
+ callbacksRef.current = {
53
+ purchasePackage,
54
+ restorePurchase,
55
+ onPurchaseSuccess,
56
+ onPurchaseError,
57
+ onAuthRequired,
58
+ onClose,
59
+ packages,
60
+ };
61
+
62
+ // ─────────────────────────────────────────────────────────────
63
+ // PURCHASE HANDLER
64
+ // ─────────────────────────────────────────────────────────────
51
65
 
52
66
  const handlePurchase = useCallback(async () => {
53
67
  const currentSelectedId = selectedPlanId;
54
68
  if (!currentSelectedId) return;
55
-
56
69
  if (isProcessingRef.current) return;
57
70
 
58
- const pkg = packagesRef.current.find((p) => p.product.identifier === currentSelectedId);
71
+ const pkg = callbacksRef.current.packages.find((p) => p.product.identifier === currentSelectedId);
59
72
  if (!pkg) {
60
- onPurchaseErrorRef.current?.(new Error(`Package not found: ${currentSelectedId}`));
73
+ callbacksRef.current.onPurchaseError?.(new Error(`Package not found: ${currentSelectedId}`));
61
74
  return;
62
75
  }
63
76
 
@@ -70,7 +83,7 @@ export function usePaywallActions({
70
83
  setIsProcessing(true);
71
84
 
72
85
  try {
73
- const success = await purchasePackageRef.current(pkg);
86
+ const success = await callbacksRef.current.purchasePackage(pkg);
74
87
 
75
88
  if (__DEV__) {
76
89
  console.log('[usePaywallActions] ✅ Purchase completed', { success });
@@ -78,36 +91,17 @@ export function usePaywallActions({
78
91
 
79
92
  let isActuallySuccessful = success === true;
80
93
 
94
+ // Fallback verification if success is undefined
81
95
  if (success === undefined) {
82
- if (__DEV__) {
83
- console.log('[usePaywallActions] 🔍 Checking premium status as fallback...');
84
- }
85
-
86
- const [statusResult, creditsResult] = await Promise.all([
87
- refetchStatus(),
88
- refetchCredits()
89
- ]);
90
-
91
- const isSubscriptionPremium = statusResult.data?.isPremium ?? false;
92
- const isCreditsPremium = creditsResult.data?.isPremium ?? false;
93
-
94
- isActuallySuccessful = isSubscriptionPremium || isCreditsPremium;
95
-
96
- if (__DEV__) {
97
- console.log('[usePaywallActions] 📊 Fallback check result:', {
98
- isSubscriptionPremium,
99
- isCreditsPremium,
100
- isActuallySuccessful
101
- });
102
- }
96
+ isActuallySuccessful = await verifyPremiumStatus();
103
97
  }
104
98
 
105
99
  if (isActuallySuccessful) {
106
100
  if (__DEV__) {
107
101
  console.log('[usePaywallActions] 🎉 Purchase successful, closing paywall');
108
102
  }
109
- onPurchaseSuccessRef.current?.();
110
- onCloseRef.current?.();
103
+ callbacksRef.current.onPurchaseSuccess?.();
104
+ callbacksRef.current.onClose?.();
111
105
  } else {
112
106
  if (__DEV__) {
113
107
  console.warn('[usePaywallActions] ⚠️ Purchase did not indicate success');
@@ -117,11 +111,15 @@ export function usePaywallActions({
117
111
  if (__DEV__) {
118
112
  console.error('[usePaywallActions] ❌ Purchase error:', error);
119
113
  }
120
- onPurchaseErrorRef.current?.(error instanceof Error ? error : new Error(String(error)));
114
+ callbacksRef.current.onPurchaseError?.(error instanceof Error ? error : new Error(String(error)));
121
115
  } finally {
122
116
  setIsProcessing(false);
123
117
  }
124
- }, [selectedPlanId, refetchStatus, refetchCredits]);
118
+ }, [selectedPlanId, verifyPremiumStatus]);
119
+
120
+ // ─────────────────────────────────────────────────────────────
121
+ // RESTORE HANDLER
122
+ // ─────────────────────────────────────────────────────────────
125
123
 
126
124
  const handleRestore = useCallback(async () => {
127
125
  if (isProcessingRef.current) return;
@@ -131,8 +129,9 @@ export function usePaywallActions({
131
129
  }
132
130
 
133
131
  setIsProcessing(true);
132
+
134
133
  try {
135
- const success = await restorePurchaseRef.current();
134
+ const success = await callbacksRef.current.restorePurchase();
136
135
 
137
136
  if (__DEV__) {
138
137
  console.log('[usePaywallActions] ✅ Restore completed', { success });
@@ -140,20 +139,17 @@ export function usePaywallActions({
140
139
 
141
140
  let isActuallySuccessful = success === true;
142
141
 
142
+ // Fallback verification if success is undefined
143
143
  if (success === undefined) {
144
- const [statusResult, creditsResult] = await Promise.all([
145
- refetchStatus(),
146
- refetchCredits()
147
- ]);
148
- isActuallySuccessful = (statusResult.data?.isPremium ?? false) || (creditsResult.data?.isPremium ?? false);
144
+ isActuallySuccessful = await verifyPremiumStatus();
149
145
  }
150
146
 
151
147
  if (isActuallySuccessful) {
152
148
  if (__DEV__) {
153
149
  console.log('[usePaywallActions] 🎉 Restore successful, closing paywall');
154
150
  }
155
- onPurchaseSuccessRef.current?.();
156
- onCloseRef.current?.();
151
+ callbacksRef.current.onPurchaseSuccess?.();
152
+ callbacksRef.current.onClose?.();
157
153
  } else {
158
154
  if (__DEV__) {
159
155
  console.warn('[usePaywallActions] ⚠️ Restore did not indicate success');
@@ -163,11 +159,15 @@ export function usePaywallActions({
163
159
  if (__DEV__) {
164
160
  console.error('[usePaywallActions] ❌ Restore error:', error);
165
161
  }
166
- onPurchaseErrorRef.current?.(error instanceof Error ? error : new Error(String(error)));
162
+ callbacksRef.current.onPurchaseError?.(error instanceof Error ? error : new Error(String(error)));
167
163
  } finally {
168
164
  setIsProcessing(false);
169
165
  }
170
- }, [refetchStatus, refetchCredits]);
166
+ }, [verifyPremiumStatus]);
167
+
168
+ // ─────────────────────────────────────────────────────────────
169
+ // RESET
170
+ // ─────────────────────────────────────────────────────────────
171
171
 
172
172
  const resetState = useCallback(() => {
173
173
  if (__DEV__) {
@@ -177,6 +177,10 @@ export function usePaywallActions({
177
177
  setIsProcessing(false);
178
178
  }, []);
179
179
 
180
+ // ─────────────────────────────────────────────────────────────
181
+ // RETURN
182
+ // ─────────────────────────────────────────────────────────────
183
+
180
184
  return useMemo(() => ({
181
185
  selectedPlanId,
182
186
  setSelectedPlanId,
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Paywall Actions Utilities
3
+ * Helper functions for paywall purchase/restore operations
4
+ */
5
+
6
+ import { useSubscriptionStatus } from "../../subscription/presentation/useSubscriptionStatus";
7
+ import { useCredits } from "../../credits/presentation/useCredits";
8
+
9
+ export function usePremiumVerification() {
10
+ const { refetch: refetchStatus } = useSubscriptionStatus();
11
+ const { refetch: refetchCredits } = useCredits();
12
+
13
+ const verifyPremiumStatus = async (): Promise<boolean> => {
14
+ if (__DEV__) {
15
+ console.log('[PremiumVerification] 🔍 Checking premium status as fallback...');
16
+ }
17
+
18
+ const [statusResult, creditsResult] = await Promise.all([
19
+ refetchStatus(),
20
+ refetchCredits()
21
+ ]);
22
+
23
+ const isSubscriptionPremium = statusResult.data?.isPremium ?? false;
24
+ const isCreditsPremium = creditsResult.data?.isPremium ?? false;
25
+ const isActuallySuccessful = isSubscriptionPremium || isCreditsPremium;
26
+
27
+ if (__DEV__) {
28
+ console.log('[PremiumVerification] 📊 Fallback check result:', {
29
+ isSubscriptionPremium,
30
+ isCreditsPremium,
31
+ isActuallySuccessful
32
+ });
33
+ }
34
+
35
+ return isActuallySuccessful;
36
+ };
37
+
38
+ return { verifyPremiumStatus };
39
+ }