@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,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)
|