@umituz/react-native-subscription 2.15.3 → 2.15.4
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/presentation/hooks/useSubscriptionSettingsConfig.ts +6 -2
- package/src/revenuecat/infrastructure/utils/ExpirationDateCalculator.ts +43 -12
- package/src/domains/README.md.bak +0 -274
- package/src/domains/wallet/README.md.bak +0 -209
- package/src/presentation/README.md.bak +0 -172
- package/src/presentation/components/README.md.bak +0 -217
- package/src/presentation/hooks/useCredits.md.bak +0 -231
- package/src/presentation/hooks/useFeatureGate.md.bak +0 -284
|
@@ -1,284 +0,0 @@
|
|
|
1
|
-
# useFeatureGate Hook
|
|
2
|
-
|
|
3
|
-
Unified feature gate combining authentication, subscription, and credits checks.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
**Import Path**: `@umituz/react-native-subscription`
|
|
8
|
-
|
|
9
|
-
**File**: `src/presentation/hooks/useFeatureGate.ts`
|
|
10
|
-
|
|
11
|
-
**Type**: Hook
|
|
12
|
-
|
|
13
|
-
## Strategy
|
|
14
|
-
|
|
15
|
-
### Progressive Access Control
|
|
16
|
-
|
|
17
|
-
1. **Authentication Check**
|
|
18
|
-
- Verify user is authenticated
|
|
19
|
-
- Show auth modal if not authenticated
|
|
20
|
-
- Queue pending action for post-auth execution
|
|
21
|
-
|
|
22
|
-
2. **Subscription Check**
|
|
23
|
-
- Verify user has required subscription tier
|
|
24
|
-
- Show paywall if subscription insufficient
|
|
25
|
-
- Bypass credit check for premium users
|
|
26
|
-
|
|
27
|
-
3. **Credit Check**
|
|
28
|
-
- Verify sufficient credit balance
|
|
29
|
-
- Show purchase prompt if insufficient
|
|
30
|
-
- Deduct credits only after all checks pass
|
|
31
|
-
|
|
32
|
-
4. **Action Execution**
|
|
33
|
-
- Execute gated action only if all checks pass
|
|
34
|
-
- Handle failures gracefully
|
|
35
|
-
- Update UI state appropriately
|
|
36
|
-
|
|
37
|
-
### Integration Points
|
|
38
|
-
|
|
39
|
-
- **useAuth**: For authentication state
|
|
40
|
-
- **usePremium**: For subscription status
|
|
41
|
-
- **useCredits**: For credit balance
|
|
42
|
-
- **useDeductCredit**: For credit deduction
|
|
43
|
-
- **Auth Modals**: Custom authentication UI
|
|
44
|
-
- **Paywall Components**: Upgrade prompts
|
|
45
|
-
|
|
46
|
-
## Restrictions
|
|
47
|
-
|
|
48
|
-
### REQUIRED
|
|
49
|
-
|
|
50
|
-
- **Authentication Check**: MUST implement `onShowAuthModal` callback
|
|
51
|
-
- **Paywall Handler**: MUST implement `onShowPaywall` callback
|
|
52
|
-
- **Credit Validation**: MUST check `hasCredits` before allowing actions
|
|
53
|
-
- **State Management**: MUST respect `canAccess` boolean
|
|
54
|
-
|
|
55
|
-
### PROHIBITED
|
|
56
|
-
|
|
57
|
-
- **NEVER** bypass authentication check for sensitive features
|
|
58
|
-
- **NEVER** show feature gate if user has access (confusing UX)
|
|
59
|
-
- **NEVER** execute action without checking all gates first
|
|
60
|
-
- **DO NOT** hardcode gate logic (use hook parameters)
|
|
61
|
-
- **NEVER** deduct credits without checking subscription status first
|
|
62
|
-
|
|
63
|
-
### CRITICAL SAFETY
|
|
64
|
-
|
|
65
|
-
- **ALWAYS** check gates in order: Auth → Subscription → Credits
|
|
66
|
-
- **ALWAYS** provide clear messaging about why access is denied
|
|
67
|
-
- **ALWAYS** preserve user intent through auth/purchase flows
|
|
68
|
-
- **NEVER** trust client-side gate for security (server-side validation required)
|
|
69
|
-
- **MUST** implement proper error boundaries around gated actions
|
|
70
|
-
|
|
71
|
-
## Rules
|
|
72
|
-
|
|
73
|
-
### Basic Feature Gating
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
// CORRECT - All gates with clear messaging
|
|
77
|
-
function PremiumFeature() {
|
|
78
|
-
const { requireFeature, canAccess, isAuthenticated, hasSubscription, hasCredits } =
|
|
79
|
-
useFeatureGate({
|
|
80
|
-
isAuthenticated: !!user,
|
|
81
|
-
onShowAuthModal: (pendingAction) => {
|
|
82
|
-
navigation.navigate('Auth', { pendingAction });
|
|
83
|
-
},
|
|
84
|
-
hasSubscription: isPremium,
|
|
85
|
-
hasCredits: credits >= 5,
|
|
86
|
-
creditBalance: credits,
|
|
87
|
-
requiredCredits: 5,
|
|
88
|
-
onShowPaywall: (required) => {
|
|
89
|
-
if (!isAuthenticated) return;
|
|
90
|
-
if (!hasSubscription) showPaywall();
|
|
91
|
-
else showCreditPurchase(required);
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const handleAction = () => {
|
|
96
|
-
requireFeature(async () => {
|
|
97
|
-
await executeFeature();
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
return (
|
|
102
|
-
<Button
|
|
103
|
-
onPress={handleAction}
|
|
104
|
-
title={!canAccess ? 'Unlock Feature' : 'Execute'}
|
|
105
|
-
/>
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// INCORRECT - Missing auth callback
|
|
110
|
-
const { requireFeature } = useFeatureGate({
|
|
111
|
-
isAuthenticated: !!user,
|
|
112
|
-
// Missing onShowAuthModal
|
|
113
|
-
hasSubscription: isPremium,
|
|
114
|
-
hasCredits: credits >= 5,
|
|
115
|
-
creditBalance: credits,
|
|
116
|
-
onShowPaywall: showPaywall,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// INCORRECT - No access check
|
|
120
|
-
const handleAction = () => {
|
|
121
|
-
requireFeature(() => executeFeature());
|
|
122
|
-
};
|
|
123
|
-
// Always shows button, even if user can't access
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### Progressive Access Control
|
|
127
|
-
|
|
128
|
-
```typescript
|
|
129
|
-
// CORRECT - Show appropriate message for each gate
|
|
130
|
-
function ProgressiveGate() {
|
|
131
|
-
const { canAccess, isAuthenticated, hasSubscription, hasCredits } = useFeatureGate({
|
|
132
|
-
isAuthenticated: !!user,
|
|
133
|
-
onShowAuthModal: (pending) => showAuthModal({ pendingAction: pending }),
|
|
134
|
-
hasSubscription: isPremium,
|
|
135
|
-
hasCredits: credits >= 3,
|
|
136
|
-
creditBalance: credits,
|
|
137
|
-
requiredCredits: 3,
|
|
138
|
-
onShowPaywall: (required) => showUpgradeModal({ requiredCredits: required }),
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
const getAccessMessage = () => {
|
|
142
|
-
if (!isAuthenticated) return 'Sign in to access';
|
|
143
|
-
if (!hasSubscription && !hasCredits) return 'Upgrade or purchase credits';
|
|
144
|
-
if (!hasCredits) return `Need ${requiredCredits} credits`;
|
|
145
|
-
return 'Full access';
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
return (
|
|
149
|
-
<View>
|
|
150
|
-
<Text>{getAccessMessage()}</Text>
|
|
151
|
-
<Button
|
|
152
|
-
onPress={() => requireFeature(() => executeAction())}
|
|
153
|
-
disabled={!canAccess}
|
|
154
|
-
title={canAccess ? 'Execute' : 'Unlock'}
|
|
155
|
-
/>
|
|
156
|
-
</View>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// INCORRECT - Generic message for all gates
|
|
161
|
-
if (!canAccess) {
|
|
162
|
-
return <Text>You cannot access this feature</Text>;
|
|
163
|
-
}
|
|
164
|
-
// Doesn't tell user what they need to do
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
### Premium Bypass Logic
|
|
168
|
-
|
|
169
|
-
```typescript
|
|
170
|
-
// CORRECT - Premium users bypass credit check
|
|
171
|
-
function PremiumBypass() {
|
|
172
|
-
const { requireFeature } = useFeatureGate({
|
|
173
|
-
isAuthenticated: !!user,
|
|
174
|
-
onShowAuthModal: (pending) => showAuthModal({ pendingAction: pending }),
|
|
175
|
-
hasSubscription: isPremium,
|
|
176
|
-
hasCredits: isPremium ? true : credits >= 5,
|
|
177
|
-
creditBalance: credits,
|
|
178
|
-
requiredCredits: isPremium ? 0 : 5,
|
|
179
|
-
onShowPaywall: (required) => {
|
|
180
|
-
if (isPremium) {
|
|
181
|
-
showInsufficientCreditsModal(required);
|
|
182
|
-
} else {
|
|
183
|
-
showPaywall();
|
|
184
|
-
}
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
return <Button onPress={() => requireFeature(executeAction)} />;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// INCORRECT - Charges premium users for credits
|
|
192
|
-
hasCredits: credits >= 5, // Even if isPremium is true
|
|
193
|
-
requiredCredits: 5, // Charges premium users
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Callback Implementation
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
// CORRECT - Proper auth modal with pending action
|
|
200
|
-
onShowAuthModal: (pendingAction) => {
|
|
201
|
-
navigation.navigate('Auth', {
|
|
202
|
-
onAuthSuccess: pendingAction,
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// CORRECT - Context-aware paywall
|
|
207
|
-
onShowPaywall: (requiredCredits) => {
|
|
208
|
-
if (isPremium) {
|
|
209
|
-
// Already premium, need credits
|
|
210
|
-
showCreditPurchaseModal({ requiredCredits });
|
|
211
|
-
} else {
|
|
212
|
-
// Not premium, show subscription
|
|
213
|
-
showSubscriptionPaywall();
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// INCORRECT - No pending action preservation
|
|
218
|
-
onShowAuthModal: () => {
|
|
219
|
-
navigation.navigate('Auth');
|
|
220
|
-
// User's intent is lost
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
### Action Gating
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
// CORRECT - Gate action execution
|
|
228
|
-
const handleGenerate = () => {
|
|
229
|
-
requireFeature(async () => {
|
|
230
|
-
// Only runs if all gates pass
|
|
231
|
-
const result = await generateContent();
|
|
232
|
-
showResult(result);
|
|
233
|
-
});
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
// INCORRECT - Execute action before gating
|
|
237
|
-
const handleGenerate = async () => {
|
|
238
|
-
const result = await generateContent(); // Runs regardless!
|
|
239
|
-
requireFeature(() => showResult(result));
|
|
240
|
-
};
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
## AI Agent Guidelines
|
|
244
|
-
|
|
245
|
-
### When Implementing Feature Gates
|
|
246
|
-
|
|
247
|
-
1. **Always** check gates in order: Auth → Subscription → Credits
|
|
248
|
-
2. **Always** provide clear, specific messaging for each gate
|
|
249
|
-
3. **Always** preserve user intent through auth/purchase flows
|
|
250
|
-
4. **Always** bypass credit check for premium users (if applicable)
|
|
251
|
-
5. **Never** trust client-side gates for security (server validation required)
|
|
252
|
-
|
|
253
|
-
### Integration Checklist
|
|
254
|
-
|
|
255
|
-
- [ ] Import from correct path: `@umituz/react-native-subscription`
|
|
256
|
-
- [ ] Implement `onShowAuthModal` with pending action preservation
|
|
257
|
-
- [ ] Implement `onShowPaywall` with context-aware messaging
|
|
258
|
-
- [ ] Check `canAccess` before showing feature
|
|
259
|
-
- [ ] Provide appropriate messaging for each gate state
|
|
260
|
-
- [ ] Respect premium status (bypass credit check if needed)
|
|
261
|
-
- [ ] Test all gate combinations (auth, subscription, credits)
|
|
262
|
-
- [ ] Test pending action execution after auth/purchase
|
|
263
|
-
- [ ] Implement error boundaries around gated actions
|
|
264
|
-
|
|
265
|
-
### Common Patterns to Implement
|
|
266
|
-
|
|
267
|
-
1. **Progressive Unlocking**: Show upgrade path for each gate
|
|
268
|
-
2. **Smart Paywalls**: Show subscription OR credits based on user state
|
|
269
|
-
3. **Intent Preservation**: Queue actions through auth/purchase flows
|
|
270
|
-
4. **Clear Messaging**: Tell users exactly what's required
|
|
271
|
-
5. **Premium Bypass**: Skip credit check for premium users
|
|
272
|
-
6. **Access Indicators**: Show lock/unlock status in UI
|
|
273
|
-
7. **Graceful Degradation**: Show limited version for free users
|
|
274
|
-
8. **Analytics Tracking**: Monitor gate triggers and conversions
|
|
275
|
-
|
|
276
|
-
## Related Documentation
|
|
277
|
-
|
|
278
|
-
- **useAuthGate**: Authentication gating only
|
|
279
|
-
- **useSubscriptionGate**: Subscription gating only
|
|
280
|
-
- **useCreditsGate**: Credits gating only
|
|
281
|
-
- **usePremiumGate**: Premium feature gating
|
|
282
|
-
- **useDeductCredit**: Credit deduction after gate passes
|
|
283
|
-
- **Feature Gating**: `../../../docs/FEATURE_GATING.md`
|
|
284
|
-
- **Access Control**: `../../../docs/ACCESS_PATTERNS.md`
|