@umituz/react-native-subscription 2.35.12 → 2.35.14
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 +1 -1
- package/src/domains/paywall/components/PaywallContainer.tsx +8 -17
- package/src/domains/paywall/components/PaywallModal.tsx +11 -2
- package/src/domains/paywall/components/PaywallModal.types.ts +5 -0
- package/src/domains/paywall/hooks/usePaywallActions.ts +127 -11
- package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +0 -7
- package/src/domains/subscription/infrastructure/handlers/package-operations/PackagePurchaser.ts +0 -10
- package/src/domains/subscription/infrastructure/managers/SubscriptionManager.ts +0 -10
- package/src/domains/subscription/infrastructure/managers/managerOperations.ts +0 -8
- package/src/domains/subscription/infrastructure/services/PurchaseHandler.ts +0 -15
- package/src/domains/subscription/infrastructure/services/RevenueCatService.types.ts +0 -8
- package/src/domains/subscription/infrastructure/services/purchase/PurchaseExecutor.ts +0 -11
- package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +51 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.35.
|
|
3
|
+
"version": "2.35.14",
|
|
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",
|
|
@@ -4,7 +4,6 @@ import { useSubscriptionPackages } from "../../subscription/infrastructure/hooks
|
|
|
4
4
|
import { useRevenueCatTrialEligibility } from "../../subscription/infrastructure/hooks/useRevenueCatTrialEligibility";
|
|
5
5
|
import { createCreditAmountsFromPackages } from "../../../utils/creditMapper";
|
|
6
6
|
import { PaywallModal } from "./PaywallModal";
|
|
7
|
-
import { usePaywallActions } from "../hooks/usePaywallActions";
|
|
8
7
|
import { useAuthAwarePurchase } from "../../subscription/presentation/useAuthAwarePurchase";
|
|
9
8
|
import { useTrialEligibilityCheck } from "../hooks/useTrialEligibilityCheck";
|
|
10
9
|
import type { PaywallContainerProps } from "./PaywallContainer.types";
|
|
@@ -36,20 +35,9 @@ export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
|
36
35
|
|
|
37
36
|
const { data: packages = [], isLoading } = useSubscriptionPackages();
|
|
38
37
|
const { eligibilityMap, checkEligibility } = useRevenueCatTrialEligibility();
|
|
39
|
-
|
|
40
|
-
const { handlePurchase: performPurchase, handleRestore: performRestore } = useAuthAwarePurchase({
|
|
41
|
-
source: purchaseSource
|
|
42
|
-
});
|
|
43
38
|
|
|
44
|
-
const { handlePurchase, handleRestore } =
|
|
45
|
-
|
|
46
|
-
onPurchase: performPurchase,
|
|
47
|
-
onRestore: performRestore,
|
|
48
|
-
source: purchaseSource,
|
|
49
|
-
onPurchaseSuccess,
|
|
50
|
-
onPurchaseError,
|
|
51
|
-
onAuthRequired,
|
|
52
|
-
onClose: handleClose,
|
|
39
|
+
const { handlePurchase: performPurchase, handleRestore: performRestore } = useAuthAwarePurchase({
|
|
40
|
+
source: purchaseSource
|
|
53
41
|
});
|
|
54
42
|
|
|
55
43
|
const trialEligibility = useTrialEligibilityCheck({
|
|
@@ -60,7 +48,6 @@ export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
|
60
48
|
trialConfig,
|
|
61
49
|
});
|
|
62
50
|
|
|
63
|
-
// Compute credit amounts from packageAllocations if not provided directly
|
|
64
51
|
const creditAmounts = useMemo(() => {
|
|
65
52
|
if (providedCreditAmounts) return providedCreditAmounts;
|
|
66
53
|
if (!packageAllocations || packages.length === 0) return undefined;
|
|
@@ -81,10 +68,14 @@ export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
|
81
68
|
bestValueIdentifier={bestValueIdentifier}
|
|
82
69
|
creditAmounts={creditAmounts}
|
|
83
70
|
creditsLabel={creditsLabel}
|
|
84
|
-
onPurchase={
|
|
85
|
-
onRestore={
|
|
71
|
+
onPurchase={performPurchase}
|
|
72
|
+
onRestore={performRestore}
|
|
86
73
|
trialEligibility={trialEligibility}
|
|
87
74
|
trialSubtitleText={trialConfig?.enabled ? trialConfig.trialText : undefined}
|
|
75
|
+
onPurchaseSuccess={onPurchaseSuccess}
|
|
76
|
+
onPurchaseError={onPurchaseError}
|
|
77
|
+
onAuthRequired={onAuthRequired}
|
|
78
|
+
source={purchaseSource}
|
|
88
79
|
/>
|
|
89
80
|
);
|
|
90
81
|
};
|
|
@@ -11,10 +11,19 @@ import { usePaywallActions } from "../hooks/usePaywallActions";
|
|
|
11
11
|
import { PaywallModalProps } from "./PaywallModal.types";
|
|
12
12
|
|
|
13
13
|
export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
14
|
-
const { visible, onClose, translations, packages = [], features = [], legalUrls = {}, bestValueIdentifier, creditAmounts, creditsLabel, heroImage, onPurchase, onRestore, trialEligibility = {}, trialSubtitleText } = props;
|
|
14
|
+
const { visible, onClose, translations, packages = [], features = [], legalUrls = {}, bestValueIdentifier, creditAmounts, creditsLabel, heroImage, onPurchase, onRestore, trialEligibility = {}, trialSubtitleText, onPurchaseSuccess, onPurchaseError, onAuthRequired, source } = props;
|
|
15
15
|
const tokens = useAppDesignTokens();
|
|
16
16
|
const insets = useSafeAreaInsets();
|
|
17
|
-
const { selectedPlanId, setSelectedPlanId, isProcessing, handlePurchase, handleRestore, resetState } = usePaywallActions({
|
|
17
|
+
const { selectedPlanId, setSelectedPlanId, isProcessing, handlePurchase, handleRestore, resetState } = usePaywallActions({
|
|
18
|
+
packages,
|
|
19
|
+
onPurchase,
|
|
20
|
+
onRestore,
|
|
21
|
+
source,
|
|
22
|
+
onPurchaseSuccess,
|
|
23
|
+
onPurchaseError,
|
|
24
|
+
onAuthRequired,
|
|
25
|
+
onClose
|
|
26
|
+
});
|
|
18
27
|
|
|
19
28
|
useEffect(() => {
|
|
20
29
|
if (!visible) resetState();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ImageSourcePropType } from "react-native";
|
|
2
2
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
3
3
|
import type { SubscriptionFeature, PaywallTranslations, PaywallLegalUrls } from "../entities/types";
|
|
4
|
+
import type { PurchaseSource } from "../../subscription/core/SubscriptionConstants";
|
|
4
5
|
|
|
5
6
|
export interface TrialEligibilityInfo {
|
|
6
7
|
eligible: boolean;
|
|
@@ -22,4 +23,8 @@ export interface PaywallModalProps {
|
|
|
22
23
|
onRestore?: () => Promise<void | boolean>;
|
|
23
24
|
trialEligibility?: Record<string, TrialEligibilityInfo>;
|
|
24
25
|
trialSubtitleText?: string;
|
|
26
|
+
onPurchaseSuccess?: () => void;
|
|
27
|
+
onPurchaseError?: (error: Error | string) => void;
|
|
28
|
+
onAuthRequired?: () => void;
|
|
29
|
+
source?: PurchaseSource;
|
|
25
30
|
}
|
|
@@ -7,6 +7,8 @@ import type { PurchasesPackage } from "react-native-purchases";
|
|
|
7
7
|
import { usePurchaseLoadingStore } from "../../subscription/presentation/stores";
|
|
8
8
|
import type { PurchaseSource } from "../../subscription/core/SubscriptionConstants";
|
|
9
9
|
|
|
10
|
+
declare const __DEV__: boolean;
|
|
11
|
+
|
|
10
12
|
export interface UsePaywallActionsParams {
|
|
11
13
|
packages?: PurchasesPackage[];
|
|
12
14
|
onPurchase?: (pkg: PurchasesPackage) => Promise<void | boolean>;
|
|
@@ -52,49 +54,163 @@ export function usePaywallActions({
|
|
|
52
54
|
});
|
|
53
55
|
|
|
54
56
|
const handlePurchase = useCallback(async () => {
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
58
|
+
console.log("[usePaywallActions] handlePurchase called", {
|
|
59
|
+
selectedPlanId,
|
|
60
|
+
hasOnPurchase: !!onPurchaseRef.current,
|
|
61
|
+
isProcessing,
|
|
62
|
+
packagesCount: packages.length,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!selectedPlanId) {
|
|
67
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
68
|
+
console.warn("[usePaywallActions] ❌ No plan selected");
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!onPurchaseRef.current) {
|
|
74
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
75
|
+
console.error("[usePaywallActions] ❌ No onPurchase callback provided");
|
|
76
|
+
}
|
|
77
|
+
const err = new Error("Purchase handler not configured");
|
|
78
|
+
onPurchaseErrorRef.current?.(err);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (isProcessing) {
|
|
83
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
84
|
+
console.warn("[usePaywallActions] ⚠️ Already processing, ignoring duplicate request");
|
|
58
85
|
}
|
|
59
86
|
return;
|
|
60
87
|
}
|
|
61
88
|
|
|
89
|
+
const pkg = packages.find((p) => p.product.identifier === selectedPlanId);
|
|
90
|
+
|
|
91
|
+
if (!pkg) {
|
|
92
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
93
|
+
console.error("[usePaywallActions] ❌ Package not found", {
|
|
94
|
+
selectedPlanId,
|
|
95
|
+
availablePackages: packages.map(p => p.product.identifier),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const err = new Error(`Package not found: ${selectedPlanId}`);
|
|
99
|
+
onPurchaseErrorRef.current?.(err);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
104
|
+
console.log("[usePaywallActions] ✅ Starting purchase", {
|
|
105
|
+
productId: pkg.product.identifier,
|
|
106
|
+
title: pkg.product.title,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
62
110
|
setIsLocalProcessing(true);
|
|
63
111
|
startPurchase(selectedPlanId, "manual");
|
|
64
112
|
|
|
65
113
|
try {
|
|
66
|
-
|
|
114
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
115
|
+
console.log("[usePaywallActions] 🚀 Calling onPurchase callback");
|
|
116
|
+
}
|
|
67
117
|
|
|
68
|
-
|
|
69
|
-
const success = await onPurchaseRef.current(pkg);
|
|
118
|
+
const success = await onPurchaseRef.current(pkg);
|
|
70
119
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
120
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
121
|
+
console.log("[usePaywallActions] 📦 Purchase result:", { success, type: typeof success });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (success === true) {
|
|
125
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
126
|
+
console.log("[usePaywallActions] ✅ Purchase successful, calling success callbacks");
|
|
127
|
+
}
|
|
128
|
+
onPurchaseSuccessRef.current?.();
|
|
129
|
+
onCloseRef.current?.();
|
|
130
|
+
} else if (success === false) {
|
|
131
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
132
|
+
console.warn("[usePaywallActions] ⚠️ Purchase returned false (user cancelled or failed)");
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
136
|
+
console.error("[usePaywallActions] ❌ Purchase returned unexpected value:", success);
|
|
74
137
|
}
|
|
75
138
|
}
|
|
76
139
|
} catch (error) {
|
|
140
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
141
|
+
console.error("[usePaywallActions] ❌ Purchase error:", error);
|
|
142
|
+
}
|
|
77
143
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
78
144
|
onPurchaseErrorRef.current?.(err);
|
|
79
145
|
} finally {
|
|
146
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
147
|
+
console.log("[usePaywallActions] 🏁 Purchase completed, cleaning up");
|
|
148
|
+
}
|
|
80
149
|
setIsLocalProcessing(false);
|
|
81
150
|
endPurchase(selectedPlanId);
|
|
82
151
|
}
|
|
83
152
|
}, [selectedPlanId, packages, isProcessing, startPurchase, endPurchase]);
|
|
84
153
|
|
|
85
154
|
const handleRestore = useCallback(async () => {
|
|
86
|
-
if (
|
|
155
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
156
|
+
console.log("[usePaywallActions] handleRestore called", {
|
|
157
|
+
hasOnRestore: !!onRestoreRef.current,
|
|
158
|
+
isProcessing,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!onRestoreRef.current) {
|
|
163
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
164
|
+
console.error("[usePaywallActions] ❌ No onRestore callback provided");
|
|
165
|
+
}
|
|
166
|
+
const err = new Error("Restore handler not configured");
|
|
167
|
+
onPurchaseErrorRef.current?.(err);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (isProcessing) {
|
|
172
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
173
|
+
console.warn("[usePaywallActions] ⚠️ Already processing, ignoring restore request");
|
|
174
|
+
}
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
87
177
|
|
|
88
178
|
setIsLocalProcessing(true);
|
|
89
179
|
try {
|
|
180
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
181
|
+
console.log("[usePaywallActions] 🚀 Calling onRestore callback");
|
|
182
|
+
}
|
|
183
|
+
|
|
90
184
|
const success = await onRestoreRef.current();
|
|
91
|
-
|
|
185
|
+
|
|
186
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
187
|
+
console.log("[usePaywallActions] 📦 Restore result:", { success, type: typeof success });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (success === true) {
|
|
191
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
192
|
+
console.log("[usePaywallActions] ✅ Restore successful");
|
|
193
|
+
}
|
|
92
194
|
onPurchaseSuccessRef.current?.();
|
|
195
|
+
} else if (success === false) {
|
|
196
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
197
|
+
console.warn("[usePaywallActions] ⚠️ Restore returned false");
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
201
|
+
console.error("[usePaywallActions] ❌ Restore returned unexpected value:", success);
|
|
202
|
+
}
|
|
93
203
|
}
|
|
94
204
|
} catch (error) {
|
|
205
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
206
|
+
console.error("[usePaywallActions] ❌ Restore error:", error);
|
|
207
|
+
}
|
|
95
208
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
96
209
|
onPurchaseErrorRef.current?.(err);
|
|
97
210
|
} finally {
|
|
211
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
212
|
+
console.log("[usePaywallActions] 🏁 Restore completed");
|
|
213
|
+
}
|
|
98
214
|
setIsLocalProcessing(false);
|
|
99
215
|
}
|
|
100
216
|
}, [isProcessing]);
|
|
@@ -24,14 +24,7 @@ export class PackageHandler {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async purchase(pkg: PurchasesPackage, userId: string): Promise<boolean> {
|
|
27
|
-
console.log('🔵 [PackageHandler] purchase called', {
|
|
28
|
-
productId: pkg.product.identifier,
|
|
29
|
-
userId
|
|
30
|
-
});
|
|
31
|
-
|
|
32
27
|
const result = await executePurchase(this.service, pkg, userId);
|
|
33
|
-
console.log('✅ [PackageHandler] purchase completed', { result });
|
|
34
|
-
|
|
35
28
|
return result;
|
|
36
29
|
}
|
|
37
30
|
|
package/src/domains/subscription/infrastructure/handlers/package-operations/PackagePurchaser.ts
CHANGED
|
@@ -6,20 +6,10 @@ export async function executePurchase(
|
|
|
6
6
|
pkg: PurchasesPackage,
|
|
7
7
|
userId: string
|
|
8
8
|
): Promise<boolean> {
|
|
9
|
-
console.log('🔵 [executePurchase] Starting', {
|
|
10
|
-
productId: pkg.product.identifier,
|
|
11
|
-
userId,
|
|
12
|
-
isInitialized: service.isInitialized()
|
|
13
|
-
});
|
|
14
|
-
|
|
15
9
|
if (!service.isInitialized()) {
|
|
16
|
-
console.error('❌ [executePurchase] Service not initialized!');
|
|
17
10
|
throw new Error("Service not initialized");
|
|
18
11
|
}
|
|
19
12
|
|
|
20
|
-
console.log('🚀 [executePurchase] Calling service.purchasePackage');
|
|
21
13
|
const result = await service.purchasePackage(pkg, userId);
|
|
22
|
-
console.log('✅ [executePurchase] Completed', { success: result.success });
|
|
23
|
-
|
|
24
14
|
return result.success;
|
|
25
15
|
}
|
|
@@ -87,19 +87,9 @@ class SubscriptionManagerImpl {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
async purchasePackage(pkg: PurchasesPackage): Promise<boolean> {
|
|
90
|
-
console.log('🔵 [SubscriptionManager] purchasePackage called', {
|
|
91
|
-
productId: pkg.product.identifier,
|
|
92
|
-
isConfigured: !!this.managerConfig,
|
|
93
|
-
hasPackageHandler: !!this.packageHandler
|
|
94
|
-
});
|
|
95
|
-
|
|
96
90
|
this.ensureConfigured();
|
|
97
91
|
this.ensurePackageHandlerInitialized();
|
|
98
|
-
|
|
99
|
-
console.log('🚀 [SubscriptionManager] Calling purchasePackageOperation');
|
|
100
92
|
const result = await purchasePackageOperation(pkg, this.managerConfig, this.state, this.packageHandler!);
|
|
101
|
-
console.log('✅ [SubscriptionManager] purchasePackageOperation completed', { result });
|
|
102
|
-
|
|
103
93
|
return result;
|
|
104
94
|
}
|
|
105
95
|
|
|
@@ -22,17 +22,9 @@ export const purchasePackageOperation = async (
|
|
|
22
22
|
state: SubscriptionInternalState,
|
|
23
23
|
packageHandler: PackageHandler
|
|
24
24
|
): Promise<boolean> => {
|
|
25
|
-
console.log('🔵 [purchasePackageOperation] Starting', {
|
|
26
|
-
productId: pkg.product.identifier
|
|
27
|
-
});
|
|
28
|
-
|
|
29
25
|
ensureConfigured(managerConfig);
|
|
30
26
|
const userId = getCurrentUserIdOrThrow(state);
|
|
31
|
-
|
|
32
|
-
console.log('🚀 [purchasePackageOperation] Calling packageHandler.purchase', { userId });
|
|
33
27
|
const result = await packageHandler.purchase(pkg, userId);
|
|
34
|
-
console.log('✅ [purchasePackageOperation] Completed', { result });
|
|
35
|
-
|
|
36
28
|
return result;
|
|
37
29
|
};
|
|
38
30
|
|
|
@@ -16,38 +16,23 @@ export async function handlePurchase(
|
|
|
16
16
|
pkg: PurchasesPackage,
|
|
17
17
|
userId: string
|
|
18
18
|
): Promise<PurchaseResult> {
|
|
19
|
-
console.log('🔵 [PurchaseHandler] handlePurchase called', {
|
|
20
|
-
productId: pkg.product.identifier,
|
|
21
|
-
userId,
|
|
22
|
-
isInitialized: deps.isInitialized()
|
|
23
|
-
});
|
|
24
|
-
|
|
25
19
|
validatePurchaseReady(deps.isInitialized());
|
|
26
20
|
|
|
27
21
|
const consumableIds = deps.config.consumableProductIdentifiers || [];
|
|
28
22
|
const isConsumable = isConsumableProduct(pkg, consumableIds);
|
|
29
23
|
|
|
30
|
-
console.log('📦 [PurchaseHandler] Product type', { isConsumable });
|
|
31
|
-
|
|
32
24
|
try {
|
|
33
|
-
console.log('🚀 [PurchaseHandler] Calling executePurchase');
|
|
34
25
|
const result = await executePurchase(deps.config, userId, pkg, isConsumable);
|
|
35
|
-
console.log('✅ [PurchaseHandler] executePurchase completed', { success: result.success });
|
|
36
26
|
return result;
|
|
37
27
|
} catch (error) {
|
|
38
|
-
console.error('❌ [PurchaseHandler] Purchase failed', { error });
|
|
39
|
-
|
|
40
28
|
if (isUserCancelledError(error)) {
|
|
41
|
-
console.log('⚠️ [PurchaseHandler] User cancelled');
|
|
42
29
|
return { success: false, isPremium: false, productId: pkg.product.identifier };
|
|
43
30
|
}
|
|
44
31
|
|
|
45
32
|
if (isAlreadyPurchasedError(error)) {
|
|
46
|
-
console.log('⚠️ [PurchaseHandler] Already purchased');
|
|
47
33
|
return await handleAlreadyPurchasedError(deps, userId, pkg, error);
|
|
48
34
|
}
|
|
49
35
|
|
|
50
|
-
console.error('❌ [PurchaseHandler] Unhandled error');
|
|
51
36
|
return handlePurchaseError(error, pkg, userId);
|
|
52
37
|
}
|
|
53
38
|
}
|
|
@@ -60,15 +60,7 @@ export class RevenueCatService implements IRevenueCatService {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
async purchasePackage(pkg: PurchasesPackage, userId: string): Promise<PurchaseResult> {
|
|
63
|
-
console.log('🔵 [RevenueCatService] purchasePackage called', {
|
|
64
|
-
productId: pkg.product.identifier,
|
|
65
|
-
userId,
|
|
66
|
-
isInitialized: this.isInitialized()
|
|
67
|
-
});
|
|
68
|
-
|
|
69
63
|
const result = await handlePurchase(this.getSDKParams(), pkg, userId);
|
|
70
|
-
console.log('✅ [RevenueCatService] purchasePackage completed', { success: result.success });
|
|
71
|
-
|
|
72
64
|
return result;
|
|
73
65
|
}
|
|
74
66
|
|
|
@@ -77,26 +77,15 @@ export async function executePurchase(
|
|
|
77
77
|
pkg: PurchasesPackage,
|
|
78
78
|
isConsumable: boolean
|
|
79
79
|
): Promise<PurchaseResult> {
|
|
80
|
-
console.log('🔵 [PurchaseExecutor] executePurchase called', {
|
|
81
|
-
productId: pkg.product.identifier,
|
|
82
|
-
userId,
|
|
83
|
-
isConsumable,
|
|
84
|
-
packageType: pkg.packageType
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
console.log('🚀 [PurchaseExecutor] Calling Purchases.purchasePackage (RevenueCat SDK)');
|
|
88
80
|
const { customerInfo } = await Purchases.purchasePackage(pkg);
|
|
89
|
-
console.log('✅ [PurchaseExecutor] Purchases.purchasePackage completed');
|
|
90
81
|
|
|
91
82
|
const productId = pkg.product.identifier;
|
|
92
83
|
const packageType = pkg.packageType ?? null;
|
|
93
84
|
|
|
94
85
|
if (isConsumable) {
|
|
95
|
-
console.log('💰 [PurchaseExecutor] Processing as consumable purchase');
|
|
96
86
|
return executeConsumablePurchase(config, userId, productId, customerInfo, packageType);
|
|
97
87
|
}
|
|
98
88
|
|
|
99
|
-
console.log('📅 [PurchaseExecutor] Processing as subscription purchase');
|
|
100
89
|
return executeSubscriptionPurchase(
|
|
101
90
|
config,
|
|
102
91
|
userId,
|
|
@@ -9,6 +9,8 @@ import { usePremium } from "./usePremium";
|
|
|
9
9
|
import type { PurchaseSource } from "../core/SubscriptionConstants";
|
|
10
10
|
import { authPurchaseStateManager } from "../infrastructure/utils/authPurchaseState";
|
|
11
11
|
|
|
12
|
+
declare const __DEV__: boolean;
|
|
13
|
+
|
|
12
14
|
export type { PurchaseAuthProvider } from "../infrastructure/utils/authPurchaseState";
|
|
13
15
|
|
|
14
16
|
export const configureAuthProvider = (provider: import("../infrastructure/utils/authPurchaseState").PurchaseAuthProvider): void => {
|
|
@@ -44,38 +46,85 @@ export const useAuthAwarePurchase = (
|
|
|
44
46
|
|
|
45
47
|
const handlePurchase = useCallback(
|
|
46
48
|
async (pkg: PurchasesPackage, source?: PurchaseSource): Promise<boolean> => {
|
|
49
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
50
|
+
console.log("[useAuthAwarePurchase] handlePurchase called", {
|
|
51
|
+
productId: pkg.product.identifier,
|
|
52
|
+
source: source || params?.source,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
47
56
|
const authProvider = authPurchaseStateManager.getProvider();
|
|
48
57
|
|
|
49
58
|
if (!authProvider) {
|
|
59
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
60
|
+
console.error("[useAuthAwarePurchase] ❌ No auth provider configured");
|
|
61
|
+
}
|
|
50
62
|
return false;
|
|
51
63
|
}
|
|
52
64
|
|
|
53
65
|
const isAuth = authProvider.isAuthenticated();
|
|
54
66
|
|
|
67
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
68
|
+
console.log("[useAuthAwarePurchase] Auth status:", { isAuth });
|
|
69
|
+
}
|
|
70
|
+
|
|
55
71
|
if (!isAuth) {
|
|
72
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
73
|
+
console.log("[useAuthAwarePurchase] 🔐 User not authenticated, saving purchase and showing auth modal");
|
|
74
|
+
}
|
|
56
75
|
authPurchaseStateManager.savePurchase(pkg, source || params?.source || "settings");
|
|
57
76
|
authProvider.showAuthModal();
|
|
58
77
|
return false;
|
|
59
78
|
}
|
|
60
79
|
|
|
61
|
-
|
|
80
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
81
|
+
console.log("[useAuthAwarePurchase] ✅ User authenticated, proceeding with purchase");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const result = await purchasePackage(pkg);
|
|
85
|
+
|
|
86
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
87
|
+
console.log("[useAuthAwarePurchase] Purchase result:", result);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return result;
|
|
62
91
|
},
|
|
63
92
|
[purchasePackage, params?.source]
|
|
64
93
|
);
|
|
65
94
|
|
|
66
95
|
const handleRestore = useCallback(async (): Promise<boolean> => {
|
|
96
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
97
|
+
console.log("[useAuthAwarePurchase] handleRestore called");
|
|
98
|
+
}
|
|
99
|
+
|
|
67
100
|
const authProvider = authPurchaseStateManager.getProvider();
|
|
68
101
|
|
|
69
102
|
if (!authProvider) {
|
|
103
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
104
|
+
console.error("[useAuthAwarePurchase] ❌ No auth provider configured");
|
|
105
|
+
}
|
|
70
106
|
return false;
|
|
71
107
|
}
|
|
72
108
|
|
|
73
109
|
if (!authProvider.isAuthenticated()) {
|
|
110
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
111
|
+
console.log("[useAuthAwarePurchase] 🔐 User not authenticated, showing auth modal");
|
|
112
|
+
}
|
|
74
113
|
authProvider.showAuthModal();
|
|
75
114
|
return false;
|
|
76
115
|
}
|
|
77
116
|
|
|
78
|
-
|
|
117
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
118
|
+
console.log("[useAuthAwarePurchase] ✅ User authenticated, proceeding with restore");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const result = await restorePurchase();
|
|
122
|
+
|
|
123
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
124
|
+
console.log("[useAuthAwarePurchase] Restore result:", result);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return result;
|
|
79
128
|
}, [restorePurchase]);
|
|
80
129
|
|
|
81
130
|
const executeSavedPurchase = useCallback(async (): Promise<boolean> => {
|