@umituz/react-native-subscription 2.14.98 → 2.14.100

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 (92) hide show
  1. package/README.md +211 -395
  2. package/package.json +1 -1
  3. package/src/application/README.md +46 -225
  4. package/src/application/ports/README.md +42 -97
  5. package/src/domain/README.md +36 -384
  6. package/src/domain/constants/README.md +0 -56
  7. package/src/domain/entities/README.md +43 -169
  8. package/src/domain/errors/README.md +33 -287
  9. package/src/domain/value-objects/README.md +43 -179
  10. package/src/domains/README.md +52 -0
  11. package/src/domains/README.md.bak +274 -0
  12. package/src/domains/config/README.md +93 -383
  13. package/src/domains/config/domain/README.md +37 -0
  14. package/src/domains/config/domain/entities/README.md +41 -0
  15. package/src/domains/paywall/README.md +99 -369
  16. package/src/domains/paywall/components/README.md +34 -178
  17. package/src/domains/paywall/entities/README.md +34 -193
  18. package/src/domains/paywall/hooks/README.md +34 -122
  19. package/src/domains/wallet/README.md +34 -275
  20. package/src/domains/wallet/README.md.bak +209 -0
  21. package/src/domains/wallet/domain/README.md +34 -101
  22. package/src/domains/wallet/domain/entities/README.md +34 -115
  23. package/src/domains/wallet/domain/errors/README.md +34 -151
  24. package/src/domains/wallet/infrastructure/README.md +34 -89
  25. package/src/domains/wallet/presentation/components/README.md +34 -224
  26. package/src/domains/wallet/presentation/hooks/README.md +34 -248
  27. package/src/infrastructure/README.md +37 -496
  28. package/src/infrastructure/mappers/README.md +0 -13
  29. package/src/infrastructure/repositories/README.md +74 -360
  30. package/src/infrastructure/services/README.md +95 -370
  31. package/src/presentation/README.md +123 -408
  32. package/src/presentation/README.md.bak +172 -0
  33. package/src/presentation/components/README.md +151 -179
  34. package/src/presentation/components/README.md.bak +217 -0
  35. package/src/presentation/components/details/CreditRow.md +65 -310
  36. package/src/presentation/components/details/DetailRow.md +63 -255
  37. package/src/presentation/components/details/PremiumDetailsCard.md +65 -238
  38. package/src/presentation/components/details/PremiumStatusBadge.md +64 -239
  39. package/src/presentation/components/details/README.md +97 -447
  40. package/src/presentation/components/feedback/PaywallFeedbackModal.md +63 -287
  41. package/src/presentation/components/feedback/README.md +97 -445
  42. package/src/presentation/components/paywall/PaywallModal.md +66 -416
  43. package/src/presentation/components/paywall/README.md +50 -186
  44. package/src/presentation/components/sections/README.md +97 -466
  45. package/src/presentation/components/sections/SubscriptionSection.md +92 -244
  46. package/src/presentation/hooks/README.md +154 -741
  47. package/src/presentation/hooks/useAuthAwarePurchase.md +58 -325
  48. package/src/presentation/hooks/useAuthGate.md +61 -375
  49. package/src/presentation/hooks/useAuthSubscriptionSync.md +66 -370
  50. package/src/presentation/hooks/useCreditChecker.md +73 -378
  51. package/src/presentation/hooks/useCredits.md +74 -313
  52. package/src/presentation/hooks/useCredits.md.bak +231 -0
  53. package/src/presentation/hooks/useCreditsGate.md +66 -318
  54. package/src/presentation/hooks/useDeductCredit.md +96 -156
  55. package/src/presentation/hooks/useDevTestCallbacks.md +63 -394
  56. package/src/presentation/hooks/useFeatureGate.md +105 -150
  57. package/src/presentation/hooks/useFeatureGate.md.bak +284 -0
  58. package/src/presentation/hooks/useInitializeCredits.md +64 -430
  59. package/src/presentation/hooks/usePaywall.md +61 -306
  60. package/src/presentation/hooks/usePaywallOperations.md +64 -458
  61. package/src/presentation/hooks/usePaywallVisibility.md +67 -316
  62. package/src/presentation/hooks/usePremium.md +84 -226
  63. package/src/presentation/hooks/usePremiumGate.md +60 -395
  64. package/src/presentation/hooks/usePremiumWithCredits.md +64 -401
  65. package/src/presentation/hooks/useSubscription.md +66 -422
  66. package/src/presentation/hooks/useSubscriptionDetails.md +65 -410
  67. package/src/presentation/hooks/useSubscriptionGate.md +80 -164
  68. package/src/presentation/hooks/useSubscriptionSettingsConfig.md +66 -346
  69. package/src/presentation/hooks/useSubscriptionStatus.md +66 -396
  70. package/src/presentation/hooks/useUserTier.md +63 -328
  71. package/src/presentation/hooks/useUserTierWithRepository.md +64 -424
  72. package/src/presentation/screens/README.md +48 -190
  73. package/src/presentation/types/README.md +0 -16
  74. package/src/presentation/utils/README.md +0 -21
  75. package/src/revenuecat/README.md +99 -518
  76. package/src/revenuecat/application/README.md +43 -0
  77. package/src/revenuecat/application/ports/README.md +41 -0
  78. package/src/revenuecat/domain/README.md +42 -141
  79. package/src/revenuecat/domain/constants/README.md +41 -0
  80. package/src/revenuecat/domain/entities/README.md +42 -0
  81. package/src/revenuecat/domain/errors/README.md +47 -191
  82. package/src/revenuecat/domain/types/README.md +41 -0
  83. package/src/revenuecat/domain/value-objects/README.md +41 -0
  84. package/src/revenuecat/infrastructure/README.md +41 -0
  85. package/src/revenuecat/infrastructure/config/README.md +32 -23
  86. package/src/revenuecat/infrastructure/handlers/README.md +41 -0
  87. package/src/revenuecat/infrastructure/managers/README.md +34 -42
  88. package/src/revenuecat/infrastructure/services/README.md +42 -0
  89. package/src/revenuecat/infrastructure/utils/README.md +41 -0
  90. package/src/revenuecat/presentation/README.md +42 -0
  91. package/src/revenuecat/presentation/hooks/README.md +29 -35
  92. package/src/utils/README.md +38 -525
