@umituz/react-native-subscription 2.26.15 → 2.26.17
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.26.
|
|
3
|
+
"version": "2.26.17",
|
|
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,3 +1,4 @@
|
|
|
1
|
+
export * from "./useAuthAwarePurchase";
|
|
1
2
|
export * from "./useAuthSubscriptionSync";
|
|
2
3
|
export * from "./useSavedPurchaseAutoExecution";
|
|
3
4
|
export * from "./useCredits";
|
|
@@ -6,5 +7,6 @@ export * from "./useFeatureGate";
|
|
|
6
7
|
export * from "./usePaywallVisibility";
|
|
7
8
|
export * from "./usePremium";
|
|
8
9
|
export * from "./useSubscriptionSettingsConfig";
|
|
10
|
+
export * from "./useSubscriptionStatus";
|
|
9
11
|
export * from "./feedback/usePaywallFeedback";
|
|
10
12
|
export * from "./feedback/useFeedbackSubmit";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth-Aware Purchase Hook
|
|
3
|
+
* Handles purchase flow with authentication requirement
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useCallback } from "react";
|
|
7
|
+
import type { PurchasesPackage } from "react-native-purchases";
|
|
8
|
+
import { usePremium } from "./usePremium";
|
|
9
|
+
import type { PurchaseSource } from "../../domain/entities/Credits";
|
|
10
|
+
|
|
11
|
+
declare const __DEV__: boolean;
|
|
12
|
+
|
|
13
|
+
export interface PurchaseAuthProvider {
|
|
14
|
+
isAuthenticated: () => boolean;
|
|
15
|
+
showAuthModal: () => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let globalAuthProvider: PurchaseAuthProvider | null = null;
|
|
19
|
+
let savedPackage: PurchasesPackage | null = null;
|
|
20
|
+
let savedSource: PurchaseSource | null = null;
|
|
21
|
+
|
|
22
|
+
export const configureAuthProvider = (provider: PurchaseAuthProvider): void => {
|
|
23
|
+
globalAuthProvider = provider;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const getSavedPurchase = (): { pkg: PurchasesPackage; source: PurchaseSource } | null => {
|
|
27
|
+
if (savedPackage && savedSource) {
|
|
28
|
+
return { pkg: savedPackage, source: savedSource };
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const clearSavedPurchase = (): void => {
|
|
34
|
+
savedPackage = null;
|
|
35
|
+
savedSource = null;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export interface UseAuthAwarePurchaseParams {
|
|
39
|
+
source?: PurchaseSource;
|
|
40
|
+
userId?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface UseAuthAwarePurchaseResult {
|
|
44
|
+
handlePurchase: (pkg: PurchasesPackage, source?: PurchaseSource) => Promise<boolean>;
|
|
45
|
+
handleRestore: () => Promise<boolean>;
|
|
46
|
+
executeSavedPurchase: () => Promise<boolean>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const useAuthAwarePurchase = (
|
|
50
|
+
params?: UseAuthAwarePurchaseParams
|
|
51
|
+
): UseAuthAwarePurchaseResult => {
|
|
52
|
+
const { purchasePackage, restorePurchase } = usePremium(params?.userId);
|
|
53
|
+
|
|
54
|
+
const handlePurchase = useCallback(
|
|
55
|
+
async (pkg: PurchasesPackage, source?: PurchaseSource): Promise<boolean> => {
|
|
56
|
+
if (__DEV__) {
|
|
57
|
+
console.log("[useAuthAwarePurchase] handlePurchase called:", {
|
|
58
|
+
productId: pkg.product.identifier,
|
|
59
|
+
hasAuthProvider: !!globalAuthProvider,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!globalAuthProvider) {
|
|
64
|
+
if (__DEV__) {
|
|
65
|
+
console.error("[useAuthAwarePurchase] Auth provider not configured");
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const isAuth = globalAuthProvider.isAuthenticated();
|
|
71
|
+
if (__DEV__) {
|
|
72
|
+
console.log("[useAuthAwarePurchase] Auth check:", { isAuthenticated: isAuth });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!isAuth) {
|
|
76
|
+
if (__DEV__) {
|
|
77
|
+
console.log("[useAuthAwarePurchase] Not authenticated, saving and showing auth");
|
|
78
|
+
}
|
|
79
|
+
savedPackage = pkg;
|
|
80
|
+
savedSource = source || params?.source || "settings";
|
|
81
|
+
globalAuthProvider.showAuthModal();
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (__DEV__) {
|
|
86
|
+
console.log("[useAuthAwarePurchase] Calling purchasePackage");
|
|
87
|
+
}
|
|
88
|
+
const result = await purchasePackage(pkg);
|
|
89
|
+
if (__DEV__) {
|
|
90
|
+
console.log("[useAuthAwarePurchase] purchasePackage returned:", result);
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
},
|
|
94
|
+
[purchasePackage, params?.source]
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const handleRestore = useCallback(async (): Promise<boolean> => {
|
|
98
|
+
if (!globalAuthProvider) {
|
|
99
|
+
if (__DEV__) {
|
|
100
|
+
console.error("[useAuthAwarePurchase] Auth provider not configured");
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!globalAuthProvider.isAuthenticated()) {
|
|
106
|
+
if (__DEV__) {
|
|
107
|
+
console.log("[useAuthAwarePurchase] Not authenticated for restore");
|
|
108
|
+
}
|
|
109
|
+
globalAuthProvider.showAuthModal();
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return restorePurchase();
|
|
114
|
+
}, [restorePurchase]);
|
|
115
|
+
|
|
116
|
+
const executeSavedPurchase = useCallback(async (): Promise<boolean> => {
|
|
117
|
+
const saved = getSavedPurchase();
|
|
118
|
+
if (!saved) {
|
|
119
|
+
if (__DEV__) {
|
|
120
|
+
console.log("[useAuthAwarePurchase] No saved purchase to execute");
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (__DEV__) {
|
|
126
|
+
console.log("[useAuthAwarePurchase] Executing saved purchase:", saved.pkg.product.identifier);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
clearSavedPurchase();
|
|
130
|
+
return purchasePackage(saved.pkg);
|
|
131
|
+
}, [purchasePackage]);
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
handlePurchase,
|
|
135
|
+
handleRestore,
|
|
136
|
+
executeSavedPurchase,
|
|
137
|
+
};
|
|
138
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useSubscriptionStatus Hook
|
|
3
|
+
*
|
|
4
|
+
* TanStack Query hook for checking real subscription status from RevenueCat.
|
|
5
|
+
* This provides the actual premium status based on entitlements, not credits.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useQuery } from "@umituz/react-native-design-system";
|
|
9
|
+
import { SubscriptionManager } from "../../revenuecat/infrastructure/managers/SubscriptionManager";
|
|
10
|
+
|
|
11
|
+
export const subscriptionStatusQueryKeys = {
|
|
12
|
+
all: ["subscriptionStatus"] as const,
|
|
13
|
+
user: (userId: string) => ["subscriptionStatus", userId] as const,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export interface SubscriptionStatusResult {
|
|
17
|
+
isPremium: boolean;
|
|
18
|
+
expirationDate: Date | null;
|
|
19
|
+
isLoading: boolean;
|
|
20
|
+
error: Error | null;
|
|
21
|
+
refetch: () => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface UseSubscriptionStatusParams {
|
|
25
|
+
userId: string | undefined;
|
|
26
|
+
enabled?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check real subscription status from RevenueCat
|
|
31
|
+
*
|
|
32
|
+
* @param userId - User ID
|
|
33
|
+
* @param enabled - Whether to enable the query
|
|
34
|
+
* @returns Subscription status with isPremium flag
|
|
35
|
+
*/
|
|
36
|
+
export const useSubscriptionStatus = ({
|
|
37
|
+
userId,
|
|
38
|
+
enabled = true,
|
|
39
|
+
}: UseSubscriptionStatusParams): SubscriptionStatusResult => {
|
|
40
|
+
const { data, isLoading, error, refetch } = useQuery({
|
|
41
|
+
queryKey: subscriptionStatusQueryKeys.user(userId ?? ""),
|
|
42
|
+
queryFn: async () => {
|
|
43
|
+
if (!userId) {
|
|
44
|
+
return { isPremium: false, expirationDate: null };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return SubscriptionManager.checkPremiumStatus();
|
|
48
|
+
},
|
|
49
|
+
enabled: enabled && !!userId && SubscriptionManager.isInitializedForUser(userId),
|
|
50
|
+
staleTime: 0, // No cache - always fetch fresh premium status
|
|
51
|
+
gcTime: 0, // Don't cache - garbage collect immediately
|
|
52
|
+
refetchOnMount: true,
|
|
53
|
+
refetchOnWindowFocus: true,
|
|
54
|
+
refetchOnReconnect: true,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
isPremium: data?.isPremium ?? false,
|
|
59
|
+
expirationDate: data?.expirationDate ?? null,
|
|
60
|
+
isLoading,
|
|
61
|
+
error: error as Error | null,
|
|
62
|
+
refetch,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
@@ -97,7 +97,7 @@ export function useRevenueCatTrialEligibility(): UseRevenueCatTrialEligibilityRe
|
|
|
97
97
|
|
|
98
98
|
try {
|
|
99
99
|
const eligibilities: Record<string, IntroEligibility> =
|
|
100
|
-
await Purchases.
|
|
100
|
+
await Purchases.checkTrialOrIntroductoryPriceEligibility(productIds);
|
|
101
101
|
|
|
102
102
|
const newMap: TrialEligibilityMap = {};
|
|
103
103
|
|