@umituz/react-native-subscription 2.13.11 → 2.13.13

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.13.11",
3
+ "version": "2.13.13",
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",
@@ -7,6 +7,8 @@
7
7
 
8
8
  import { useQuery } from "@tanstack/react-query";
9
9
  import type { UserCredits, CreditType } from "../../domain/entities/Credits";
10
+
11
+ declare const __DEV__: boolean;
10
12
  import {
11
13
  getCreditsRepository,
12
14
  getCreditsConfig,
@@ -64,6 +66,18 @@ export const useCredits = ({
64
66
  const hasTextCredits = (credits?.textCredits ?? 0) > 0;
65
67
  const hasImageCredits = (credits?.imageCredits ?? 0) > 0;
66
68
 
69
+ if (__DEV__) {
70
+ console.log("[useCredits] State", {
71
+ userId,
72
+ enabled,
73
+ isLoading,
74
+ imageCredits: credits?.imageCredits ?? 0,
75
+ textCredits: credits?.textCredits ?? 0,
76
+ hasImageCredits,
77
+ hasTextCredits,
78
+ });
79
+ }
80
+
67
81
  const textCreditsPercent = credits
68
82
  ? Math.round((credits.textCredits / config.textCreditLimit) * 100)
69
83
  : 0;
@@ -2,12 +2,12 @@
2
2
  * useFeatureGate Hook
3
3
  *
4
4
  * Feature gating with TanStack Query for server state.
5
- * Checks auth and premium status before allowing actions.
5
+ * Checks auth, premium status, AND credit balance before allowing actions.
6
6
  *
7
7
  * Flow:
8
8
  * 1. NOT authenticated → onShowAuthModal(callback)
9
- * 2. Authenticated but not premium → onShowPaywall()
10
- * 3. Authenticated and premium → Execute action
9
+ * 2. Authenticated but no credits → onShowPaywall()
10
+ * 3. Authenticated with credits → Execute action
11
11
  *
12
12
  * @example
13
13
  * ```typescript
@@ -16,6 +16,7 @@
16
16
  * isAuthenticated: !!user,
17
17
  * onShowAuthModal: (cb) => authModal.show(cb),
18
18
  * onShowPaywall: () => setShowPaywall(true),
19
+ * creditType: 'image', // or 'text'
19
20
  * });
20
21
  *
21
22
  * // Gate a premium feature
@@ -27,6 +28,7 @@
27
28
 
28
29
  import { useCallback } from "react";
29
30
  import { useCredits } from "./useCredits";
31
+ import type { CreditType } from "../../domain/entities/Credits";
30
32
 
31
33
  declare const __DEV__: boolean;
32
34
 
@@ -39,67 +41,118 @@ export interface UseFeatureGateParams {
39
41
  onShowAuthModal: (pendingCallback: () => void | Promise<void>) => void;
40
42
  /** Callback to show paywall */
41
43
  onShowPaywall: () => void;
44
+ /** Credit type to check (default: 'image') */
45
+ creditType?: CreditType;
42
46
  }
43
47
 
44
48
  export interface UseFeatureGateResult {
45
- /** Gate a feature - checks auth first, then premium (credits) */
49
+ /** Gate a feature - checks auth first, then credits balance */
46
50
  requireFeature: (action: () => void | Promise<void>) => void;
47
51
  /** Whether user is authenticated */
48
52
  isAuthenticated: boolean;
49
- /** Whether user has premium access (has credits) */
50
- isPremium: boolean;
53
+ /** Whether user has credits remaining */
54
+ hasCredits: boolean;
51
55
  /** Whether feature access is allowed */
52
56
  canAccess: boolean;
53
57
  /** Loading state */
54
58
  isLoading: boolean;
59
+ /** Current credit balance for the specified type */
60
+ creditBalance: number;
55
61
  }
56
62
 
57
63
  export function useFeatureGate(
58
64
  params: UseFeatureGateParams
59
65
  ): UseFeatureGateResult {
60
- const { userId, isAuthenticated, onShowAuthModal, onShowPaywall } = params;
66
+ const {
67
+ userId,
68
+ isAuthenticated,
69
+ onShowAuthModal,
70
+ onShowPaywall,
71
+ creditType = "image",
72
+ } = params;
61
73
 
62
74
  // Use TanStack Query to get credits (server state)
63
- const { credits, isLoading } = useCredits({
75
+ const { credits, isLoading, hasImageCredits, hasTextCredits } = useCredits({
64
76
  userId,
65
77
  enabled: isAuthenticated && !!userId,
66
78
  });
67
79
 
68
- // User is premium if they have credits
69
- // NOTE: This assumes credits system = premium subscription
70
- // If your app uses CustomerInfo for premium status, use useCustomerInfo() instead
71
- const isPremium = credits !== null;
80
+ // Check actual credit balance, not just existence
81
+ const hasCredits = creditType === "image" ? hasImageCredits : hasTextCredits;
82
+ const creditBalance =
83
+ creditType === "image"
84
+ ? credits?.imageCredits ?? 0
85
+ : credits?.textCredits ?? 0;
86
+
87
+ if (__DEV__) {
88
+ console.log("[useFeatureGate] Hook state", {
89
+ userId,
90
+ isAuthenticated,
91
+ creditType,
92
+ hasCredits,
93
+ creditBalance,
94
+ isLoading,
95
+ });
96
+ }
72
97
 
73
98
  const requireFeature = useCallback(
74
99
  (action: () => void | Promise<void>) => {
100
+ if (__DEV__) {
101
+ console.log("[useFeatureGate] requireFeature called", {
102
+ isAuthenticated,
103
+ hasCredits,
104
+ creditBalance,
105
+ creditType,
106
+ });
107
+ }
108
+
75
109
  // Step 1: Check authentication
76
110
  if (!isAuthenticated) {
111
+ if (__DEV__) {
112
+ console.log("[useFeatureGate] Not authenticated, showing auth modal");
113
+ }
77
114
  onShowAuthModal(() => {
78
115
  // We NO LONGER call action() blindly here.
79
116
  // The component will re-render with the new auth state,
80
117
  // and the user should be allowed to try the action again.
81
- // This avoids executing actions before credits are loaded or verified.
82
118
  });
83
119
  return;
84
120
  }
85
121
 
86
- // Step 2: Check premium (has credits from TanStack Query)
87
- if (!isPremium) {
122
+ // Step 2: Check credit balance (not just existence)
123
+ if (!hasCredits) {
124
+ if (__DEV__) {
125
+ console.log("[useFeatureGate] No credits, showing paywall", {
126
+ creditBalance,
127
+ creditType,
128
+ });
129
+ }
88
130
  onShowPaywall();
89
131
  return;
90
132
  }
91
133
 
92
- // Step 3: User is authenticated and premium - execute action
134
+ // Step 3: User is authenticated with credits - execute action
135
+ if (__DEV__) {
136
+ console.log("[useFeatureGate] Access granted, executing action");
137
+ }
93
138
  action();
94
139
  },
95
- [isAuthenticated, isPremium, onShowAuthModal, onShowPaywall]
140
+ [
141
+ isAuthenticated,
142
+ hasCredits,
143
+ creditBalance,
144
+ creditType,
145
+ onShowAuthModal,
146
+ onShowPaywall,
147
+ ]
96
148
  );
97
149
 
98
150
  return {
99
151
  requireFeature,
100
152
  isAuthenticated,
101
- isPremium,
102
- canAccess: isAuthenticated && isPremium,
153
+ hasCredits,
154
+ canAccess: isAuthenticated && hasCredits,
103
155
  isLoading,
156
+ creditBalance,
104
157
  };
105
158
  }