@@ -2,423 +2,93 @@
2
2
 
3
3
  Hook for accessing detailed subscription status information.
4
4
 
5
- ## Import
5
+ ## Location
6
6
 
7
- ```typescript
8
- import { useSubscriptionStatus } from '@umituz/react-native-subscription';
9
- ```
7
+ **Import Path**: `@umituz/react-native-subscription`
10
8
 
11
- ## Signature
9
+ **File**: `src/presentation/hooks/useSubscriptionStatus.ts`
12
10
 
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
- ```
11
+ **Type**: Hook
27
12
 
28
- ## Returns
13
+ ## Strategy
29
14
 
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 |
15
+ ### Subscription Status Flow
41
16
 
42
- ## Basic Usage
17
+ 1. **Status Fetch**: Retrieve current subscription status from repository
18
+ 2. **Status Parsing**: Extract tier, active state, expiration info
19
+ 3. **Real-time Updates**: Update when subscription changes
20
+ 4. **Expiration Tracking**: Calculate days until expiration
21
+ 5. **Renewal Status**: Determine if subscription will auto-renew
22
+ 6. **Caching**: Cache status for performance (5 min default)
43
23
 
44
- ```typescript
45
- function SubscriptionStatusDisplay() {
46
- const {
47
- status,
48
- tier,
49
- isActive,
50
- expirationDate,
51
- daysUntilExpiration,
52
- isLoading,
53
- } = useSubscriptionStatus();
24
+ ### Integration Points
54
25
 
55
- if (isLoading) return <ActivityIndicator />;
26
+ - **Subscription Repository**: `src/infrastructure/repositories/SubscriptionRepository.ts`
27
+ - **SubscriptionStatus Entity**: `src/domain/entities/README.md`
28
+ - **TanStack Query**: For caching and real-time updates
29
+ - **RevenueCat**: For subscription data source
56
30
 
57
- return (
58
- <View>
59
- <Text>Tier: {tier}</Text>
60
- <Text>Status: {isActive ? 'Active' : 'Inactive'}</Text>
31
+ ## Restrictions
61
32
 
62
- {expirationDate && (
63
- <Text>
64
- Expires: {expirationDate.toLocaleDateString()}
65
- ({daysUntilExpiration} days)
66
- </Text>
67
- )}
68
- </View>
69
- );
70
- }
71
- ```
33
+ ### REQUIRED
72
34
 
73
- ## Advanced Usage
35
+ - **Loading State**: MUST handle loading state
36
+ - **Error Handling**: MUST handle error state
37
+ - **Null Check**: MUST handle null status (guest users)
38
+ - **Expiration**: SHOULD warn users before expiration
74
39
 
75
- ### With Expiration Warning
40
+ ### PROHIBITED
76
41
 
77
- ```typescript
78
- function ExpirationWarning() {
79
- const { daysUntilExpiration, willRenew } = useSubscriptionStatus();
42
+ - **NEVER** assume status exists (check for null)
43
+ - **NEVER** use for security decisions without server validation
44
+ - **DO NOT** show expiration for lifetime subscriptions
45
+ - **DO NOT** cache beyond configured time
80
46
 
81
- if (willRenew) {
82
- return <Text>Auto-renewal is on</Text>;
83
- }
47
+ ### CRITICAL SAFETY
84
48
 
85
- if (daysUntilExpiration === null) {
86
- return null;
87
- }
49
+ - **ALWAYS** check if status is null before accessing properties
50
+ - **NEVER** trust client-side status for security
51
+ - **MUST** implement error boundaries
52
+ - **ALWAYS** refresh status when app comes to foreground
88
53
 
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
- }
54
+ ## AI Agent Guidelines
97
55
 
