@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,356 @@
|
|
|
1
|
+
# useUserTier Hook
|
|
2
|
+
|
|
3
|
+
Hook for determining and tracking user tier (guest, free, premium).
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { useUserTier } from '@umituz/react-native-subscription';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Signature
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
function useUserTier(): {
|
|
15
|
+
tier: UserTier;
|
|
16
|
+
isGuest: boolean;
|
|
17
|
+
isFree: boolean;
|
|
18
|
+
isPremium: boolean;
|
|
19
|
+
canUpgrade: boolean;
|
|
20
|
+
isLoading: boolean;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Returns
|
|
25
|
+
|
|
26
|
+
| Property | Type | Description |
|
|
27
|
+
|----------|------|-------------|
|
|
28
|
+
| `tier` | `'guest' \| 'free' \| 'premium'` | Current user tier |
|
|
29
|
+
| `isGuest` | `boolean` | User is not authenticated |
|
|
30
|
+
| `isFree` | `boolean` | User is authenticated but free |
|
|
31
|
+
| `isPremium` | `boolean` | User has premium subscription |
|
|
32
|
+
| `canUpgrade` | `boolean` | User can upgrade to premium |
|
|
33
|
+
| `isLoading` | `boolean` | Loading state |
|
|
34
|
+
|
|
35
|
+
## User Tiers
|
|
36
|
+
|
|
37
|
+
### Guest
|
|
38
|
+
- User is not authenticated
|
|
39
|
+
- No access to personalized features
|
|
40
|
+
- Limited functionality
|
|
41
|
+
|
|
42
|
+
### Free
|
|
43
|
+
- User is authenticated
|
|
44
|
+
- Has basic access
|
|
45
|
+
- Can upgrade to premium
|
|
46
|
+
|
|
47
|
+
### Premium
|
|
48
|
+
- User has active subscription
|
|
49
|
+
- Full access to all features
|
|
50
|
+
- Priority support
|
|
51
|
+
|
|
52
|
+
## Basic Usage
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
function UserDisplay() {
|
|
56
|
+
const { tier, isGuest, isFree, isPremium } = useUserTier();
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<View>
|
|
60
|
+
<Badge>{tier.toUpperCase()}</Badge>
|
|
61
|
+
|
|
62
|
+
{isGuest && <Text>Please sign in to save your progress</Text>}
|
|
63
|
+
{isFree && <Text>Upgrade to Premium for full access</Text>}
|
|
64
|
+
{isPremium && <Text>Welcome, Premium member!</Text>}
|
|
65
|
+
</View>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Advanced Usage
|
|
71
|
+
|
|
72
|
+
### Tier-Based UI
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
function TierBasedFeatures() {
|
|
76
|
+
const { tier } = useUserTier();
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<View>
|
|
80
|
+
{/* Available to everyone */}
|
|
81
|
+
<BasicFeature />
|
|
82
|
+
|
|
83
|
+
{/* Free and Premium only */}
|
|
84
|
+
{(tier === 'free' || tier === 'premium') && (
|
|
85
|
+
<FreeFeature />
|
|
86
|
+
)}
|
|
87
|
+
|
|
88
|
+
{/* Premium only */}
|
|
89
|
+
{tier === 'premium' && (
|
|
90
|
+
<PremiumFeature />
|
|
91
|
+
)}
|
|
92
|
+
</View>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### With Navigation Guard
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
function ProtectedScreen() {
|
|
101
|
+
const { tier, isLoading } = useUserTier();
|
|
102
|
+
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
if (!isLoading && tier !== 'premium') {
|
|
105
|
+
navigation.replace('Paywall');
|
|
106
|
+
}
|
|
107
|
+
}, [tier, isLoading]);
|
|
108
|
+
|
|
109
|
+
if (isLoading) return <LoadingScreen />;
|
|
110
|
+
|
|
111
|
+
return tier === 'premium' ? <PremiumContent /> : null;
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### With Progress Tracking
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
function TierProgress() {
|
|
119
|
+
const { tier, canUpgrade } = useUserTier();
|
|
120
|
+
|
|
121
|
+
const tiers = ['guest', 'free', 'premium'];
|
|
122
|
+
const currentIndex = tiers.indexOf(tier);
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<View>
|
|
126
|
+
<Text>Current Tier: {tier}</Text>
|
|
127
|
+
|
|
128
|
+
<View style={styles.progress}>
|
|
129
|
+
{tiers.map((t, index) => (
|
|
130
|
+
<View
|
|
131
|
+
key={t}
|
|
132
|
+
style={[
|
|
133
|
+
styles.step,
|
|
134
|
+
index <= currentIndex && styles.activeStep,
|
|
135
|
+
]}
|
|
136
|
+
>
|
|
137
|
+
<Text>{t}</Text>
|
|
138
|
+
</View>
|
|
139
|
+
))}
|
|
140
|
+
</View>
|
|
141
|
+
|
|
142
|
+
{canUpgrade && (
|
|
143
|
+
<Button
|
|
144
|
+
onPress={() => navigation.navigate('Upgrade')}
|
|
145
|
+
title="Upgrade to Premium"
|
|
146
|
+
/>
|
|
147
|
+
)}
|
|
148
|
+
</View>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Examples
|
|
154
|
+
|
|
155
|
+
### Tier-Based Pricing
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
function PricingCards() {
|
|
159
|
+
const { tier } = useUserTier();
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<ScrollView horizontal>
|
|
163
|
+
<PricingCard
|
|
164
|
+
tier="free"
|
|
165
|
+
price="$0"
|
|
166
|
+
features={['Basic Access', 'Limited Storage']}
|
|
167
|
+
isCurrent={tier === 'free'}
|
|
168
|
+
/>
|
|
169
|
+
|
|
170
|
+
<PricingCard
|
|
171
|
+
tier="premium"
|
|
172
|
+
price="$9.99/mo"
|
|
173
|
+
features={[
|
|
174
|
+
'Full Access',
|
|
175
|
+
'Unlimited Storage',
|
|
176
|
+
'Priority Support',
|
|
177
|
+
'Ad-Free',
|
|
178
|
+
]}
|
|
179
|
+
isCurrent={tier === 'premium'}
|
|
180
|
+
popular
|
|
181
|
+
/>
|
|
182
|
+
</ScrollView>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Tier Indicator
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
function TierIndicator() {
|
|
191
|
+
const { tier, isPremium } = useUserTier();
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<View style={[
|
|
195
|
+
styles.container,
|
|
196
|
+
isPremium && styles.premiumContainer,
|
|
197
|
+
]}>
|
|
198
|
+
{isPremium ? (
|
|
199
|
+
<>
|
|
200
|
+
<Icon name="crown" size={20} color="#FFD700" />
|
|
201
|
+
<Text style={styles.text}>PREMIUM</Text>
|
|
202
|
+
</>
|
|
203
|
+
) : (
|
|
204
|
+
<Text style={styles.text}>FREE</Text>
|
|
205
|
+
)}
|
|
206
|
+
</View>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const styles = StyleSheet.create({
|
|
211
|
+
container: {
|
|
212
|
+
paddingHorizontal: 12,
|
|
213
|
+
paddingVertical: 6,
|
|
214
|
+
borderRadius: 16,
|
|
215
|
+
backgroundColor: '#E0E0E0',
|
|
216
|
+
},
|
|
217
|
+
premiumContainer: {
|
|
218
|
+
backgroundColor: '#FFD700',
|
|
219
|
+
},
|
|
220
|
+
text: {
|
|
221
|
+
fontWeight: 'bold',
|
|
222
|
+
fontSize: 12,
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Conditional Features
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
function FeatureList() {
|
|
231
|
+
const { isGuest, isFree, isPremium } = useUserTier();
|
|
232
|
+
|
|
233
|
+
const features = [
|
|
234
|
+
{ name: 'Basic Search', available: true },
|
|
235
|
+
{ name: 'Save Favorites', available: !isGuest },
|
|
236
|
+
{ name: 'Advanced Filters', available: isFree || isPremium },
|
|
237
|
+
{ name: 'AI Recommendations', available: isPremium },
|
|
238
|
+
{ name: 'Priority Support', available: isPremium },
|
|
239
|
+
];
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<View>
|
|
243
|
+
{features.map((feature) => (
|
|
244
|
+
<FeatureItem
|
|
245
|
+
key={feature.name}
|
|
246
|
+
{...feature}
|
|
247
|
+
locked={!feature.available}
|
|
248
|
+
/>
|
|
249
|
+
))}
|
|
250
|
+
</View>
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Tier Transition Tracking
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
function TierTransitionTracker() {
|
|
259
|
+
const { tier } = useUserTier();
|
|
260
|
+
const previousTier = useRef(tier);
|
|
261
|
+
|
|
262
|
+
useEffect(() => {
|
|
263
|
+
if (previousTier.current !== tier) {
|
|
264
|
+
analytics.track('tier_changed', {
|
|
265
|
+
from: previousTier.current,
|
|
266
|
+
to: tier,
|
|
267
|
+
timestamp: Date.now(),
|
|
268
|
+
});
|
|
269
|
+
previousTier.current = tier;
|
|
270
|
+
}
|
|
271
|
+
}, [tier]);
|
|
272
|
+
|
|
273
|
+
return <YourComponent />;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Integration with Auth
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
function TierWithAuth() {
|
|
281
|
+
const { user } = useAuth();
|
|
282
|
+
const { tier } = useUserTier();
|
|
283
|
+
|
|
284
|
+
// Tier updates automatically when auth state changes
|
|
285
|
+
useEffect(() => {
|
|
286
|
+
if (user) {
|
|
287
|
+
console.log(`Logged in as ${tier}`);
|
|
288
|
+
} else {
|
|
289
|
+
console.log('Logged out, now guest');
|
|
290
|
+
}
|
|
291
|
+
}, [user, tier]);
|
|
292
|
+
|
|
293
|
+
return (
|
|
294
|
+
<View>
|
|
295
|
+
<Text>Current tier: {tier}</Text>
|
|
296
|
+
<Text>User: {user?.email || 'Not logged in'}</Text>
|
|
297
|
+
</View>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Testing
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
describe('useUserTier', () => {
|
|
306
|
+
it('should return guest for unauthenticated user', () => {
|
|
307
|
+
const { result } = renderHook(() => useUserTier(), {
|
|
308
|
+
wrapper: ({ children }) => (
|
|
309
|
+
<AuthProvider value={{ user: null }}>{children}</AuthProvider>
|
|
310
|
+
),
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
expect(result.current.tier).toBe('guest');
|
|
314
|
+
expect(result.current.isGuest).toBe(true);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('should return premium for subscribed user', () => {
|
|
318
|
+
const { result } = renderHook(() => useUserTier(), {
|
|
319
|
+
wrapper: ({ children }) => (
|
|
320
|
+
<AuthProvider
|
|
321
|
+
value={{
|
|
322
|
+
user: { uid: '123' },
|
|
323
|
+
subscription: { type: 'premium', isActive: true },
|
|
324
|
+
}}
|
|
325
|
+
>
|
|
326
|
+
{children}
|
|
327
|
+
</AuthProvider>
|
|
328
|
+
),
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
expect(result.current.tier).toBe('premium');
|
|
332
|
+
expect(result.current.isPremium).toBe(true);
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Best Practices
|
|
338
|
+
|
|
339
|
+
1. **Handle all tiers** - Don't forget guest users
|
|
340
|
+
2. **Show upgrade prompts** - Guide free users to premium
|
|
341
|
+
3. **Track transitions** - Monitor tier changes
|
|
342
|
+
4. **Provide value** - Show benefits of upgrading
|
|
343
|
+
5. **Respect users** - Don't be too aggressive with upselling
|
|
344
|
+
6. **Test all tiers** - Ensure features work for each tier
|
|
345
|
+
|
|
346
|
+
## Related Hooks
|
|
347
|
+
|
|
348
|
+
- **useAuth** - Authentication state
|
|
349
|
+
- **usePremium** - Premium subscription check
|
|
350
|
+
- **useSubscription** - Subscription details
|
|
351
|
+
- **useAuthGate** - Auth + subscription gate
|
|
352
|
+
|
|
353
|
+
## See Also
|
|
354
|
+
|
|
355
|
+
- [User Tier Utils](../../../utils/README.md#user-tier-utilities)
|
|
356
|
+
- [Tier README](../../utils/README.md)
|