@umituz/react-native-subscription 2.14.97 → 2.14.98
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/LICENSE +21 -0
- package/README.md +462 -0
- package/package.json +1 -3
- package/src/application/README.md +229 -0
- package/src/application/ports/README.md +103 -0
- package/src/domain/README.md +402 -0
- package/src/domain/constants/README.md +80 -0
- package/src/domain/entities/README.md +176 -0
- package/src/domain/errors/README.md +307 -0
- package/src/domain/value-objects/README.md +186 -0
- package/src/domains/config/README.md +390 -0
- package/src/domains/paywall/README.md +371 -0
- package/src/domains/paywall/components/PaywallHeader.tsx +8 -11
- package/src/domains/paywall/components/README.md +185 -0
- package/src/domains/paywall/entities/README.md +199 -0
- package/src/domains/paywall/hooks/README.md +129 -0
- package/src/domains/wallet/README.md +292 -0
- package/src/domains/wallet/domain/README.md +108 -0
- package/src/domains/wallet/domain/entities/README.md +122 -0
- package/src/domains/wallet/domain/errors/README.md +157 -0
- package/src/domains/wallet/infrastructure/README.md +96 -0
- package/src/domains/wallet/presentation/components/BalanceCard.tsx +6 -12
- package/src/domains/wallet/presentation/components/README.md +231 -0
- package/src/domains/wallet/presentation/hooks/README.md +255 -0
- package/src/infrastructure/README.md +514 -0
- package/src/infrastructure/mappers/README.md +34 -0
- package/src/infrastructure/models/README.md +26 -0
- package/src/infrastructure/repositories/README.md +385 -0
- package/src/infrastructure/services/README.md +374 -0
- package/src/presentation/README.md +410 -0
- package/src/presentation/components/README.md +183 -0
- package/src/presentation/components/details/CreditRow.md +337 -0
- package/src/presentation/components/details/DetailRow.md +283 -0
- package/src/presentation/components/details/PremiumDetailsCard.md +266 -0
- package/src/presentation/components/details/PremiumStatusBadge.md +266 -0
- package/src/presentation/components/details/README.md +449 -0
- package/src/presentation/components/feedback/PaywallFeedbackModal.md +314 -0
- package/src/presentation/components/feedback/README.md +447 -0
- package/src/presentation/components/paywall/PaywallModal.md +444 -0
- package/src/presentation/components/paywall/README.md +190 -0
- package/src/presentation/components/sections/README.md +468 -0
- package/src/presentation/components/sections/SubscriptionSection.md +246 -0
- package/src/presentation/hooks/README.md +743 -0
- package/src/presentation/hooks/useAuthAwarePurchase.md +359 -0
- package/src/presentation/hooks/useAuthGate.md +403 -0
- package/src/presentation/hooks/useAuthSubscriptionSync.md +398 -0
- package/src/presentation/hooks/useCreditChecker.md +407 -0
- package/src/presentation/hooks/useCredits.md +342 -0
- package/src/presentation/hooks/useCreditsGate.md +346 -0
- package/src/presentation/hooks/useDeductCredit.md +160 -0
- package/src/presentation/hooks/useDevTestCallbacks.md +422 -0
- package/src/presentation/hooks/useFeatureGate.md +157 -0
- package/src/presentation/hooks/useInitializeCredits.md +458 -0
- package/src/presentation/hooks/usePaywall.md +334 -0
- package/src/presentation/hooks/usePaywallOperations.md +486 -0
- package/src/presentation/hooks/usePaywallVisibility.md +344 -0
- package/src/presentation/hooks/usePremium.md +230 -0
- package/src/presentation/hooks/usePremiumGate.md +423 -0
- package/src/presentation/hooks/usePremiumWithCredits.md +429 -0
- package/src/presentation/hooks/useSubscription.md +450 -0
- package/src/presentation/hooks/useSubscriptionDetails.md +438 -0
- package/src/presentation/hooks/useSubscriptionGate.md +168 -0
- package/src/presentation/hooks/useSubscriptionSettingsConfig.md +374 -0
- package/src/presentation/hooks/useSubscriptionStatus.md +424 -0
- package/src/presentation/hooks/useUserTier.md +356 -0
- package/src/presentation/hooks/useUserTierWithRepository.md +452 -0
- package/src/presentation/screens/README.md +194 -0
- package/src/presentation/types/README.md +38 -0
- package/src/presentation/utils/README.md +52 -0
- package/src/revenuecat/README.md +523 -0
- package/src/revenuecat/domain/README.md +147 -0
- package/src/revenuecat/domain/errors/README.md +197 -0
- package/src/revenuecat/infrastructure/config/README.md +40 -0
- package/src/revenuecat/infrastructure/managers/README.md +49 -0
- package/src/revenuecat/presentation/hooks/README.md +56 -0
- package/src/utils/README.md +529 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
# useAuthGate Hook
|
|
2
|
+
|
|
3
|
+
Hook for combining authentication and subscription gating.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { useAuthGate } from '@umituz/react-native-subscription';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Signature
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
function useAuthGate(config?: {
|
|
15
|
+
requireAuth?: boolean;
|
|
16
|
+
requireSubscription?: boolean;
|
|
17
|
+
}): {
|
|
18
|
+
isAuthenticated: boolean;
|
|
19
|
+
isAuthorized: boolean;
|
|
20
|
+
user: User | null;
|
|
21
|
+
subscription: SubscriptionStatus | null;
|
|
22
|
+
signIn: () => void;
|
|
23
|
+
signOut: () => void;
|
|
24
|
+
isLoading: boolean;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Parameters
|
|
29
|
+
|
|
30
|
+
| Parameter | Type | Default | Description |
|
|
31
|
+
|-----------|------|---------|-------------|
|
|
32
|
+
| `requireAuth` | `boolean` | `false` | Require user to be logged in |
|
|
33
|
+
| `requireSubscription` | `boolean` | `false` | Require premium subscription |
|
|
34
|
+
|
|
35
|
+
## Returns
|
|
36
|
+
|
|
37
|
+
| Property | Type | Description |
|
|
38
|
+
|----------|------|-------------|
|
|
39
|
+
| `isAuthenticated` | `boolean` | User is logged in |
|
|
40
|
+
| `isAuthorized` | `boolean` | User meets all requirements |
|
|
41
|
+
| `user` | `User \| null` | Current user object |
|
|
42
|
+
| `subscription` | `SubscriptionStatus \| null` | Subscription status |
|
|
43
|
+
| `signIn` | `() => void` | Trigger sign in |
|
|
44
|
+
| `signOut` | `() => void` | Trigger sign out |
|
|
45
|
+
| `isLoading` | `boolean` | Loading state |
|
|
46
|
+
|
|
47
|
+
## Basic Usage
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
function ProtectedFeature() {
|
|
51
|
+
const { isAuthorized, signIn, isLoading } = useAuthGate({
|
|
52
|
+
requireAuth: true,
|
|
53
|
+
requireSubscription: true,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (isLoading) return <ActivityIndicator />;
|
|
57
|
+
|
|
58
|
+
if (!isAuthorized) {
|
|
59
|
+
return (
|
|
60
|
+
<View>
|
|
61
|
+
<Text>This feature requires Premium</Text>
|
|
62
|
+
<Button onPress={signIn} title="Sign In / Subscribe" />
|
|
63
|
+
</View>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return <PremiumFeature />;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Use Cases
|
|
72
|
+
|
|
73
|
+
### Auth Required Only
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
function AuthRequiredComponent() {
|
|
77
|
+
const { isAuthorized, signIn } = useAuthGate({
|
|
78
|
+
requireAuth: true,
|
|
79
|
+
requireSubscription: false,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (!isAuthorized) {
|
|
83
|
+
return (
|
|
84
|
+
<View>
|
|
85
|
+
<Text>Please sign in to continue</Text>
|
|
86
|
+
<Button onPress={signIn} title="Sign In" />
|
|
87
|
+
</View>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return <UserDashboard />;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Subscription Required (Auth Implicit)
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
function SubscriptionRequiredComponent() {
|
|
99
|
+
const { isAuthorized, user, subscription } = useAuthGate({
|
|
100
|
+
requireAuth: false, // Auto-handles auth internally
|
|
101
|
+
requireSubscription: true,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (!isAuthorized) {
|
|
105
|
+
return (
|
|
106
|
+
<View>
|
|
107
|
+
<Text>This feature requires Premium</Text>
|
|
108
|
+
<Button
|
|
109
|
+
onPress={() => user ? showPaywall() : signIn()}
|
|
110
|
+
title={user ? 'Upgrade' : 'Sign In & Subscribe'}
|
|
111
|
+
/>
|
|
112
|
+
</View>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return <PremiumContent />;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Both Auth and Subscription Required
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
function FullyProtectedFeature() {
|
|
124
|
+
const {
|
|
125
|
+
isAuthorized,
|
|
126
|
+
user,
|
|
127
|
+
subscription,
|
|
128
|
+
signIn,
|
|
129
|
+
isLoading
|
|
130
|
+
} = useAuthGate({
|
|
131
|
+
requireAuth: true,
|
|
132
|
+
requireSubscription: true,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
if (isLoading) return <LoadingScreen />;
|
|
136
|
+
|
|
137
|
+
if (!isAuthorized) {
|
|
138
|
+
if (!user) {
|
|
139
|
+
return <SignInPrompt onSignIn={signIn} />;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!subscription?.isPremium) {
|
|
143
|
+
return <UpgradePrompt onUpgrade={() => navigation.navigate('Paywall')} />;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return <PremiumContent />;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Advanced Usage
|
|
152
|
+
|
|
153
|
+
### Progressive Gating
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
function ProgressiveAccess() {
|
|
157
|
+
const { isAuthorized, user, subscription } = useAuthGate({
|
|
158
|
+
requireAuth: true,
|
|
159
|
+
requireSubscription: true,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Determine access level
|
|
163
|
+
const accessLevel = !user
|
|
164
|
+
? 'public'
|
|
165
|
+
: !subscription?.isPremium
|
|
166
|
+
? 'authenticated'
|
|
167
|
+
: 'premium';
|
|
168
|
+
|
|
169
|
+
const features = {
|
|
170
|
+
public: ['Basic Browse'],
|
|
171
|
+
authenticated: ['Save Favorites', 'View History'],
|
|
172
|
+
premium: ['Advanced Filters', 'AI Features', 'Priority Support'],
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<FeatureList
|
|
177
|
+
availableFeatures={features[accessLevel]}
|
|
178
|
+
onFeatureLocked={(feature) => showUpgradePrompt(feature, accessLevel)}
|
|
179
|
+
/>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### With Graceful Degradation
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
function GracefulDegradationComponent() {
|
|
188
|
+
const { isAuthorized, user, subscription } = useAuthGate({
|
|
189
|
+
requireAuth: true,
|
|
190
|
+
requireSubscription: true,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
if (!isAuthorized) {
|
|
194
|
+
// Show limited version with upgrade prompt
|
|
195
|
+
return (
|
|
196
|
+
<View>
|
|
197
|
+
<FeatureFreeVersion />
|
|
198
|
+
|
|
199
|
+
<View style={styles.upgradeBanner}>
|
|
200
|
+
<Text>Upgrade to unlock all features</Text>
|
|
201
|
+
<Button onPress={() => user ? showPaywall() : signIn()} />
|
|
202
|
+
</View>
|
|
203
|
+
</View>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return <FullVersion />;
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### With Custom Auth Flow
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
function CustomAuthFlow() {
|
|
215
|
+
const { isAuthorized, signIn } = useAuthGate({
|
|
216
|
+
requireAuth: true,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const handleSignIn = () => {
|
|
220
|
+
// Navigate to custom auth flow
|
|
221
|
+
navigation.navigate('CustomAuth', {
|
|
222
|
+
onSuccess: () => {
|
|
223
|
+
// Auth success, callback will trigger re-render
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
if (!isAuthorized) {
|
|
229
|
+
return (
|
|
230
|
+
<View>
|
|
231
|
+
<Text>Sign in to access this feature</Text>
|
|
232
|
+
<Button onPress={handleSignIn} title="Sign In" />
|
|
233
|
+
</View>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return <ProtectedContent />;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Integration Examples
|
|
242
|
+
|
|
243
|
+
### Navigation Guard
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
function ProtectedScreen() {
|
|
247
|
+
const { isAuthorized, signIn } = useAuthGate({
|
|
248
|
+
requireAuth: true,
|
|
249
|
+
requireSubscription: true,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
if (!isAuthorized) {
|
|
254
|
+
// Replace navigation instead of just showing UI
|
|
255
|
+
navigation.replace('AuthGate', {
|
|
256
|
+
requireAuth: true,
|
|
257
|
+
requireSubscription: true,
|
|
258
|
+
returnTo: 'ProtectedScreen',
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}, [isAuthorized]);
|
|
262
|
+
|
|
263
|
+
if (!isAuthorized) return null;
|
|
264
|
+
|
|
265
|
+
return <ScreenContent />;
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Settings Screen
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
function SettingsScreen() {
|
|
273
|
+
const { user, subscription, signIn, signOut } = useAuthGate({
|
|
274
|
+
requireAuth: true,
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<ScrollView>
|
|
279
|
+
<Section title="Account">
|
|
280
|
+
<InfoRow label="Email" value={user?.email} />
|
|
281
|
+
<InfoRow
|
|
282
|
+
label="Subscription"
|
|
283
|
+
value={subscription?.type || 'Free'}
|
|
284
|
+
/>
|
|
285
|
+
</Section>
|
|
286
|
+
|
|
287
|
+
<Section title="Actions">
|
|
288
|
+
<Button
|
|
289
|
+
onPress={signIn}
|
|
290
|
+
title="Sign In"
|
|
291
|
+
/>
|
|
292
|
+
<Button
|
|
293
|
+
onPress={signOut}
|
|
294
|
+
title="Sign Out"
|
|
295
|
+
/>
|
|
296
|
+
</Section>
|
|
297
|
+
</ScrollView>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Content Based on Access Level
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
function DynamicContent() {
|
|
306
|
+
const { isAuthorized, user, subscription } = useAuthGate({
|
|
307
|
+
requireAuth: true,
|
|
308
|
+
requireSubscription: false,
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<View>
|
|
313
|
+
{/* Always visible */}
|
|
314
|
+
<PublicContent />
|
|
315
|
+
|
|
316
|
+
{/* Authenticated users */}
|
|
317
|
+
{user && <AuthenticatedContent />}
|
|
318
|
+
|
|
319
|
+
{/* Premium users */}
|
|
320
|
+
{subscription?.isPremium && <PremiumContent />}
|
|
321
|
+
</View>
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Best Practices
|
|
327
|
+
|
|
328
|
+
1. **Check authorization first** - Before rendering content
|
|
329
|
+
2. **Provide clear messaging** - Tell users what's required
|
|
330
|
+
3. **Easy sign-in flow** - Make authentication simple
|
|
331
|
+
4. **Show upgrade path** - Guide users to subscription
|
|
332
|
+
5. **Handle loading** - Show loading states appropriately
|
|
333
|
+
6. **Cache auth state** - Avoid unnecessary re-authentication
|
|
334
|
+
7. **Sign out cleanup** - Clear sensitive data on sign out
|
|
335
|
+
|
|
336
|
+
## Testing
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
describe('useAuthGate', () => {
|
|
340
|
+
it('should authorize authenticated user', () => {
|
|
341
|
+
const { result } = renderHook(() =>
|
|
342
|
+
useAuthGate({ requireAuth: true }),
|
|
343
|
+
{
|
|
344
|
+
wrapper: ({ children }) => (
|
|
345
|
+
<AuthProvider value={{ user: { uid: '123' }}}>
|
|
346
|
+
{children}
|
|
347
|
+
</AuthProvider>
|
|
348
|
+
),
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
expect(result.current.isAuthorized).toBe(true);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('should not authorize unauthenticated user', () => {
|
|
356
|
+
const { result } = renderHook(() =>
|
|
357
|
+
useAuthGate({ requireAuth: true }),
|
|
358
|
+
{
|
|
359
|
+
wrapper: ({ children }) => (
|
|
360
|
+
<AuthProvider value={{ user: null }}>
|
|
361
|
+
{children}
|
|
362
|
+
</AuthProvider>
|
|
363
|
+
),
|
|
364
|
+
}
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
expect(result.current.isAuthorized).toBe(false);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it('should authorize premium user', () => {
|
|
371
|
+
const { result } = renderHook(() =>
|
|
372
|
+
useAuthGate({ requireSubscription: true }),
|
|
373
|
+
{
|
|
374
|
+
wrapper: ({ children }) => (
|
|
375
|
+
<AuthProvider
|
|
376
|
+
value={{
|
|
377
|
+
user: { uid: '123' },
|
|
378
|
+
subscription: { type: 'premium', isActive: true },
|
|
379
|
+
}}
|
|
380
|
+
>
|
|
381
|
+
{children}
|
|
382
|
+
</AuthProvider>
|
|
383
|
+
),
|
|
384
|
+
}
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
expect(result.current.isAuthorized).toBe(true);
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Related Hooks
|
|
393
|
+
|
|
394
|
+
- **useAuth** - Authentication only
|
|
395
|
+
- **usePremium** - Premium check only
|
|
396
|
+
- **useSubscriptionGate** - Subscription gating
|
|
397
|
+
- **useUserTier** - Tier information
|
|
398
|
+
|
|
399
|
+
## See Also
|
|
400
|
+
|
|
401
|
+
- [Auth Integration](../../hooks/useAuthSubscriptionSync.md)
|
|
402
|
+
- [usePremium](./usePremium.md)
|
|
403
|
+
- [useUserTier](./useUserTier.md)
|