98
- if (daysUntilExpiration <= 7) {
99
- return <InfoCard message={`Subscription expires in ${daysUntilExpiration} days`} />;
100
- }
56
+ ### When Displaying Subscription Info
101
57
 
102
- return null;
103
- }
104
- ```
58
+ 1. **Always** check for null status (guest users)
59
+ 2. **Always** handle loading and error states
60
+ 3. **Always** show expiration warnings
61
+ 4. **Always** display auto-renewal status
62
+ 5. **Never** show technical details to end users
105
63
 
106
- ### With Status Badge
64
+ ### Integration Checklist
107
65
 
108
- ```typescript
109
- function StatusBadge() {
110
- const { isActive, isExpired } = useSubscriptionStatus();
66
+ - [ ] Import from correct path: `@umituz/react-native-subscription`
67
+ - [ ] Handle loading state
68
+ - [ ] Handle error state
69
+ - [ ] Check for null status (guest users)
70
+ - [ ] Display subscription tier
71
+ - [ ] Show expiration date
72
+ - [ ] Show days until expiration
73
+ - [ ] Show auto-renewal status
74
+ - [ ] Implement expiration warnings
75
+ - [ ] Test with active subscription
76
+ - [ ] Test with expired subscription
77
+ - [ ] Test with guest user (null status)
111
78
 
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
- };
79
+ ### Common Patterns
121
80
 
122
- const config = getStatusConfig();
81
+ 1. **Status Badge**: Visual indicator of subscription status
82
+ 2. **Expiration Countdown**: Days remaining until expiration
83
+ 3. **Warning System**: Notify users before expiration
84
+ 4. **Detail Card**: Comprehensive subscription information
85
+ 5. **Lifecycle Management**: Handle subscription events
123
86
 
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
- ```
87
+ ## Related Documentation
132
88
 
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)
89
+ - **usePremium**: Simple premium status check
90
+ - **useSubscription**: Detailed subscription information
91
+ - **useSubscriptionDetails**: Package and feature details
92
+ - **useUserTier**: Tier information
93
+ - **SubscriptionStatus Entity**: `src/domain/entities/README.md`
94
+ - **Subscription Repository**: `src/infrastructure/repositories/README.md`