@umituz/react-native-subscription 2.14.99 → 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 -394
  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 +50 -238
  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 +23 -376
  14. package/src/domains/config/domain/entities/README.md +34 -343
  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 +0 -76
  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 +35 -150
  77. package/src/revenuecat/application/ports/README.md +34 -162
  78. package/src/revenuecat/domain/README.md +42 -141
  79. package/src/revenuecat/domain/constants/README.md +34 -176
  80. package/src/revenuecat/domain/entities/README.md +34 -374
  81. package/src/revenuecat/domain/errors/README.md +47 -191
  82. package/src/revenuecat/domain/types/README.md +34 -366
  83. package/src/revenuecat/domain/value-objects/README.md +34 -434
  84. package/src/revenuecat/infrastructure/README.md +34 -43
  85. package/src/revenuecat/infrastructure/config/README.md +32 -23
  86. package/src/revenuecat/infrastructure/handlers/README.md +34 -211
  87. package/src/revenuecat/infrastructure/managers/README.md +34 -42
  88. package/src/revenuecat/infrastructure/services/README.md +35 -318
  89. package/src/revenuecat/infrastructure/utils/README.md +34 -375
  90. package/src/revenuecat/presentation/README.md +34 -176
  91. package/src/revenuecat/presentation/hooks/README.md +29 -35
  92. package/src/utils/README.md +38 -525
@@ -2,449 +2,93 @@
2
2
 
3
3
  Core hook for subscription status management and operations.
4
4
 
5
- ## Import
5
+ ## Location
6
6
 
7
- ```typescript
8
- import { useSubscription } from '@umituz/react-native-subscription';
9
- ```
7
+ **Import Path**: `@umituz/react-native-subscription`
10
8
 
11
- ## Signature
9
+ **File**: `src/presentation/hooks/useSubscription.ts`
12
10
 
13
- ```typescript
14
- function useSubscription(): {
15
- status: SubscriptionStatus | null;
16
- loading: boolean;
17
- error: string | null;
18
- isPremium: boolean;
19
- loadStatus: (userId: string) => Promise<void>;
20
- refreshStatus: (userId: string) => Promise<void>;
21
- activateSubscription: (
22
- userId: string,
23
- productId: string,
24
- expiresAt: string | null,
25
- ) => Promise<void>;
26
- deactivateSubscription: (userId: string) => Promise<void>;
27
- }
28
- ```
11
+ **Type**: Hook
29
12
 
30
- ## Returns
13
+ ## Strategy
31
14
 
32
- | Property | Type | Description |
33
- |----------|------|-------------|
34
- | `status` | `SubscriptionStatus \| null` | Current subscription status object |
35
- | `loading` | `boolean` | Loading state |
36
- | `error` | `string \| null` | Error message if any |
37
- | `isPremium` | `boolean` | Whether user has active subscription |
38
- | `loadStatus` | `(userId) => Promise<void>` | Load subscription status |
39
- | `refreshStatus` | `(userId) => Promise<void>` | Refresh subscription status |
40
- | `activateSubscription` | `(userId, productId, expiresAt) => Promise<void>` | Activate subscription |
41
- | `deactivateSubscription` | `(userId) => Promise<void>` | Deactivate subscription |
15
+ ### Subscription Management Flow
42
16
 
43
- ## Basic Usage
17
+ 1. **Status Retrieval**: Fetch current subscription status from repository
18
+ 2. **State Caching**: Cache status for 5 minutes using TanStack Query
19
+ 3. **Real-time Updates**: Auto-refresh when user auth state changes
20
+ 4. **Manual Operations**: Provide functions for manual activation/deactivation
21
+ 5. **Loading States**: Handle loading and error states properly
22
+ 6. **Refresh Mechanisms**: Support both load and refresh operations
44
23
 
45
- ```typescript
46
- function SubscriptionStatus() {
47
- const { user } = useAuth();
48
- const { status, isPremium, loading, loadStatus } = useSubscription();
24
+ ### Integration Points
49
25
 
50
- useEffect(() => {
51
- if (user?.uid) {
52
- loadStatus(user.uid);
53
- }
54
- }, [user]);
26
+ - **Subscription Repository**: `src/infrastructure/repositories/SubscriptionRepository.ts`
27
+ - **TanStack Query**: For caching and background updates
28
+ - **Auth Context**: Sync with user authentication state
29
+ - **RevenueCat**: For subscription data source
55
30
 
56
- if (loading) return <ActivityIndicator />;
31
+ ## Restrictions
57
32
 
58
- return (
59
- <View>
60
- <Text>Status: {isPremium ? 'Premium' : 'Free'}</Text>
61
- {status && (
62
- <Text>Product: {status.productId}</Text>
63
- )}
64
- </View>
65
- );
66
- }
67
- ```
33
+ ### REQUIRED
68
34
 
