@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.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +462 -0
  3. package/package.json +1 -3
  4. package/src/application/README.md +229 -0
  5. package/src/application/ports/README.md +103 -0
  6. package/src/domain/README.md +402 -0
  7. package/src/domain/constants/README.md +80 -0
  8. package/src/domain/entities/README.md +176 -0
  9. package/src/domain/errors/README.md +307 -0
  10. package/src/domain/value-objects/README.md +186 -0
  11. package/src/domains/config/README.md +390 -0
  12. package/src/domains/paywall/README.md +371 -0
  13. package/src/domains/paywall/components/PaywallHeader.tsx +8 -11
  14. package/src/domains/paywall/components/README.md +185 -0
  15. package/src/domains/paywall/entities/README.md +199 -0
  16. package/src/domains/paywall/hooks/README.md +129 -0
  17. package/src/domains/wallet/README.md +292 -0
  18. package/src/domains/wallet/domain/README.md +108 -0
  19. package/src/domains/wallet/domain/entities/README.md +122 -0
  20. package/src/domains/wallet/domain/errors/README.md +157 -0
  21. package/src/domains/wallet/infrastructure/README.md +96 -0
  22. package/src/domains/wallet/presentation/components/BalanceCard.tsx +6 -12
  23. package/src/domains/wallet/presentation/components/README.md +231 -0
  24. package/src/domains/wallet/presentation/hooks/README.md +255 -0
  25. package/src/infrastructure/README.md +514 -0
  26. package/src/infrastructure/mappers/README.md +34 -0
  27. package/src/infrastructure/models/README.md +26 -0
  28. package/src/infrastructure/repositories/README.md +385 -0
  29. package/src/infrastructure/services/README.md +374 -0
  30. package/src/presentation/README.md +410 -0
  31. package/src/presentation/components/README.md +183 -0
  32. package/src/presentation/components/details/CreditRow.md +337 -0
  33. package/src/presentation/components/details/DetailRow.md +283 -0
  34. package/src/presentation/components/details/PremiumDetailsCard.md +266 -0
  35. package/src/presentation/components/details/PremiumStatusBadge.md +266 -0
  36. package/src/presentation/components/details/README.md +449 -0
  37. package/src/presentation/components/feedback/PaywallFeedbackModal.md +314 -0
  38. package/src/presentation/components/feedback/README.md +447 -0
  39. package/src/presentation/components/paywall/PaywallModal.md +444 -0
  40. package/src/presentation/components/paywall/README.md +190 -0
  41. package/src/presentation/components/sections/README.md +468 -0
  42. package/src/presentation/components/sections/SubscriptionSection.md +246 -0
  43. package/src/presentation/hooks/README.md +743 -0
  44. package/src/presentation/hooks/useAuthAwarePurchase.md +359 -0
  45. package/src/presentation/hooks/useAuthGate.md +403 -0
  46. package/src/presentation/hooks/useAuthSubscriptionSync.md +398 -0
  47. package/src/presentation/hooks/useCreditChecker.md +407 -0
  48. package/src/presentation/hooks/useCredits.md +342 -0
  49. package/src/presentation/hooks/useCreditsGate.md +346 -0
  50. package/src/presentation/hooks/useDeductCredit.md +160 -0
  51. package/src/presentation/hooks/useDevTestCallbacks.md +422 -0
  52. package/src/presentation/hooks/useFeatureGate.md +157 -0
  53. package/src/presentation/hooks/useInitializeCredits.md +458 -0
  54. package/src/presentation/hooks/usePaywall.md +334 -0
  55. package/src/presentation/hooks/usePaywallOperations.md +486 -0
  56. package/src/presentation/hooks/usePaywallVisibility.md +344 -0
  57. package/src/presentation/hooks/usePremium.md +230 -0
  58. package/src/presentation/hooks/usePremiumGate.md +423 -0
  59. package/src/presentation/hooks/usePremiumWithCredits.md +429 -0
  60. package/src/presentation/hooks/useSubscription.md +450 -0
  61. package/src/presentation/hooks/useSubscriptionDetails.md +438 -0
  62. package/src/presentation/hooks/useSubscriptionGate.md +168 -0
  63. package/src/presentation/hooks/useSubscriptionSettingsConfig.md +374 -0
  64. package/src/presentation/hooks/useSubscriptionStatus.md +424 -0
  65. package/src/presentation/hooks/useUserTier.md +356 -0
  66. package/src/presentation/hooks/useUserTierWithRepository.md +452 -0
  67. package/src/presentation/screens/README.md +194 -0
  68. package/src/presentation/types/README.md +38 -0
  69. package/src/presentation/utils/README.md +52 -0
  70. package/src/revenuecat/README.md +523 -0
  71. package/src/revenuecat/domain/README.md +147 -0
  72. package/src/revenuecat/domain/errors/README.md +197 -0
  73. package/src/revenuecat/infrastructure/config/README.md +40 -0
  74. package/src/revenuecat/infrastructure/managers/README.md +49 -0
  75. package/src/revenuecat/presentation/hooks/README.md +56 -0
  76. package/src/utils/README.md +529 -0
