@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.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +462 -0
  3. package/package.json +3 -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/revenuecat/presentation/hooks/usePurchasePackage.ts +1 -1
  77. package/src/utils/README.md +529 -0
@@ -0,0 +1,344 @@
1
+ # usePaywallVisibility Hook
2
+
3
+ Simple global state management for paywall visibility using external store.
4
+
5
+ ## Import
6
+
7
+ ```typescript
8
+ import {
9
+ usePaywallVisibility,
10
+ paywallControl
11
+ } from '@umituz/react-native-subscription';
12
+ ```
13
+
14
+ ## Signature
15
+
16
+ ```typescript
17
+ function usePaywallVisibility(): {
18
+ showPaywall: boolean;
19
+ setShowPaywall: (visible: boolean) => void;
20
+ openPaywall: () => void;
21
+ closePaywall: () => void;
22
+ }
23
+
24
+ // Direct control (non-React contexts)
25
+ paywallControl: {
26
+ open: () => void;
27
+ close: () => void;
28
+ isOpen: () => boolean;
29
+ }
30
+ ```
31
+
32
+ ## Returns
33
+
34
+ | Property | Type | Description |
35
+ |----------|------|-------------|
36
+ | `showPaywall` | `boolean` | Current visibility state |
37
+ | `setShowPaywall` | `(visible) => void` | Set visibility state |
38
+ | `openPaywall` | `() => void` | Open paywall |
39
+ | `closePaywall` | `() => void` | Close paywall |
40
+
41
+ ## Basic Usage
42
+
43
+ ```typescript
44
+ function PaywallModal() {
45
+ const { showPaywall, closePaywall } = usePaywallVisibility();
46
+
47
+ if (!showPaywall) return null;
48
+
49
+ return (
50
+ <Modal visible={showPaywall} onRequestClose={closePaywall}>
51
+ <PaywallContent onClose={closePaywall} />
52
+ </Modal>
53
+ );
54
+ }
55
+ ```
56
+
57
+ ## Advanced Usage
58
+
59
+ ### With App Root Setup
60
+
61
+ ```typescript
62
+ function App() {
63
+ return (
64
+ <>
65
+ <YourAppNavigation />
66
+ <PaywallModal />
67
+ </>
68
+ );
69
+ }
70
+
71
+ function PaywallModal() {
72
+ const { showPaywall, closePaywall } = usePaywallVisibility();
73
+
74
+ return (
75
+ <Modal visible={showPaywall} animationType="slide">
76
+ <PaywallScreen onClose={closePaywall} />
77
+ </Modal>
78
+ );
79
+ }
80
+ ```
81
+
82
+ ### With Trigger Button
83
+
84
+ ```typescript
85
+ function PremiumFeature() {
86
+ const { openPaywall } = usePaywallVisibility();
87
+
88
+ return (
89
+ <Button
90
+ onPress={openPaywall}
91
+ title="Upgrade to Premium"
92
+ />
93
+ );
94
+ }
95
+ ```
96
+
97
+ ### With Direct Control (Non-React)
98
+
99
+ ```typescript
100
+ // In app initializer or non-React code
101
+ import { paywallControl } from '@umituz/react-native-subscription';
102
+
103
+ function showPaywallFromDeepLink(url: URL) {
104
+ if (url.pathname === '/upgrade') {
105
+ paywallControl.open();
106
+ }
107
+ }
108
+
109
+ function checkAndShowPaywall() {
110
+ if (!paywallControl.isOpen()) {
111
+ paywallControl.open();
112
+ }
113
+ }
114
+ ```
115
+
116
+ ### With Conditional Display
117
+
118
+ ```typescript
119
+ function ConditionalPaywall() {
120
+ const { showPaywall, openPaywall, closePaywall } = usePaywallVisibility();
121
+ const { isPremium } = usePremium();
122
+
123
+ useEffect(() => {
124
+ // Auto-show paywall for free users on certain screens
125
+ if (!isPremium && someCondition) {
126
+ openPaywall();
127
+ }
128
+ }, [isPremium]);
129
+
130
+ if (isPremium) return null; // Don't show for premium users
131
+
132
+ return (
133
+ <Modal visible={showPaywall}>
134
+ <PaywallContent onClose={closePaywall} />
135
+ </Modal>
136
+ );
137
+ }
138
+ ```
139
+
140
+ ### With History/Navigation
141
+
142
+ ```typescript
143
+ function PaywallWithHistory() {
144
+ const { showPaywall, closePaywall, openPaywall } = usePaywallVisibility();
145
+ const navigation = useNavigation();
146
+
147
+ useEffect(() => {
148
+ const unsubscribe = navigation.addListener('focus', () => {
149
+ // Show paywall when returning to certain screens
150
+ if (shouldShowPaywall()) {
151
+ openPaywall();
152
+ }
153
+ });
154
+
155
+ return unsubscribe;
156
+ }, [navigation]);
157
+
158
+ const handleClose = () => {
159
+ closePaywall();
160
+ navigation.goBack();
161
+ };
162
+
163
+ return (
164
+ <Modal visible={showPaywall}>
165
+ <PaywallContent onClose={handleClose} />
166
+ </Modal>
167
+ );
168
+ }
169
+ ```
170
+
171
+ ## Examples
172
+
173
+ ### Global Paywall System
174
+
175
+ ```typescript
176
+ // App.tsx
177
+ function App() {
178
+ return (
179
+ <PaywallProvider>
180
+ <Navigation />
181
+ <GlobalPaywall />
182
+ </PaywallProvider>
183
+ );
184
+ }
185
+
186
+ // components/GlobalPaywall.tsx
187
+ function GlobalPaywall() {
188
+ const { showPaywall, closePaywall } = usePaywallVisibility();
189
+
190
+ return (
191
+ <Modal visible={showPaywall} animationType="slide">
192
+ <PaywallScreen onClose={closePaywall} />
193
+ </Modal>
194
+ );
195
+ }
196
+
197
+ // Any component can trigger the paywall
198
+ function UpgradeButton() {
199
+ const { openPaywall } = usePaywallVisibility();
200
+ return <Button onPress={openPaywall} title="Upgrade" />;
201
+ }
202
+ ```
203
+
204
+ ### With Context Integration
205
+
206
+ ```typescript
207
+ function PaywallWithContext() {
208
+ const { showPaywall, closePaywall, setShowPaywall } = usePaywallVisibility();
209
+ const { isPremium } = usePremium();
210
+
211
+ // Close paywall when user becomes premium
212
+ useEffect(() => {
213
+ if (isPremium && showPaywall) {
214
+ setShowPaywall(false);
215
+ }
216
+ }, [isPremium, showPaywall]);
217
+
218
+ if (isPremium) return null;
219
+
220
+ return (
221
+ <Modal visible={showPaywall}>
222
+ <PaywallScreen onClose={closePaywall} />
223
+ </Modal>
224
+ );
225
+ }
226
+ ```
227
+
228
+ ### With Timeout/Auto-Close
229
+
230
+ ```typescript
231
+ function TimedPaywall() {
232
+ const { showPaywall, closePaywall } = usePaywallVisibility();
233
+
234
+ useEffect(() => {
235
+ if (!showPaywall) return;
236
+
237
+ // Auto-close after 30 seconds
238
+ const timer = setTimeout(() => {
239
+ closePaywall();
240
+ }, 30000);
241
+
242
+ return () => clearTimeout(timer);
243
+ }, [showPaywall, closePaywall]);
244
+
245
+ return (
246
+ <Modal visible={showPaywall}>
247
+ <PaywallContent onClose={closePaywall} />
248
+ </Modal>
249
+ );
250
+ }
251
+ ```
252
+
253
+ ### With Back Handler
254
+
255
+ ```typescript
256
+ function PaywallWithBackHandler() {
257
+ const { showPaywall, closePaywall } = usePaywallVisibility();
258
+
259
+ useBackHandler(showPaywall, () => {
260
+ closePaywall();
261
+ return true; // Prevent default back behavior
262
+ });
263
+
264
+ return (
265
+ <Modal visible={showPaywall}>
266
+ <PaywallContent onClose={closePaywall} />
267
+ </Modal>
268
+ );
269
+ }
270
+ ```
271
+
272
+ ### From Deep Link
273
+
274
+ ```typescript
275
+ // Deep link handler
276
+ import { paywallControl } from '@umituz/react-native-subscription';
277
+ import { Linking } from 'react-native';
278
+
279
+ Linking.addEventListener('url', ({ url }) => {
280
+ const parsed = new URL(url);
281
+
282
+ if (parsed.pathname === '/upgrade') {
283
+ paywallControl.open();
284
+ }
285
+
286
+ if (parsed.searchParams.get('show_paywall') === 'true') {
287
+ paywallControl.open();
288
+ }
289
+ });
290
+ ```
291
+
292
+ ### From Push Notification
293
+
294
+ ```typescript
295
+ // Push notification handler
296
+ import { paywallControl } from '@umituz/react-native-subscription';
297
+ import messaging from '@react-native-firebase/messaging';
298
+
299
+ messaging().onNotificationOpenedApp((remoteMessage) => {
300
+ if (remoteMessage.data?.type === 'paywall') {
301
+ paywallControl.open();
302
+ }
303
+ });
304
+
305
+ // Or when app is in background
306
+ messaging().setBackgroundMessageHandler(async (remoteMessage) => {
307
+ if (remoteMessage.data?.show_paywall) {
308
+ // Store flag to show paywall when app opens
309
+ AsyncStorage.setItem('pending_paywall', 'true');
310
+ }
311
+ });
312
+
313
+ // Then in your app
314
+ useEffect(() => {
315
+ AsyncStorage.getItem('pending_paywall').then((value) => {
316
+ if (value === 'true') {
317
+ paywallControl.open();
318
+ AsyncStorage.removeItem('pending_paywall');
319
+ }
320
+ });
321
+ }, []);
322
+ ```
323
+
324
+ ## Best Practices
325
+
326
+ 1. **Single modal instance** - Place paywall once at app root
327
+ 2. **Global access** - Use `paywallControl` for non-React contexts
328
+ 3. **Clean close** - Always provide close button
329
+ 4. **Back handler** - Handle Android back button
330
+ 5. **State persistence** - Don't rely on component state
331
+ 6. **Auto-close for premium** - Hide when user subscribes
332
+ 7. **Deeplink support** - Open from URLs and notifications
333
+
334
+ ## Related Hooks
335
+
336
+ - **usePaywallOperations** - For paywall purchase operations
337
+ - **usePremium** - For subscription status
338
+ - **usePaywall** - For complete paywall management
339
+
340
+ ## See Also
341
+
342
+ - [Paywall Screen](../screens/README.md)
343
+ - [Paywall Components](../components/paywall/README.md)
344
+ - [Modal Integration](../../../docs/MODAL_INTEGRATION.md)
@@ -0,0 +1,230 @@
1
+ # usePremium Hook
2
+
3
+ Hook for checking and managing premium subscription status.
4
+
5
+ ## Import
6
+
7
+ ```typescript
8
+ import { usePremium } from '@umituz/react-native-subscription';
9
+ ```
10
+
11
+ ## Signature
12
+
13
+ ```typescript
14
+ function usePremium(): {
15
+ isPremium: boolean;
16
+ isLoading: boolean;
17
+ error: Error | null;
18
+ subscription: SubscriptionStatus | null;
19
+ refetch: () => Promise<void>;
20
+ }
21
+ ```
22
+
23
+ ## Returns
24
+
25
+ | Property | Type | Description |
26
+ |----------|------|-------------|
27
+ | `isPremium` | `boolean` | Whether user has active premium subscription |
28
+ | `isLoading` | `boolean` | Whether hook is loading data |
29
+ | `error` | `Error \| null` | Error if fetching failed |
30
+ | `subscription` | `SubscriptionStatus \| null` | Full subscription status object |
31
+ | `refetch` | `() => Promise<void>` | Function to manually refetch data |
32
+
33
+ ## Basic Usage
34
+
35
+ ```typescript
36
+ function MyComponent() {
37
+ const { isPremium, isLoading } = usePremium();
38
+
39
+ if (isLoading) {
40
+ return <ActivityIndicator />;
41
+ }
42
+
43
+ return (
44
+ <View>
45
+ <Text>
46
+ {isPremium ? 'Premium User' : 'Free User'}
47
+ </Text>
48
+ </View>
49
+ );
50
+ }
51
+ ```
52
+
53
+ ## Advanced Usage
54
+
55
+ ### With Error Handling
56
+
57
+ ```typescript
58
+ function PremiumContent() {
59
+ const { isPremium, isLoading, error } = usePremium();
60
+
61
+ useEffect(() => {
62
+ if (error) {
63
+ console.error('Failed to load premium status:', error);
64
+ analytics.track('premium_check_failed', {
65
+ error: error.message,
66
+ });
67
+ }
68
+ }, [error]);
69
+
70
+ if (isLoading) return <Skeleton />;
71
+ if (error) return <ErrorState error={error} />;
72
+
73
+ return <PremiumFeatures />;
74
+ }
75
+ ```
76
+
77
+ ### With Refetch
78
+
79
+ ```typescript
80
+ function SettingsScreen() {
81
+ const { isPremium, refetch, isLoading } = usePremium();
82
+
83
+ const handleRefresh = async () => {
84
+ await refetch();
85
+ Alert.alert('Success', 'Status refreshed');
86
+ };
87
+
88
+ return (
89
+ <View>
90
+ <Text>Status: {isPremium ? 'Premium' : 'Free'}</Text>
91
+
92
+ <Button
93
+ onPress={handleRefresh}
94
+ disabled={isLoading}
95
+ title="Refresh Status"
96
+ />
97
+ </View>
98
+ );
99
+ }
100
+ ```
101
+
102
+ ### With Full Subscription Details
103
+
104
+ ```typescript
105
+ function SubscriptionInfo() {
106
+ const { isPremium, subscription } = usePremium();
107
+
108
+ if (!subscription) return null;
109
+
110
+ return (
111
+ <View>
112
+ <Text>Type: {subscription.type}</Text>
113
+ <Text>Active: {subscription.isActive ? 'Yes' : 'No'}</Text>
114
+
115
+ {subscription.expirationDate && (
116
+ <Text>
117
+ Expires: {new Date(subscription.expirationDate).toLocaleDateString()}
118
+ </Text>
119
+ )}
120
+
121
+ {subscription.willRenew && (
122
+ <Text>Auto-renew: On</Text>
123
+ )}
124
+ </View>
125
+ );
126
+ }
127
+ ```
128
+
129
+ ## Examples
130
+
131
+ ### Conditional Rendering
132
+
133
+ ```typescript
134
+ function FeatureList() {
135
+ const { isPremium, isLoading } = usePremium();
136
+
137
+ if (isLoading) return <LoadingSpinner />;
138
+
139
+ return (
140
+ <View>
141
+ <Feature name="Basic Feature" available={true} />
142
+ <Feature name="Premium Feature 1" available={isPremium} />
143
+ <Feature name="Premium Feature 2" available={isPremium} />
144
+ <Feature name="Premium Feature 3" available={isPremium} />
145
+ </View>
146
+ );
147
+ }
148
+ ```
149
+
150
+ ### Premium Badge
151
+
152
+ ```typescript
153
+ function PremiumBadge() {
154
+ const { isPremium } = usePremium();
155
+
156
+ return (
157
+ <View style={[
158
+ styles.badge,
159
+ isPremium && styles.badgePremium,
160
+ ]}>
161
+ <Text style={styles.badgeText}>
162
+ {isPremium ? '⭐ PREMIUM' : 'FREE'}
163
+ </Text>
164
+ </View>
165
+ );
166
+ }
167
+ ```
168
+
169
+ ### Premium Gate
170
+
171
+ ```typescript
172
+ function PremiumOnlyComponent() {
173
+ const { isPremium, isLoading } = usePremium();
174
+
175
+ if (isLoading) {
176
+ return <ActivityIndicator />;
177
+ }
178
+
179
+ if (!isPremium) {
180
+ return (
181
+ <View>
182
+ <Text>This feature requires Premium</Text>
183
+ <Button
184
+ onPress={() => navigation.navigate('Paywall')}
185
+ title="Upgrade to Premium"
186
+ />
187
+ </View>
188
+ );
189
+ }
190
+
191
+ return <PremiumContent />;
192
+ }
193
+ ```
194
+
195
+ ## Behavior
196
+
197
+ ### Loading States
198
+
199
+ The hook goes through these states:
200
+
201
+ 1. **Initial**: `isLoading = true`, `isPremium = false`
202
+ 2. **Loading**: Fetches subscription status
203
+ 3. **Loaded**: `isLoading = false`, `isPremium` set to actual value
204
+ 4. **Error**: `isLoading = false`, `error` set
205
+
206
+ ### Automatic Updates
207
+
208
+ The hook automatically updates when:
209
+ - User logs in/logs out
210
+ - Subscription status changes
211
+ - App comes to foreground
212
+
213
+ ### Caching
214
+
215
+ The hook caches subscription status for:
216
+ - Default: 5 minutes
217
+ - Configurable via `staleTime` option
218
+
219
+ ## Related Hooks
220
+
221
+ - **usePremiumGate** - For gating premium features
222
+ - **useSubscription** - For more subscription details
223
+ - **useSubscriptionStatus** - For detailed status info
224
+ - **usePremiumWithCredits** - For premium OR credits features
225
+
226
+ ## See Also
227
+
228
+ - [usePremiumGate](./usePremiumGate.md)
229
+ - [useSubscription](./useSubscription.md)
230
+ - [usePremiumWithCredits](./usePremiumWithCredits.md)