69
- ## Advanced Usage
35
+ - **User ID**: MUST provide valid userId for operations
36
+ - **Loading State**: MUST handle loading state in UI
37
+ - **Error Handling**: MUST handle error state
38
+ - **Status Check**: MUST verify isPremium before showing premium features
70
39
 
71
- ### With Auto-Refresh
40
+ ### PROHIBITED
72
41
 
73
- ```typescript
74
- function SubscriptionWithRefresh() {
75
- const { user } = useAuth();
76
- const { status, isPremium, loading, refreshStatus } = useSubscription();
42
+ - **NEVER** assume instant data availability (always check loading state)
43
+ - **NEVER** use for security decisions without server validation
44
+ - **DO NOT** call loadStatus/refreshStatus without userId
45
+ - **DO NOT** activate/deactivate subscriptions without proper validation
77
46
 
78
- useEffect(() => {
79
- if (user?.uid) {
80
- refreshStatus(user.uid);
81
- }
82
- }, [user]);
47
+ ### CRITICAL SAFETY
83
48
 
84
- // Refresh when app comes to foreground
85
- useFocusEffect(
86
- useCallback(() => {
87
- if (user?.uid) {
88
- refreshStatus(user.uid);
89
- }
90
- }, [user])
91
- );
49
+ - **ALWAYS** check loading state before accessing status
50
+ - **NEVER** trust client-side state for security enforcement
51
+ - **MUST** validate userId before all operations
52
+ - **ALWAYS** handle errors gracefully
92
53
 
93
- // Refresh every 5 minutes
94
- useEffect(() => {
95
- const interval = setInterval(() => {
96
- if (user?.uid) {
97
- refreshStatus(user.uid);
98
- }
99
- }, 5 * 60 * 1000);
54
+ ## AI Agent Guidelines
100
55
 
101
- return () => clearInterval(interval);
102
- }, [user]);
56
+ ### When Implementing Subscription Features
103
57
 
104
- if (loading) return <LoadingScreen />;
58
+ 1. **Always** check loading state before rendering subscription data
59
+ 2. **Always** handle error state
60
+ 3. **Always** verify isPremium before showing premium features
61
+ 4. **Always** validate userId before operations
62
+ 5. **Never** use for security decisions without server validation
105
63
 
106
- return (
107
- <View>
108
- <Text>{isPremium ? 'Premium' : 'Free'} User</Text>
109
- </View>
110
- );
111
- }
112
- ```
64
+ ### Integration Checklist
113
65
 
114
- ### With Manual Activation
66
+ - [ ] Import from correct path: `@umituz/react-native-subscription`
67
+ - [ ] Handle loading state
68
+ - [ ] Handle error state
69
+ - [ ] Check isPremium before rendering premium content
70
+ - [ ] Validate userId before operations
71
+ - [ ] Implement refresh mechanism
72
+ - [ ] Test with premium user
73
+ - [ ] Test with free user
74
+ - [ ] Test with guest user
75
+ - [ ] Test offline scenario
115
76
 
