@umituz/react-native-subscription 2.14.96 → 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 +3 -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/revenuecat/presentation/hooks/usePurchasePackage.ts +1 -1
- package/src/utils/README.md +529 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
# useUserTierWithRepository Hook
|
|
2
|
+
|
|
3
|
+
Automatically fetches premium status and provides tier information with repository integration.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { useUserTierWithRepository } from '@umituz/react-native-subscription';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Signature
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
function useUserTierWithRepository(params: {
|
|
15
|
+
auth: AuthProvider;
|
|
16
|
+
repository: ISubscriptionRepository;
|
|
17
|
+
}): {
|
|
18
|
+
tier: 'guest' | 'freemium' | 'premium';
|
|
19
|
+
isPremium: boolean;
|
|
20
|
+
isGuest: boolean;
|
|
21
|
+
isAuthenticated: boolean;
|
|
22
|
+
userId: string | null;
|
|
23
|
+
isLoading: boolean;
|
|
24
|
+
error: string | null;
|
|
25
|
+
refresh: () => Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Parameters
|
|
30
|
+
|
|
31
|
+
| Parameter | Type | Default | Description |
|
|
32
|
+
|-----------|------|---------|-------------|
|
|
33
|
+
| `auth` | `AuthProvider` | **Required** | Auth provider with user state |
|
|
34
|
+
| `repository` | `ISubscriptionRepository` | **Required** | Subscription repository |
|
|
35
|
+
|
|
36
|
+
## AuthProvider Interface
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
interface AuthProvider {
|
|
40
|
+
user: { uid: string } | null;
|
|
41
|
+
isGuest: boolean;
|
|
42
|
+
isAuthenticated: boolean;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Returns
|
|
47
|
+
|
|
48
|
+
| Property | Type | Description |
|
|
49
|
+
|----------|------|-------------|
|
|
50
|
+
| `tier` | `'guest' \| 'freemium' \| 'premium'` | User tier |
|
|
51
|
+
| `isPremium` | `boolean` | User has premium access |
|
|
52
|
+
| `isGuest` | `boolean` | User is not authenticated |
|
|
53
|
+
| `isAuthenticated` | `boolean` | User is authenticated |
|
|
54
|
+
| `userId` | `string \| null` | User ID |
|
|
55
|
+
| `isLoading` | `boolean` | Premium status is loading |
|
|
56
|
+
| `error` | `string \| null` | Error message |
|
|
57
|
+
| `refresh` | `() => Promise<void>` | Manually refresh premium status |
|
|
58
|
+
|
|
59
|
+
## Basic Usage
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
function UserTierDisplay() {
|
|
63
|
+
const auth = useAuth(); // Your auth hook
|
|
64
|
+
const subscriptionRepository = useSubscriptionRepository();
|
|
65
|
+
|
|
66
|
+
const {
|
|
67
|
+
tier,
|
|
68
|
+
isPremium,
|
|
69
|
+
isLoading,
|
|
70
|
+
} = useUserTierWithRepository({
|
|
71
|
+
auth,
|
|
72
|
+
repository: subscriptionRepository,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (isLoading) return <ActivityIndicator />;
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<View>
|
|
79
|
+
<Text>Tier: {tier.toUpperCase()}</Text>
|
|
80
|
+
<Text>Status: {isPremium ? 'Premium' : 'Free'}</Text>
|
|
81
|
+
</View>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Advanced Usage
|
|
87
|
+
|
|
88
|
+
### With Custom Auth Provider
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
function WithCustomAuth() {
|
|
92
|
+
const authManager = useCustomAuthManager();
|
|
93
|
+
|
|
94
|
+
const authProvider = {
|
|
95
|
+
user: authManager.user ? { uid: authManager.user.id } : null,
|
|
96
|
+
isGuest: !authManager.user,
|
|
97
|
+
isAuthenticated: !!authManager.user,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const { tier, isPremium } = useUserTierWithRepository({
|
|
101
|
+
auth: authProvider,
|
|
102
|
+
repository: subscriptionRepository,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<View>
|
|
107
|
+
<Badge text={tier} />
|
|
108
|
+
{isPremium && <PremiumBadge />}
|
|
109
|
+
</View>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### With Firebase Auth
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
function WithFirebaseAuth() {
|
|
118
|
+
const { user } = useFirebaseAuth();
|
|
119
|
+
|
|
120
|
+
const authProvider = useMemo(() => ({
|
|
121
|
+
user: user ? { uid: user.uid } : null,
|
|
122
|
+
isGuest: !user,
|
|
123
|
+
isAuthenticated: !!user,
|
|
124
|
+
}), [user]);
|
|
125
|
+
|
|
126
|
+
const { tier, isPremium, isLoading } = useUserTierWithRepository({
|
|
127
|
+
auth: authProvider,
|
|
128
|
+
repository: subscriptionRepository,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (isLoading) return <LoadingScreen />;
|
|
132
|
+
|
|
133
|
+
return <TierBadge tier={tier} />;
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### With Error Handling
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
function TierWithErrorHandling() {
|
|
141
|
+
const auth = useAuth();
|
|
142
|
+
|
|
143
|
+
const {
|
|
144
|
+
tier,
|
|
145
|
+
error,
|
|
146
|
+
isLoading,
|
|
147
|
+
refresh,
|
|
148
|
+
} = useUserTierWithRepository({
|
|
149
|
+
auth,
|
|
150
|
+
repository: subscriptionRepository,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
if (error) {
|
|
155
|
+
console.error('Failed to fetch tier:', error);
|
|
156
|
+
// Optionally show error to user
|
|
157
|
+
}
|
|
158
|
+
}, [error]);
|
|
159
|
+
|
|
160
|
+
if (isLoading) return <LoadingScreen />;
|
|
161
|
+
|
|
162
|
+
if (error) {
|
|
163
|
+
return (
|
|
164
|
+
<View>
|
|
165
|
+
<Text>Failed to load subscription status</Text>
|
|
166
|
+
<Button onPress={refresh} title="Retry" />
|
|
167
|
+
</View>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return <TierDisplay tier={tier} />;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### With Manual Refresh
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
function TierWithRefresh() {
|
|
179
|
+
const auth = useAuth();
|
|
180
|
+
|
|
181
|
+
const {
|
|
182
|
+
tier,
|
|
183
|
+
isLoading,
|
|
184
|
+
refresh,
|
|
185
|
+
} = useUserTierWithRepository({
|
|
186
|
+
auth,
|
|
187
|
+
repository: subscriptionRepository,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const handleRefresh = async () => {
|
|
191
|
+
await refresh();
|
|
192
|
+
Alert.alert('Success', 'Subscription status refreshed');
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<View>
|
|
197
|
+
<Text>Tier: {tier}</Text>
|
|
198
|
+
|
|
199
|
+
<Button
|
|
200
|
+
onPress={handleRefresh}
|
|
201
|
+
disabled={isLoading}
|
|
202
|
+
title="Refresh Status"
|
|
203
|
+
/>
|
|
204
|
+
</View>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### With Loading State
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
function TierWithLoading() {
|
|
213
|
+
const auth = useAuth();
|
|
214
|
+
|
|
215
|
+
const {
|
|
216
|
+
tier,
|
|
217
|
+
isPremium,
|
|
218
|
+
isLoading,
|
|
219
|
+
} = useUserTierWithRepository({
|
|
220
|
+
auth,
|
|
221
|
+
repository: subscriptionRepository,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<View>
|
|
226
|
+
<Text>Tier: {tier}</Text>
|
|
227
|
+
<Text>Premium: {isPremium ? 'Yes' : 'No'}</Text>
|
|
228
|
+
|
|
229
|
+
{isLoading && (
|
|
230
|
+
<View style={styles.loadingContainer}>
|
|
231
|
+
<ActivityIndicator size="small" />
|
|
232
|
+
<Text>Checking subscription...</Text>
|
|
233
|
+
</View>
|
|
234
|
+
)}
|
|
235
|
+
</View>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Examples
|
|
241
|
+
|
|
242
|
+
### Complete User Profile
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
function UserProfile() {
|
|
246
|
+
const auth = useAuth();
|
|
247
|
+
|
|
248
|
+
const {
|
|
249
|
+
tier,
|
|
250
|
+
isPremium,
|
|
251
|
+
userId,
|
|
252
|
+
isLoading,
|
|
253
|
+
error,
|
|
254
|
+
} = useUserTierWithRepository({
|
|
255
|
+
auth,
|
|
256
|
+
repository: subscriptionRepository,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
if (isLoading) return <LoadingScreen />;
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<ScrollView>
|
|
263
|
+
<UserHeader userId={userId} />
|
|
264
|
+
|
|
265
|
+
<View style={styles.section}>
|
|
266
|
+
<Text style={styles.label}>Account Status</Text>
|
|
267
|
+
<TierBadge tier={tier} />
|
|
268
|
+
</View>
|
|
269
|
+
|
|
270
|
+
{isPremium && (
|
|
271
|
+
<View style={styles.section}>
|
|
272
|
+
<Text style={styles.label}>Premium Benefits</Text>
|
|
273
|
+
<BenefitList />
|
|
274
|
+
</View>
|
|
275
|
+
)}
|
|
276
|
+
|
|
277
|
+
{!isPremium && tier !== 'guest' && (
|
|
278
|
+
<View style={styles.section}>
|
|
279
|
+
<Button
|
|
280
|
+
onPress={() => navigation.navigate('Paywall')}
|
|
281
|
+
title="Upgrade to Premium"
|
|
282
|
+
/>
|
|
283
|
+
</View>
|
|
284
|
+
)}
|
|
285
|
+
|
|
286
|
+
{error && (
|
|
287
|
+
<ErrorBanner
|
|
288
|
+
message="Failed to load subscription status"
|
|
289
|
+
onRetry={() => refresh()}
|
|
290
|
+
/>
|
|
291
|
+
)}
|
|
292
|
+
</ScrollView>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Navigation Guard
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
function ProtectedScreen() {
|
|
301
|
+
const auth = useAuth();
|
|
302
|
+
const navigation = useNavigation();
|
|
303
|
+
|
|
304
|
+
const {
|
|
305
|
+
tier,
|
|
306
|
+
isLoading,
|
|
307
|
+
} = useUserTierWithRepository({
|
|
308
|
+
auth,
|
|
309
|
+
repository: subscriptionRepository,
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
useEffect(() => {
|
|
313
|
+
if (!isLoading && tier !== 'premium') {
|
|
314
|
+
navigation.replace('Paywall', {
|
|
315
|
+
returnTo: 'ProtectedScreen',
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}, [tier, isLoading]);
|
|
319
|
+
|
|
320
|
+
if (isLoading) return <LoadingScreen />;
|
|
321
|
+
if (tier !== 'premium') return null;
|
|
322
|
+
|
|
323
|
+
return <ProtectedContent />;
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Conditional Features
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
function TierBasedFeatures() {
|
|
331
|
+
const auth = useAuth();
|
|
332
|
+
|
|
333
|
+
const { tier } = useUserTierWithRepository({
|
|
334
|
+
auth,
|
|
335
|
+
repository: subscriptionRepository,
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
return (
|
|
339
|
+
<View>
|
|
340
|
+
{/* Available to everyone */}
|
|
341
|
+
<BasicFeature />
|
|
342
|
+
|
|
343
|
+
{/* Available to freemium and premium */}
|
|
344
|
+
{(tier === 'freemium' || tier === 'premium') && (
|
|
345
|
+
<AuthenticatedFeature />
|
|
346
|
+
)}
|
|
347
|
+
|
|
348
|
+
{/* Premium only */}
|
|
349
|
+
{tier === 'premium' && (
|
|
350
|
+
<PremiumFeature />
|
|
351
|
+
)}
|
|
352
|
+
</View>
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### With Analytics
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
function TierTracker() {
|
|
361
|
+
const auth = useAuth();
|
|
362
|
+
|
|
363
|
+
const { tier } = useUserTierWithRepository({
|
|
364
|
+
auth,
|
|
365
|
+
repository: subscriptionRepository,
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
const previousTier = useRef(tier);
|
|
369
|
+
|
|
370
|
+
useEffect(() => {
|
|
371
|
+
if (previousTier.current !== tier) {
|
|
372
|
+
analytics.track('tier_changed', {
|
|
373
|
+
from: previousTier.current,
|
|
374
|
+
to: tier,
|
|
375
|
+
timestamp: Date.now(),
|
|
376
|
+
});
|
|
377
|
+
previousTier.current = tier;
|
|
378
|
+
}
|
|
379
|
+
}, [tier]);
|
|
380
|
+
|
|
381
|
+
return <YourComponent />;
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## How It Works
|
|
386
|
+
|
|
387
|
+
### Automatic Fetching
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
// Mount with authenticated user
|
|
391
|
+
auth.user = { uid: 'user-123' }
|
|
392
|
+
auth.isAuthenticated = true
|
|
393
|
+
→ Fetch premium status from repository ✅
|
|
394
|
+
|
|
395
|
+
// Status returned
|
|
396
|
+
tier = 'premium'
|
|
397
|
+
isPremium = true
|
|
398
|
+
isLoading = false ✅
|
|
399
|
+
|
|
400
|
+
// User logs out
|
|
401
|
+
auth.user = null
|
|
402
|
+
auth.isAuthenticated = false
|
|
403
|
+
→ No fetch (guest users can't be premium) ✅
|
|
404
|
+
tier = 'guest'
|
|
405
|
+
isPremium = false ✅
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Guest Users
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
auth.user = null
|
|
412
|
+
auth.isGuest = true
|
|
413
|
+
auth.isAuthenticated = false
|
|
414
|
+
|
|
415
|
+
// Hook doesn't fetch for guests
|
|
416
|
+
tier = 'guest'
|
|
417
|
+
isPremium = false
|
|
418
|
+
isLoading = false (no fetch needed) ✅
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Abort Handling
|
|
422
|
+
|
|
423
|
+
The hook uses AbortController for race condition prevention:
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
// User changes quickly: A → B → A
|
|
427
|
+
// Only the last user's status is set
|
|
428
|
+
// Intermediate fetches are aborted ✅
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Best Practices
|
|
432
|
+
|
|
433
|
+
1. **Provide valid auth** - Ensure auth provider has correct state
|
|
434
|
+
2. **Handle loading** - Show loading during initial fetch
|
|
435
|
+
3. **Handle errors** - Display error messages and retry option
|
|
436
|
+
4. **Use refresh** - Call refresh when needed (e.g., after purchase)
|
|
437
|
+
5. **Check tier** - Use tier for feature gating
|
|
438
|
+
6. **Test transitions** - Verify guest → freemium → premium flows
|
|
439
|
+
7. **Cache appropriately** - Repository should handle caching
|
|
440
|
+
|
|
441
|
+
## Related Hooks
|
|
442
|
+
|
|
443
|
+
- **useUserTier** - Tier logic without repository
|
|
444
|
+
- **usePremium** - Premium status checking
|
|
445
|
+
- **useAuthGate** - Authentication gating
|
|
446
|
+
- **useSubscription** - Subscription details
|
|
447
|
+
|
|
448
|
+
## See Also
|
|
449
|
+
|
|
450
|
+
- [User Tier Guide](../../../docs/USER_TIER.md)
|
|
451
|
+
- [Repository Pattern](../../infrastructure/repositories/README.md)
|
|
452
|
+
- [Tier Utilities](../../utils/tierUtils.md)
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Screens
|
|
2
|
+
|
|
3
|
+
Tam ekran UI bileşenleri ve ekranlar.
|
|
4
|
+
|
|
5
|
+
## Bileşenler
|
|
6
|
+
|
|
7
|
+
- [SubscriptionDetailScreen](#subscriptiondetailscreen)
|
|
8
|
+
|
|
9
|
+
## SubscriptionDetailScreen
|
|
10
|
+
|
|
11
|
+
Abonelik detaylarını gösteren tam ekran bileşeni.
|
|
12
|
+
|
|
13
|
+
### Kullanım
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { SubscriptionDetailScreen } from '@umituz/react-native-subscription';
|
|
17
|
+
|
|
18
|
+
function App() {
|
|
19
|
+
return (
|
|
20
|
+
<Stack.Screen
|
|
21
|
+
name="SubscriptionDetail"
|
|
22
|
+
component={SubscriptionDetailScreen}
|
|
23
|
+
options={{
|
|
24
|
+
title: 'Subscription',
|
|
25
|
+
}}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Props
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
interface SubscriptionDetailScreenProps {
|
|
35
|
+
route: {
|
|
36
|
+
key: string;
|
|
37
|
+
name: string;
|
|
38
|
+
params?: {
|
|
39
|
+
userId?: string;
|
|
40
|
+
showUpgradeButton?: boolean;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
navigation: any;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Özellikler
|
|
48
|
+
|
|
49
|
+
- Abonelik durumunu gösterir
|
|
50
|
+
- Paket detaylarını görüntüler
|
|
51
|
+
- Yönetim butonları sağlar
|
|
52
|
+
- Refresh desteği
|
|
53
|
+
- Yönetilebilir stil
|
|
54
|
+
|
|
55
|
+
## Ekran Akışları
|
|
56
|
+
|
|
57
|
+
### 1. Settings → Subscription Detail
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
function SettingsScreen({ navigation }) {
|
|
61
|
+
return (
|
|
62
|
+
<View>
|
|
63
|
+
<Button
|
|
64
|
+
onPress={() => navigation.navigate('SubscriptionDetail')}
|
|
65
|
+
title="Manage Subscription"
|
|
66
|
+
/>
|
|
67
|
+
</View>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Paywall → Subscription Detail
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
function PaywallFlow() {
|
|
76
|
+
const navigation = useNavigation();
|
|
77
|
+
|
|
78
|
+
const handlePurchaseSuccess = () => {
|
|
79
|
+
navigation.navigate('SubscriptionDetail');
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<PaywallModal onPurchase={handlePurchaseSuccess} />
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Özelleştirme
|
|
89
|
+
|
|
90
|
+
### Custom Header
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
<Stack.Screen
|
|
94
|
+
name="SubscriptionDetail"
|
|
95
|
+
component={SubscriptionDetailScreen}
|
|
96
|
+
options={{
|
|
97
|
+
title: 'My Subscription',
|
|
98
|
+
headerStyle: {
|
|
99
|
+
backgroundColor: '#FF6B6B',
|
|
100
|
+
},
|
|
101
|
+
headerTintColor: '#fff',
|
|
102
|
+
headerTitleStyle: {
|
|
103
|
+
fontWeight: 'bold',
|
|
104
|
+
},
|
|
105
|
+
}}
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Navigation Integrasyonu
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { createStackNavigator } from '@react-navigation/stack';
|
|
113
|
+
|
|
114
|
+
const Stack = createStackNavigator();
|
|
115
|
+
|
|
116
|
+
function SubscriptionStack() {
|
|
117
|
+
return (
|
|
118
|
+
<Stack.Navigator>
|
|
119
|
+
<Stack.Screen
|
|
120
|
+
name="SubscriptionDetail"
|
|
121
|
+
component={SubscriptionDetailScreen}
|
|
122
|
+
options={{
|
|
123
|
+
title: 'Subscription',
|
|
124
|
+
headerRight: () => (
|
|
125
|
+
<Button onPress={handleRefresh} title="Refresh" />
|
|
126
|
+
),
|
|
127
|
+
}}
|
|
128
|
+
/>
|
|
129
|
+
</Stack.Navigator>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Örnek Implementasyon
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import React from 'react';
|
|
138
|
+
import { createStackNavigator } from '@react-navigation/stack';
|
|
139
|
+
import { SubscriptionDetailScreen } from '@umituz/react-native-subscription';
|
|
140
|
+
|
|
141
|
+
const Stack = createStackNavigator();
|
|
142
|
+
|
|
143
|
+
function App() {
|
|
144
|
+
return (
|
|
145
|
+
<NavigationContainer>
|
|
146
|
+
<Stack.Navigator
|
|
147
|
+
screenOptions={{
|
|
148
|
+
headerShown: true,
|
|
149
|
+
cardStyle: { backgroundColor: '#f5f5f5' },
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
<Stack.Screen
|
|
153
|
+
name="Home"
|
|
154
|
+
component={HomeScreen}
|
|
155
|
+
options={{ title: 'Home' }}
|
|
156
|
+
/>
|
|
157
|
+
<Stack.Screen
|
|
158
|
+
name="SubscriptionDetail"
|
|
159
|
+
component={SubscriptionDetailScreen}
|
|
160
|
+
options={{
|
|
161
|
+
title: 'My Subscription',
|
|
162
|
+
headerStyle: {
|
|
163
|
+
backgroundColor: '#FF6B6B',
|
|
164
|
+
},
|
|
165
|
+
headerTintColor: '#fff',
|
|
166
|
+
}}
|
|
167
|
+
/>
|
|
168
|
+
</Stack.Navigator>
|
|
169
|
+
</NavigationContainer>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function HomeScreen({ navigation }) {
|
|
174
|
+
const { isPremium } = usePremium();
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<View>
|
|
178
|
+
<Text>Welcome!</Text>
|
|
179
|
+
<Button
|
|
180
|
+
onPress={() => navigation.navigate('SubscriptionDetail')}
|
|
181
|
+
title="View Subscription"
|
|
182
|
+
/>
|
|
183
|
+
</View>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Best Practices
|
|
189
|
+
|
|
190
|
+
1. **Navigation**: Screen'i doğru navigation stack'e ekleyin
|
|
191
|
+
2. **Header**: Uygun başlık ve stiller kullanın
|
|
192
|
+
3. **Back Button**: Kullanıcının geri dönmesini sağlayın
|
|
193
|
+
4. **Loading**: Yükleme durumlarını gösterin
|
|
194
|
+
5. **Error**: Hata durumlarını graceful handle edin
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Presentation Types
|
|
2
|
+
|
|
3
|
+
TypeScript type definitions and interfaces for the presentation layer.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This directory contains all type definitions used by presentation components and hooks.
|
|
8
|
+
|
|
9
|
+
## Contents
|
|
10
|
+
|
|
11
|
+
### Subscription Types
|
|
12
|
+
|
|
13
|
+
- **SubscriptionSettingsTypes.ts** - Configuration types for subscription settings UI
|
|
14
|
+
- **PaywallTypes.ts** - Paywall component types
|
|
15
|
+
- **SubscriptionTypes.ts** - General subscription UI types
|
|
16
|
+
|
|
17
|
+
## Key Exports
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Subscription Settings
|
|
21
|
+
export type {
|
|
22
|
+
SubscriptionSettingsConfig,
|
|
23
|
+
SubscriptionSettingsItemConfig,
|
|
24
|
+
SubscriptionSettingsTranslations,
|
|
25
|
+
} from './SubscriptionSettingsTypes';
|
|
26
|
+
|
|
27
|
+
// Paywall
|
|
28
|
+
export type {
|
|
29
|
+
PaywallConfig,
|
|
30
|
+
PaywallTrigger,
|
|
31
|
+
PaywallPackage,
|
|
32
|
+
} from './PaywallTypes';
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Related
|
|
36
|
+
|
|
37
|
+
- [Hooks](../hooks/README.md)
|
|
38
|
+
- [Components](../components/README.md)
|