@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.
- package/README.md +211 -394
- package/package.json +1 -1
- package/src/application/README.md +46 -225
- package/src/application/ports/README.md +42 -97
- package/src/domain/README.md +36 -384
- package/src/domain/constants/README.md +0 -56
- package/src/domain/entities/README.md +43 -169
- package/src/domain/errors/README.md +33 -287
- package/src/domain/value-objects/README.md +43 -179
- package/src/domains/README.md +50 -238
- package/src/domains/README.md.bak +274 -0
- package/src/domains/config/README.md +93 -383
- package/src/domains/config/domain/README.md +23 -376
- package/src/domains/config/domain/entities/README.md +34 -343
- package/src/domains/paywall/README.md +99 -369
- package/src/domains/paywall/components/README.md +34 -178
- package/src/domains/paywall/entities/README.md +34 -193
- package/src/domains/paywall/hooks/README.md +34 -122
- package/src/domains/wallet/README.md +34 -275
- package/src/domains/wallet/README.md.bak +209 -0
- package/src/domains/wallet/domain/README.md +34 -101
- package/src/domains/wallet/domain/entities/README.md +34 -115
- package/src/domains/wallet/domain/errors/README.md +34 -151
- package/src/domains/wallet/infrastructure/README.md +34 -89
- package/src/domains/wallet/presentation/components/README.md +34 -224
- package/src/domains/wallet/presentation/hooks/README.md +34 -248
- package/src/infrastructure/README.md +37 -496
- package/src/infrastructure/mappers/README.md +0 -13
- package/src/infrastructure/repositories/README.md +74 -360
- package/src/infrastructure/services/README.md +95 -370
- package/src/presentation/README.md +123 -408
- package/src/presentation/README.md.bak +172 -0
- package/src/presentation/components/README.md +151 -179
- package/src/presentation/components/README.md.bak +217 -0
- package/src/presentation/components/details/CreditRow.md +65 -310
- package/src/presentation/components/details/DetailRow.md +63 -255
- package/src/presentation/components/details/PremiumDetailsCard.md +65 -238
- package/src/presentation/components/details/PremiumStatusBadge.md +64 -239
- package/src/presentation/components/details/README.md +97 -447
- package/src/presentation/components/feedback/PaywallFeedbackModal.md +63 -287
- package/src/presentation/components/feedback/README.md +97 -445
- package/src/presentation/components/paywall/PaywallModal.md +66 -416
- package/src/presentation/components/paywall/README.md +50 -186
- package/src/presentation/components/sections/README.md +97 -466
- package/src/presentation/components/sections/SubscriptionSection.md +92 -244
- package/src/presentation/hooks/README.md +154 -741
- package/src/presentation/hooks/useAuthAwarePurchase.md +58 -325
- package/src/presentation/hooks/useAuthGate.md +61 -375
- package/src/presentation/hooks/useAuthSubscriptionSync.md +66 -370
- package/src/presentation/hooks/useCreditChecker.md +73 -378
- package/src/presentation/hooks/useCredits.md +74 -313
- package/src/presentation/hooks/useCredits.md.bak +231 -0
- package/src/presentation/hooks/useCreditsGate.md +66 -318
- package/src/presentation/hooks/useDeductCredit.md +0 -76
- package/src/presentation/hooks/useDevTestCallbacks.md +63 -394
- package/src/presentation/hooks/useFeatureGate.md +105 -150
- package/src/presentation/hooks/useFeatureGate.md.bak +284 -0
- package/src/presentation/hooks/useInitializeCredits.md +64 -430
- package/src/presentation/hooks/usePaywall.md +61 -306
- package/src/presentation/hooks/usePaywallOperations.md +64 -458
- package/src/presentation/hooks/usePaywallVisibility.md +67 -316
- package/src/presentation/hooks/usePremium.md +84 -226
- package/src/presentation/hooks/usePremiumGate.md +60 -395
- package/src/presentation/hooks/usePremiumWithCredits.md +64 -401
- package/src/presentation/hooks/useSubscription.md +66 -422
- package/src/presentation/hooks/useSubscriptionDetails.md +65 -410
- package/src/presentation/hooks/useSubscriptionGate.md +80 -164
- package/src/presentation/hooks/useSubscriptionSettingsConfig.md +66 -346
- package/src/presentation/hooks/useSubscriptionStatus.md +66 -396
- package/src/presentation/hooks/useUserTier.md +63 -328
- package/src/presentation/hooks/useUserTierWithRepository.md +64 -424
- package/src/presentation/screens/README.md +48 -190
- package/src/presentation/types/README.md +0 -16
- package/src/presentation/utils/README.md +0 -21
- package/src/revenuecat/README.md +99 -518
- package/src/revenuecat/application/README.md +35 -150
- package/src/revenuecat/application/ports/README.md +34 -162
- package/src/revenuecat/domain/README.md +42 -141
- package/src/revenuecat/domain/constants/README.md +34 -176
- package/src/revenuecat/domain/entities/README.md +34 -374
- package/src/revenuecat/domain/errors/README.md +47 -191
- package/src/revenuecat/domain/types/README.md +34 -366
- package/src/revenuecat/domain/value-objects/README.md +34 -434
- package/src/revenuecat/infrastructure/README.md +34 -43
- package/src/revenuecat/infrastructure/config/README.md +32 -23
- package/src/revenuecat/infrastructure/handlers/README.md +34 -211
- package/src/revenuecat/infrastructure/managers/README.md +34 -42
- package/src/revenuecat/infrastructure/services/README.md +35 -318
- package/src/revenuecat/infrastructure/utils/README.md +34 -375
- package/src/revenuecat/presentation/README.md +34 -176
- package/src/revenuecat/presentation/hooks/README.md +29 -35
- 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
|
-
##
|
|
5
|
+
## Location
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
import { useSubscription } from '@umituz/react-native-subscription';
|
|
9
|
-
```
|
|
7
|
+
**Import Path**: `@umituz/react-native-subscription`
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
**File**: `src/presentation/hooks/useSubscription.ts`
|
|
12
10
|
|
|
13
|
-
|
|
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
|
-
##
|
|
13
|
+
## Strategy
|
|
31
14
|
|
|
32
|
-
|
|
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
|
-
|
|
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
|
-
|
|
46
|
-
function SubscriptionStatus() {
|
|
47
|
-
const { user } = useAuth();
|
|
48
|
-
const { status, isPremium, loading, loadStatus } = useSubscription();
|
|
24
|
+
### Integration Points
|
|
49
25
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
31
|
+
## Restrictions
|
|
57
32
|
|
|
58
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
40
|
+
### PROHIBITED
|
|
72
41
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
79
|
-
if (user?.uid) {
|
|
80
|
-
refreshStatus(user.uid);
|
|
81
|
-
}
|
|
82
|
-
}, [user]);
|
|
47
|
+
### CRITICAL SAFETY
|
|
83
48
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
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
|
-
|
|
102
|
-
}, [user]);
|
|
56
|
+
### When Implementing Subscription Features
|
|
103
57
|
|
|
104
|
-
|
|
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
|
-
|
|
107
|
-
<View>
|
|
108
|
-
<Text>{isPremium ? 'Premium' : 'Free'} User</Text>
|
|
109
|
-
</View>
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
```
|
|
64
|
+
### Integration Checklist
|
|
113
65
|
|
|
114
|
-
|
|
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
|
-
|
|
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
|
-
|
|
127
|
-
|
|
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
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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`
|