116
- ```typescript
117
- function SubscriptionManager() {
118
- const { user } = useAuth();
119
- const {
120
- status,
121
- activateSubscription,
122
- deactivateSubscription,
123
- loading,
124
- } = useSubscription();
77
+ ### Common Patterns
125
78
 
126
- const handleActivate = async () => {
127
- if (!user?.uid) return;
79
+ 1. **Status Display**: Show current subscription status
80
+ 2. **Conditional Rendering**: Show/hide features based on isPremium
81
+ 3. **Manual Refresh**: Provide refresh button for users
82
+ 4. **Auto-refresh**: Refresh on screen focus or app foreground
83
+ 5. **Status Polling**: Periodic refresh for real-time updates
84
+ 6. **Purchase Completion**: Refresh after successful purchase
85
+ 7. **Error Recovery**: Provide retry mechanism on failure
128
86
 
129
- try {
130
- await activateSubscription(
131
- user.uid,
132
- 'premium_monthly',
133
- new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString()
134
- );
135
- Alert.alert('Success', 'Subscription activated');
136
- } catch (error) {
137
- Alert.alert('Error', 'Failed to activate subscription');
138
- }
139
- };
87
+ ## Related Documentation
140
88
 
141
- const handleDeactivate = async () => {
142
- if (!user?.uid) return;
143
-
144
- try {
145
- await deactivateSubscription(user.uid);
146
- Alert.alert('Success', 'Subscription deactivated');
147
- } catch (error) {
148
- Alert.alert('Error', 'Failed to deactivate subscription');
149
- }
150
- };
151
-
152
- return (
153
- <View>
154
- <Text>Status: {status?.type || 'None'}</Text>
155
-
156
- <Button
157
- onPress={handleActivate}
158
- disabled={loading}
159
- title="Activate Subscription"
160
- />
161
-
162
- <Button
163
- onPress={handleDeactivate}
164
- disabled={loading || !status}
165
- title="Deactivate Subscription"
166
- />
167
- </View>
168
- );
169
- }
170
- ```
171
-
172
- ### With Error Handling
173
-
174
- ```typescript
175
- function RobustSubscription() {
176
- const { user } = useAuth();
177
- const { status, error, loading, loadStatus } = useSubscription();
178
-
179
- useEffect(() => {
180
- if (user?.uid) {
181
- loadStatus(user.uid).catch((err) => {
182
- console.error('Failed to load subscription:', err);
183
- });
184
- }
185
- }, [user]);
186
-
187
- useEffect(() => {
188
- if (error) {
189
- Alert.alert(
190
- 'Subscription Error',
191
- error,
192
- [{ text: 'Retry', onPress: () => user && loadStatus(user.uid) }]
193
- );
194
- }
195
- }, [error]);
196
-
197
- if (loading) return <LoadingScreen />;
198
-
199
- return (
200
- <View>
201
- {error ? (
202
- <ErrorBanner message={error} />
203
- ) : (
204
- <SubscriptionDisplay status={status} />
205
- )}
206
- </View>
207
- );
208
- }
209
- ```
210
-
211
- ### With Status Polling
212
-
213
- ```typescript
214
- function PollingSubscription() {
215
- const { user } = useAuth();
216
- const { status, refreshStatus, loading } = useSubscription();
217
-
218
- const [isPolling, setIsPolling] = useState(false);
219
-
220
- useEffect(() => {
221
- if (!user?.uid) return;
222
-
223
- // Initial load
224
- refreshStatus(user.uid);
225
-
226
- // Poll for status updates
227
- const interval = setInterval(async () => {
228
- if (!isPolling) {
229
- setIsPolling(true);
230
- try {
231
- await refreshStatus(user.uid);
232
- } finally {
233
- setIsPolling(false);
234
- }
235
- }
236
- }, 30000); // Every 30 seconds
237
-
238
- return () => clearInterval(interval);
239
- }, [user]);
240
-
241
- return (
242
- <View>
243
- <Text>Status: {status?.type || 'Loading...'}</Text>
244
- {loading && <ActivityIndicator size="small" />}
245
- </View>
246
- );
247
- }
248
- ```
249
-
250
- ## Examples
251
-
252
- ### Complete Subscription Dashboard
253
-
254
- ```typescript
255
- function SubscriptionDashboard() {
256
- const { user } = useAuth();
257
- const {
258
- status,
259
- isPremium,
260
- loading,
261
- error,
262
- refreshStatus,
263
- } = useSubscription();
264
-
265
- useEffect(() => {
266
- if (user?.uid) {
267
- refreshStatus(user.uid);
268
- }
269
- }, [user]);
270
-
271
- useFocusEffect(
272
- useCallback(() => {
273
- if (user?.uid) {
274
- refreshStatus(user.uid);
275
- }
276
- }, [user])
277
- );
278
-
279
- if (loading) {
280
- return <LoadingScreen />;
281
- }
282
-
283
- return (
284
- <ScrollView>
285
- {error && <ErrorBanner message={error} />}
286
-
287
- <SubscriptionCard
288
- status={status}
289
- isPremium={isPremium}
290
- />
291
-
292
- {status && (
293
- <>
294
- <DetailRow
295
- label="Product ID"
296
- value={status.productId}
297
- />
298
- <DetailRow
299
- label="Status"
300
- value={status.isActive ? 'Active' : 'Inactive'}
301
- />
302
- {status.expirationDate && (
303
- <DetailRow
304
- label="Expires"
305
- value={new Date(status.expirationDate).toLocaleDateString()}
306
- />
307
- )}
308
- </>
309
- )}
310
-
311
- <Button
312
- onPress={() => user && refreshStatus(user.uid)}
313
- title="Refresh Status"
314
- />
315
- </ScrollView>
316
- );
317
- }
318
- ```
319
-
320
- ### Subscription State Machine
321
-
322
- ```typescript
323
- function SubscriptionStateMachine() {
324
- const { user } = useAuth();
325
- const { status, loading, isPremium } = useSubscription();
326
-
327
- useEffect(() => {
328
- if (user?.uid) {
329
- loadStatus(user.uid);
330
- }
331
- }, [user]);
332
-
333
- const getState = () => {
334
- if (loading) return 'loading';
335
- if (!status) return 'none';
336
- if (!status.isActive) return 'expired';
337
- if (isPremium) return 'active';
338
- return 'inactive';
339
- };
340
-
341
- const state = getState();
342
-
343
- switch (state) {
344
- case 'loading':
345
- return <LoadingScreen />;
346
- case 'none':
347
- return <EmptyState message="No subscription found" />;
348
- case 'expired':
349
- return <ExpiredState onRenew={() => navigation.navigate('Paywall')} />;
350
- case 'active':
351
- return <PremiumContent />;
352
- default:
353
- return <FreeContent />;
354
- }
355
- }
356
- ```
357
-
358
- ### With Analytics Tracking
359
-
360
- ```typescript
361
- function TrackedSubscription() {
362
- const { user } = useAuth();
363
- const { status, isPremium, loading, loadStatus } = useSubscription();
364
-
365
- const previousStatus = useRef(status);
366
-
367
- useEffect(() => {
368
- if (user?.uid) {
369
- loadStatus(user.uid);
370
- }
371
- }, [user]);
372
-
373
- useEffect(() => {
374
- // Track subscription status changes
375
- if (previousStatus.current?.isActive !== status?.isActive) {
376
- analytics.track('subscription_status_changed', {
377
- from: previousStatus.current?.isActive,
378
- to: status?.isActive,
379
- userId: user?.uid,
380
- });
381
- }
382
-
383
- if (previousStatus.current?.type !== status?.type) {
384
- analytics.track('subscription_type_changed', {
385
- from: previousStatus.current?.type,
386
- to: status?.type,
387
- userId: user?.uid,
388
- });
389
- }
390
-
391
- previousStatus.current = status;
392
- }, [status]);
393
-
394
- if (loading) return <LoadingScreen />;
395
-
396
- return (
397
- <View>
398
- <Text>Status: {isPremium ? 'Premium' : 'Free'}</Text>
399
- </View>
400
- );
401
- }
402
- ```
403
-
404
- ## Best Practices
405
-
406
- 1. **Validate user ID** - Always check userId before operations
407
- 2. **Handle loading** - Show loading states appropriately
408
- 3. **Handle errors** - Display user-friendly error messages
409
- 4. **Refresh on focus** - Update when screen regains focus
410
- 5. **Auto-load** - Load status when user changes
411
- 6. **Track changes** - Monitor status transitions
412
- 7. **Cache wisely** - Don't over-refresh
413
-
414
- ## Common Patterns
415
-
416
- ### Basic Load
417
-
418
- ```typescript
419
- const { status, loadStatus } = useSubscription();
420
- useEffect(() => {
421
- if (user?.uid) loadStatus(user.uid);
422
- }, [user]);
423
- ```
424
-
425
- ### With Refresh
426
-
427
- ```typescript
428
- const { status, refreshStatus } = useSubscription();
429
- const handleRefresh = () => user && refreshStatus(user.uid);
430
- ```
431
-
432
- ### Manual Activation
433
-
434
- ```typescript
435
- const { activateSubscription } = useSubscription();
436
- await activateSubscription(userId, productId, expiresAt);
437
- ```
438
-
439
- ## Related Hooks
440
-
441
- - **usePremium** - Simplified premium checking
442
- - **useSubscriptionStatus** - Detailed subscription status
443
- - **useSubscriptionDetails** - Package and pricing info
444
- - **useUserTier** - Tier information
445
-
446
- ## See Also
447
-
448
- - [Subscription Entity](../../domain/entities/SubscriptionStatus.md)
449
- - [Subscription Service](../../infrastructure/services/SubscriptionService.md)
450
- - [Status Utilities](../../utils/subscriptionUtils.md)
89
+ - **usePremium**: Simplified premium checking
90
+ - **useSubscriptionStatus**: Detailed subscription status
91
+ - **useSubscriptionDetails**: Package and pricing info
92
+ - **useUserTier**: Tier information
93
+ - **Subscription Repository**: `src/infrastructure/repositories/README.md`
94
+ - **Domain Layer**: `src/domain/README.md`