@umituz/react-native-subscription 2.27.138 → 2.27.139
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/credits/presentation/useCredits.ts +9 -4
- package/src/domains/subscription/infrastructure/hooks/useCustomerInfo.ts +7 -5
- package/src/domains/subscription/presentation/components/details/PremiumDetailsCard.tsx +1 -0
- package/src/domains/subscription/presentation/usePremium.ts +7 -2
- package/src/domains/subscription/presentation/useSubscriptionStatus.ts +4 -2
- package/src/shared/utils/numberUtils.core.ts +2 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.27.
|
|
3
|
+
"version": "2.27.139",
|
|
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,5 +1,5 @@
|
|
|
1
1
|
import { useQuery, useQueryClient } from "@umituz/react-native-design-system";
|
|
2
|
-
import { useCallback, useMemo, useEffect } from "react";
|
|
2
|
+
import { useCallback, useMemo, useEffect, useRef } from "react";
|
|
3
3
|
import { useAuthStore, selectUserId } from "@umituz/react-native-auth";
|
|
4
4
|
import { subscriptionEventBus, SUBSCRIPTION_EVENTS } from "../../../shared/infrastructure/SubscriptionEventBus";
|
|
5
5
|
import type { UserCredits } from "../core/Credits";
|
|
@@ -47,7 +47,7 @@ export const useCredits = (): UseCreditsResult => {
|
|
|
47
47
|
const queryEnabled = !!userId && isConfigured;
|
|
48
48
|
|
|
49
49
|
const { data, status, error, refetch } = useQuery({
|
|
50
|
-
queryKey: creditsQueryKeys.user(userId
|
|
50
|
+
queryKey: userId ? creditsQueryKeys.user(userId) : creditsQueryKeys.all,
|
|
51
51
|
queryFn: async () => {
|
|
52
52
|
if (!userId || !isConfigured) return null;
|
|
53
53
|
|
|
@@ -67,18 +67,23 @@ export const useCredits = (): UseCreditsResult => {
|
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
const queryClient = useQueryClient();
|
|
70
|
+
const queryClientRef = useRef(queryClient);
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
queryClientRef.current = queryClient;
|
|
74
|
+
}, [queryClient]);
|
|
70
75
|
|
|
71
76
|
useEffect(() => {
|
|
72
77
|
if (!userId) return;
|
|
73
78
|
|
|
74
79
|
const unsubscribe = subscriptionEventBus.on(SUBSCRIPTION_EVENTS.CREDITS_UPDATED, (updatedUserId) => {
|
|
75
80
|
if (updatedUserId === userId) {
|
|
76
|
-
|
|
81
|
+
queryClientRef.current.invalidateQueries({ queryKey: creditsQueryKeys.user(userId) });
|
|
77
82
|
}
|
|
78
83
|
});
|
|
79
84
|
|
|
80
85
|
return unsubscribe;
|
|
81
|
-
}, [userId
|
|
86
|
+
}, [userId]);
|
|
82
87
|
|
|
83
88
|
const credits = data ?? null;
|
|
84
89
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* @see https://www.revenuecat.com/docs/customers/customer-info
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { useEffect, useState, useCallback } from "react";
|
|
17
|
+
import { useEffect, useState, useCallback, useRef } from "react";
|
|
18
18
|
import Purchases, { type CustomerInfo } from "react-native-purchases";
|
|
19
19
|
|
|
20
20
|
export interface UseCustomerInfoResult {
|
|
@@ -81,21 +81,23 @@ export function useCustomerInfo(): UseCustomerInfoResult {
|
|
|
81
81
|
}
|
|
82
82
|
}, []);
|
|
83
83
|
|
|
84
|
+
const listenerRef = useRef<((info: CustomerInfo) => void) | null>(null);
|
|
85
|
+
|
|
84
86
|
useEffect(() => {
|
|
85
|
-
// Initial fetch
|
|
86
87
|
fetchCustomerInfo();
|
|
87
88
|
|
|
88
|
-
// Listen for real-time updates (renewals, purchases, restore)
|
|
89
89
|
const listener = (info: CustomerInfo) => {
|
|
90
90
|
setCustomerInfo(info);
|
|
91
91
|
setError(null);
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
+
listenerRef.current = listener;
|
|
94
95
|
Purchases.addCustomerInfoUpdateListener(listener);
|
|
95
96
|
|
|
96
|
-
// Cleanup listener on unmount
|
|
97
97
|
return () => {
|
|
98
|
-
|
|
98
|
+
if (listenerRef.current) {
|
|
99
|
+
Purchases.removeCustomerInfoUpdateListener(listenerRef.current);
|
|
100
|
+
}
|
|
99
101
|
};
|
|
100
102
|
}, [fetchCustomerInfo]);
|
|
101
103
|
|
|
@@ -22,9 +22,14 @@ export const usePremium = (): UsePremiumResult => {
|
|
|
22
22
|
const restoreMutation = useRestorePurchase();
|
|
23
23
|
|
|
24
24
|
const { showPaywall, setShowPaywall, closePaywall, openPaywall } = usePaywallVisibility();
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
const isPremium = subscriptionActive || (credits?.isPremium ?? false);
|
|
27
|
-
const isSyncing =
|
|
27
|
+
const isSyncing =
|
|
28
|
+
!statusLoading &&
|
|
29
|
+
!creditsLoading &&
|
|
30
|
+
subscriptionActive &&
|
|
31
|
+
credits !== null &&
|
|
32
|
+
!credits.isPremium;
|
|
28
33
|
|
|
29
34
|
const handlePurchase = useCallback(
|
|
30
35
|
async (pkg: PurchasesPackage): Promise<boolean> => {
|
|
@@ -14,8 +14,10 @@ export const useSubscriptionStatus = (): SubscriptionStatusResult => {
|
|
|
14
14
|
const userId = useAuthStore(selectUserId);
|
|
15
15
|
const queryClient = useQueryClient();
|
|
16
16
|
|
|
17
|
+
const queryEnabled = !!userId && SubscriptionManager.isInitializedForUser(userId);
|
|
18
|
+
|
|
17
19
|
const { data, status, error, refetch } = useQuery({
|
|
18
|
-
queryKey: subscriptionStatusQueryKeys.user(userId
|
|
20
|
+
queryKey: userId ? subscriptionStatusQueryKeys.user(userId) : subscriptionStatusQueryKeys.all,
|
|
19
21
|
queryFn: async () => {
|
|
20
22
|
if (!userId) {
|
|
21
23
|
return { isPremium: false, expirationDate: null };
|
|
@@ -28,7 +30,7 @@ export const useSubscriptionStatus = (): SubscriptionStatusResult => {
|
|
|
28
30
|
return { isPremium: false, expirationDate: null };
|
|
29
31
|
}
|
|
30
32
|
},
|
|
31
|
-
enabled:
|
|
33
|
+
enabled: queryEnabled,
|
|
32
34
|
});
|
|
33
35
|
|
|
34
36
|
useEffect(() => {
|
|
@@ -59,7 +59,7 @@ export function calculateRemaining(current: number, cost: number): number {
|
|
|
59
59
|
* Check if user can afford a cost
|
|
60
60
|
*/
|
|
61
61
|
export function canAfford(balance: number | null | undefined, cost: number): boolean {
|
|
62
|
-
if (balance === null || balance === undefined) return false;
|
|
62
|
+
if (balance === null || balance === undefined || cost < 0) return false;
|
|
63
63
|
return balance >= cost;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -67,7 +67,6 @@ export function canAfford(balance: number | null | undefined, cost: number): boo
|
|
|
67
67
|
* Calculate credit percentage for UI display
|
|
68
68
|
*/
|
|
69
69
|
export function calculateCreditPercentage(current: number | null | undefined, max: number): number {
|
|
70
|
-
if (current === null || current === undefined) return 0;
|
|
71
|
-
if (max <= 0) return 100;
|
|
70
|
+
if (current === null || current === undefined || max <= 0) return 0;
|
|
72
71
|
return calculatePercentageClamped(current, max);
|
|
73
72
|
}
|