@@ -0,0 +1,424 @@
1
+ # useSubscriptionStatus Hook
2
+
3
+ Hook for accessing detailed subscription status information.
4
+
5
+ ## Import
6
+
7
+ ```typescript
8
+ import { useSubscriptionStatus } from '@umituz/react-native-subscription';
9
+ ```
10
+
11
+ ## Signature
12
+
13
+ ```typescript
14
+ function useSubscriptionStatus(): {
15
+ status: SubscriptionStatus | null;
16
+ tier: UserTier;
17
+ isActive: boolean;
18
+ isExpired: boolean;
19
+ willRenew: boolean;
20
+ expirationDate: Date | null;
21
+ daysUntilExpiration: number | null;
22
+ isLoading: boolean;
23
+ error: Error | null;
24
+ refetch: () => Promise<void>;
25
+ }
26
+ ```
27
+
28
+ ## Returns
29
+
30
+ | Property | Type | Description |
31
+ |----------|------|-------------|
32
+ | `status` | `SubscriptionStatus \| null` | Full status object |
33
+ | `tier` | `UserTier` | User tier (guest/free/premium) |
34
+ | `isActive` | `boolean` | Subscription is currently active |
35
+ | `isExpired` | `boolean` | Subscription has expired |
36
+ | `willRenew` | `boolean` | Subscription will auto-renew |
37
+ | `expirationDate` | `Date \| null` | When subscription expires |
38
+ | `daysUntilExpiration` | `number \| null` | Days until expiration |
39
+ | `isLoading` | `boolean` | Loading state |
40
+ | `error` | `Error \| null` | Error if any |
41
+
42
+ ## Basic Usage
43
+
44
+ ```typescript
45
+ function SubscriptionStatusDisplay() {
46
+ const {
47
+ status,
48
+ tier,
49
+ isActive,
50
+ expirationDate,
51
+ daysUntilExpiration,
52
+ isLoading,
53
+ } = useSubscriptionStatus();
54
+
55
+ if (isLoading) return <ActivityIndicator />;
56
+
57
+ return (
58
+ <View>
59
+ <Text>Tier: {tier}</Text>
60
+ <Text>Status: {isActive ? 'Active' : 'Inactive'}</Text>
61
+
62
+ {expirationDate && (
63
+ <Text>
64
+ Expires: {expirationDate.toLocaleDateString()}
65
+ ({daysUntilExpiration} days)
66
+ </Text>
67
+ )}
68
+ </View>
69
+ );
70
+ }
71
+ ```
72
+
73
+ ## Advanced Usage
74
+
75
+ ### With Expiration Warning
76
+
77
+ ```typescript
78
+ function ExpirationWarning() {
79
+ const { daysUntilExpiration, willRenew } = useSubscriptionStatus();
80
+
81
+ if (willRenew) {
82
+ return <Text>Auto-renewal is on</Text>;
83
+ }
84
+
85
+ if (daysUntilExpiration === null) {
86
+ return null;
87
+ }
88
+
89
+ if (daysUntilExpiration <= 3) {
90
+ return (
91
+ <WarningCard
92
+ type={daysUntilExpiration <= 1 ? 'critical' : 'warning'}
93
+ message={`Your subscription expires in ${daysUntilExpiration} day${daysUntilExpiration > 1 ? 's' : ''}`}
94
+ />
95
+ );
96
+ }
97
+
98
+ if (daysUntilExpiration <= 7) {
99
+ return <InfoCard message={`Subscription expires in ${daysUntilExpiration} days`} />;
100
+ }
101
+
102
+ return null;
103
+ }
104
+ ```
105
+
106
+ ### With Status Badge
107
+
108
+ ```typescript
109
+ function StatusBadge() {
110
+ const { isActive, isExpired } = useSubscriptionStatus();
111
+
112
+ const getStatusConfig = () => {
113
+ if (isExpired) {
114
+ return { color: 'red', icon: '⚠️', text: 'Expired' };
115
+ }
116
+ if (isActive) {
117
+ return { color: 'green', icon: '✅', text: 'Active' };
118
+ }
119
+ return { color: 'gray', icon: '⏸️', text: 'Inactive' };
120
+ };
121
+
122
+ const config = getStatusConfig();
123
+
124
+ return (
125
+ <View style={[styles.badge, { backgroundColor: config.color }]}>
126
+ <Text>{config.icon}</Text>
127
+ <Text>{config.text}</Text>
128
+ </View>
129
+ );
130
+ }
131
+ ```
132
+
133
+ ### With Auto-Refresh
134
+
135
+ ```typescript
136
+ function AutoRefreshStatus() {
137
+ const { status, refetch, isLoading } = useSubscriptionStatus();
138
+
139
+ // Refetch every 5 minutes
140
+ useEffect(() => {
141
+ const interval = setInterval(() => {
142
+ refetch();
143
+ }, 5 * 60 * 1000);
144
+
145
+ return () => clearInterval(interval);
146
+ }, [refetch]);
147
+
148
+ // Refetch when app comes to foreground
149
+ useFocusEffect(
150
+ useCallback(() => {
151
+ refetch();
152
+ }, [refetch])
153
+ );
154
+
155
+ return (
156
+ <View>
157
+ <Text>Status: {status?.type}</Text>
158
+ <Button
159
+ onPress={refetch}
160
+ disabled={isLoading}
161
+ title="Refresh"
162
+ />
163
+ </View>
164
+ );
165
+ }
166
+ ```
167
+
168
+ ### With Detailed Info Card
169
+
170
+ ```typescript
171
+ function DetailedSubscriptionCard() {
172
+ const {
173
+ status,
174
+ tier,
175
+ isActive,
176
+ willRenew,
177
+ expirationDate,
178
+ daysUntilExpiration,
179
+ } = useSubscriptionStatus();
180
+
181
+ if (!status) return null;
182
+
183
+ return (
184
+ <Card style={styles.card}>
185
+ <View style={styles.header}>
186
+ <Badge tier={tier} />
187
+ <Badge
188
+ variant={isActive ? 'success' : 'default'}
189
+ text={isActive ? 'Active' : 'Inactive'}
190
+ />
191
+ </View>
192
+
193
+ <Divider />
194
+
195
+ <View style={styles.section}>
196
+ <DetailRow
197
+ label="Plan"
198
+ value={status.productId?.replace('_', ' ').toUpperCase()}
199
+ />
200
+ <DetailRow
201
+ label="Auto-renew"
202
+ value={willRenew ? 'Enabled' : 'Disabled'}
203
+ />
204
+ </View>
205
+
206
+ {expirationDate && (
207
+ <>
208
+ <Divider />
209
+ <View style={styles.section}>
210
+ <DetailRow
211
+ label="Expires"
212
+ value={expirationDate.toLocaleDateString()}
213
+ />
214
+ {daysUntilExpiration !== null && (
215
+ <DetailRow
216
+ label="Days remaining"
217
+ value={daysUntilExpiration.toString()}
218
+ />
219
+ )}
220
+ </View>
221
+ </>
222
+ )}
223
+
224
+ {daysUntilExpiration !== null &&
225
+ daysUntilExpiration <= 7 && (
226
+ <Alert
227
+ severity={daysUntilExpiration <= 3 ? 'warning' : 'info'}
228
+ message={`Subscription expires in ${daysUntilExpiration} days`}
229
+ />
230
+ )}
231
+ </Card>
232
+ );
233
+ }
234
+ ```
235
+
236
+ ## Examples
237
+
238
+ ### Subscription Countdown
239
+
240
+ ```typescript
241
+ function SubscriptionCountdown() {
242
+ const { expirationDate, daysUntilExpiration, isActive } =
243
+ useSubscriptionStatus();
244
+
245
+ if (!isActive || !expirationDate) {
246
+ return null;
247
+ }
248
+
249
+ const [timeLeft, setTimeLeft] = useState('');
250
+
251
+ useEffect(() => {
252
+ const updateCountdown = () => {
253
+ const now = new Date();
254
+ const diff = expirationDate.getTime() - now.getTime();
255
+
256
+ if (diff <= 0) {
257
+ setTimeLeft('Expired');
258
+ return;
259
+ }
260
+
261
+ const days = Math.floor(diff / (1000 * 60 * 60 * 24));
262
+ const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
263
+ const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
264
+
265
+ setTimeLeft(`${days}d ${hours}h ${minutes}m`);
266
+ };
267
+
268
+ updateCountdown();
269
+ const interval = setInterval(updateCountdown, 60000); // Every minute
270
+
271
+ return () => clearInterval(interval);
272
+ }, [expirationDate]);
273
+
274
+ return (
275
+ <View style={styles.countdown}>
276
+ <Text>Expires in:</Text>
277
+ <Text style={styles.timeLeft}>{timeLeft}</Text>
278
+ </View>
279
+ );
280
+ }
281
+ ```
282
+
283
+ ### Status History Tracker
284
+
285
+ ```typescript
286
+ function StatusHistoryTracker() {
287
+ const { status } = useSubscriptionStatus();
288
+ const previousStatus = useRef(status);
289
+
290
+ useEffect(() => {
291
+ if (previousStatus.current?.type !== status?.type) {
292
+ analytics.track('subscription_status_changed', {
293
+ from: previousStatus.current?.type,
294
+ to: status?.type,
295
+ timestamp: Date.now(),
296
+ });
297
+
298
+ // Log to database for audit trail
299
+ logStatusChange(previousStatus.current, status);
300
+ }
301
+
302
+ previousStatus.current = status;
303
+ }, [status]);
304
+
305
+ return null;
306
+ }
307
+ ```
308
+
309
+ ### Lifecycle Management
310
+
311
+ ```typescript
312
+ function SubscriptionLifecycleManager() {
313
+ const { status, isActive, daysUntilExpiration, willRenew } =
314
+ useSubscriptionStatus();
315
+
316
+ useEffect(() => {
317
+ if (!isActive) {
318
+ return;
319
+ }
320
+
321
+ // Expiration warning
322
+ if (daysUntilExpiration === 3) {
323
+ notifications.send({
324
+ title: 'Subscription Expiring Soon',
325
+ body: 'Your subscription expires in 3 days',
326
+ });
327
+ }
328
+
329
+ // Renewal reminder
330
+ if (daysUntilExpiration === 1 && !willRenew) {
331
+ notifications.send({
332
+ title: 'Last Chance!',
333
+ body: 'Your subscription expires tomorrow. Renew now to maintain access.',
334
+ });
335
+ }
336
+ }, [daysUntilExpiration, willRenew, isActive]);
337
+
338
+ return null;
339
+ }
340
+ ```
341
+
342
+ ## State Machine
343
+
344
+ ```typescript
345
+ function SubscriptionStateMachine() {
346
+ const { status, isActive, isExpired } = useSubscriptionStatus();
347
+
348
+ const getState = () => {
349
+ if (!status) return 'unknown';
350
+ if (!isActive) return 'inactive';
351
+ if (isExpired) return 'expired';
352
+ return 'active';
353
+ };
354
+
355
+ const state = getState();
356
+
357
+ switch (state) {
358
+ case 'unknown':
359
+ return <LoadingState />;
360
+ case 'inactive':
361
+ return <UpgradePrompt />;
362
+ case 'expired':
363
+ return <RenewPrompt />;
364
+ case 'active':
365
+ return <PremiumContent />;
366
+ default:
367
+ return null;
368
+ }
369
+ }
370
+ ```
371
+
372
+ ## Visual Status Indicator
373
+
374
+ ```typescript
375
+ function StatusIndicator() {
376
+ const { isActive, isExpired, willRenew } = useSubscriptionStatus();
377
+
378
+ const getStatusColor = () => {
379
+ if (isExpired) return '#F44336'; // red
380
+ if (isActive) return '#4CAF50'; // green
381
+ return '#9E9E9E'; // gray
382
+ };
383
+
384
+ const getStatusIcon = () => {
385
+ if (isExpired) return '⚠️';
386
+ if (isActive && willRenew) return '♻️';
387
+ if (isActive && !willRenew) return '⏳';
388
+ return '⏸️';
389
+ };
390
+
391
+ return (
392
+ <View style={[styles.indicator, { borderColor: getStatusColor() }]}>
393
+ <Text>{getStatusIcon()}</Text>
394
+ <ActivityIndicator
395
+ size={8}
396
+ color={getStatusColor()}
397
+ animating={isActive}
398
+ />
399
+ </View>
400
+ );
401
+ }
402
+ ```
403
+
404
+ ## Best Practices
405
+
406
+ 1. **Handle null status** - Check if status exists
407
+ 2. **Show expiration warnings** - Remind users before expiry
408
+ 3. **Display renewal status** - Show if auto-renew is on/off
409
+ 4. **Track changes** - Monitor status transitions
410
+ 5. **Refresh regularly** - Keep status up to date
411
+ 6. **Handle errors** - Show user-friendly error messages
412
+
413
+ ## Related Hooks
414
+
415
+ - **usePremium** - Simple premium check
416
+ - **useSubscription** - Subscription details
417
+ - **useSubscriptionDetails** - Package and plan info
418
+ - **useUserTier** - Tier information
419
+
420
+ ## See Also
421
+
422
+ - [SubscriptionStatus Entity](../../domain/entities/README.md)
423
+ - [usePremium](./usePremium.md)
424
+ - [useUserTier](./useUserTier.md)