@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-subscription",
3
- "version": "2.27.138",
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
- queryClient.invalidateQueries({ queryKey: creditsQueryKeys.user(userId) });
81
+ queryClientRef.current.invalidateQueries({ queryKey: creditsQueryKeys.user(userId) });
77
82
  }
78
83
  });
79
84
 
80
85
  return unsubscribe;
81
- }, [userId, queryClient]);
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
- Purchases.removeCustomerInfoUpdateListener(listener);
98
+ if (listenerRef.current) {
99
+ Purchases.removeCustomerInfoUpdateListener(listenerRef.current);
100
+ }
99
101
  };
100
102
  }, [fetchCustomerInfo]);
101
103
 
@@ -66,6 +66,7 @@ export const PremiumDetailsCard: React.FC<PremiumDetailsCardProps> = ({
66
66
  highlight={
67
67
  daysRemaining !== null &&
68
68
  daysRemaining !== undefined &&
69
+ daysRemaining > 0 &&
69
70
  daysRemaining <= 7
70
71
  }
71
72
  />
@@ -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 = subscriptionActive && credits !== null && !credits.isPremium;
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: !!userId && SubscriptionManager.isInitializedForUser(userId),
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
  }