@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,398 @@
|
|
|
1
|
+
# useAuthSubscriptionSync Hook
|
|
2
|
+
|
|
3
|
+
Automatically synchronizes subscription state with authentication changes.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { useAuthSubscriptionSync } from '@umituz/react-native-subscription';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Signature
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
function useAuthSubscriptionSync(config: {
|
|
15
|
+
onAuthStateChanged: (callback: (userId: string | null) => void) => () => void;
|
|
16
|
+
initializeSubscription: (userId: string) => Promise<void>;
|
|
17
|
+
}): void
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Parameters
|
|
21
|
+
|
|
22
|
+
| Parameter | Type | Default | Description |
|
|
23
|
+
|-----------|------|---------|-------------|
|
|
24
|
+
| `onAuthStateChanged` | `(callback) => () => void` | **Required** | Subscribe to auth changes, returns unsubscribe function |
|
|
25
|
+
| `initializeSubscription` | `(userId) => Promise<void>` | **Required** | Initialize subscription for user |
|
|
26
|
+
|
|
27
|
+
## Basic Usage
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
function App() {
|
|
31
|
+
useAuthSubscriptionSync({
|
|
32
|
+
onAuthStateChanged: (callback) => {
|
|
33
|
+
// Subscribe to Firebase auth changes
|
|
34
|
+
const unsubscribe = auth.onAuthStateChanged((user) => {
|
|
35
|
+
callback(user?.uid || null);
|
|
36
|
+
});
|
|
37
|
+
return unsubscribe;
|
|
38
|
+
},
|
|
39
|
+
initializeSubscription: async (userId) => {
|
|
40
|
+
// Initialize RevenueCat or subscription service
|
|
41
|
+
await Purchases.configure({ apiKey: 'your_key', appUserID: userId });
|
|
42
|
+
await fetchSubscriptionStatus(userId);
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return <YourAppNavigation />;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Advanced Usage
|
|
51
|
+
|
|
52
|
+
### With Firebase Auth
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
function AppWithFirebase() {
|
|
56
|
+
useAuthSubscriptionSync({
|
|
57
|
+
onAuthStateChanged: (callback) => {
|
|
58
|
+
const unsubscribe = auth.onAuthStateChanged((user) => {
|
|
59
|
+
callback(user?.uid || null);
|
|
60
|
+
});
|
|
61
|
+
return unsubscribe;
|
|
62
|
+
},
|
|
63
|
+
initializeSubscription: async (userId) => {
|
|
64
|
+
if (!userId) return;
|
|
65
|
+
|
|
66
|
+
// Configure RevenueCat with user ID
|
|
67
|
+
await Purchases.logIn(userId);
|
|
68
|
+
await syncSubscriptionWithBackend(userId);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return <AppNavigator />;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### With Custom Auth Provider
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
function AppWithCustomAuth() {
|
|
80
|
+
const authManager = useAuthManager();
|
|
81
|
+
|
|
82
|
+
useAuthSubscriptionSync({
|
|
83
|
+
onAuthStateChanged: (callback) => {
|
|
84
|
+
// Your custom auth system
|
|
85
|
+
const unsubscribe = authManager.addListener((user) => {
|
|
86
|
+
callback(user?.id || null);
|
|
87
|
+
});
|
|
88
|
+
return unsubscribe;
|
|
89
|
+
},
|
|
90
|
+
initializeSubscription: async (userId) => {
|
|
91
|
+
// Initialize your subscription system
|
|
92
|
+
await subscriptionService.initialize(userId);
|
|
93
|
+
await loadSubscriptionData(userId);
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return <App />;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### With Multiple Subscription Services
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
function AppWithMultipleServices() {
|
|
105
|
+
useAuthSubscriptionSync({
|
|
106
|
+
onAuthStateChanged: (callback) => {
|
|
107
|
+
return auth.onAuthStateChanged((user) => {
|
|
108
|
+
callback(user?.uid || null);
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
initializeSubscription: async (userId) => {
|
|
112
|
+
// Initialize RevenueCat
|
|
113
|
+
await Purchases.logIn(userId);
|
|
114
|
+
|
|
115
|
+
// Initialize custom credits system
|
|
116
|
+
await creditsRepository.initialize(userId);
|
|
117
|
+
|
|
118
|
+
// Sync with backend
|
|
119
|
+
await subscriptionSyncService.sync(userId);
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return <App />;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### With Error Handling
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
function AppWithErrorHandling() {
|
|
131
|
+
const [syncError, setSyncError] = useState<Error | null>(null);
|
|
132
|
+
|
|
133
|
+
useAuthSubscriptionSync({
|
|
134
|
+
onAuthStateChanged: (callback) => {
|
|
135
|
+
return auth.onAuthStateChanged((user) => {
|
|
136
|
+
callback(user?.uid || null);
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
initializeSubscription: async (userId) => {
|
|
140
|
+
try {
|
|
141
|
+
setSyncError(null);
|
|
142
|
+
await Purchases.logIn(userId);
|
|
143
|
+
await syncSubscriptionData(userId);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error('Subscription sync failed:', error);
|
|
146
|
+
setSyncError(error as Error);
|
|
147
|
+
// Optionally retry or show error to user
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (syncError) {
|
|
153
|
+
return <ErrorScreen error={syncError} />;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return <AppNavigation />;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### With Loading State
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
function AppWithLoadingState() {
|
|
164
|
+
const [isSyncing, setIsSyncing] = useState(false);
|
|
165
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
166
|
+
|
|
167
|
+
useAuthSubscriptionSync({
|
|
168
|
+
onAuthStateChanged: (callback) => {
|
|
169
|
+
return auth.onAuthStateChanged((user) => {
|
|
170
|
+
callback(user?.uid || null);
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
initializeSubscription: async (userId) => {
|
|
174
|
+
if (!userId) {
|
|
175
|
+
setIsInitialized(false);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
setIsSyncing(true);
|
|
180
|
+
try {
|
|
181
|
+
await Purchases.logIn(userId);
|
|
182
|
+
await loadUserSubscription(userId);
|
|
183
|
+
setIsInitialized(true);
|
|
184
|
+
} finally {
|
|
185
|
+
setIsSyncing(false);
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
if (isSyncing) {
|
|
191
|
+
return <LoadingScreen message="Syncing subscription..." />;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return <AppNavigation />;
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Examples
|
|
199
|
+
|
|
200
|
+
### Complete App Setup
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import React from 'react';
|
|
204
|
+
import { useAuthSubscriptionSync } from '@umituz/react-native-subscription';
|
|
205
|
+
import { auth } from './firebase/config';
|
|
206
|
+
import { Purchases } from 'react-native-purchases';
|
|
207
|
+
import { subscriptionService } from './services/subscription';
|
|
208
|
+
|
|
209
|
+
function App() {
|
|
210
|
+
useAuthSubscriptionSync({
|
|
211
|
+
onAuthStateChanged: (callback) => {
|
|
212
|
+
const unsubscribe = auth.onAuthStateChanged(async (user) => {
|
|
213
|
+
console.log('Auth state changed:', user?.uid || 'none');
|
|
214
|
+
callback(user?.uid || null);
|
|
215
|
+
});
|
|
216
|
+
return unsubscribe;
|
|
217
|
+
},
|
|
218
|
+
initializeSubscription: async (userId) => {
|
|
219
|
+
if (!userId) {
|
|
220
|
+
console.log('No user, skipping subscription init');
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
console.log('Initializing subscription for:', userId);
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
// Step 1: Identify user in RevenueCat
|
|
228
|
+
await Purchases.logIn(userId);
|
|
229
|
+
|
|
230
|
+
// Step 2: Fetch subscription status
|
|
231
|
+
await subscriptionService.fetchStatus(userId);
|
|
232
|
+
|
|
233
|
+
// Step 3: Sync with backend
|
|
234
|
+
await subscriptionService.syncWithBackend(userId);
|
|
235
|
+
|
|
236
|
+
console.log('Subscription initialized successfully');
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error('Failed to initialize subscription:', error);
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
return <AppNavigator />;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export default App;
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### With Analytics Tracking
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
function AppWithAnalytics() {
|
|
253
|
+
useAuthSubscriptionSync({
|
|
254
|
+
onAuthStateChanged: (callback) => {
|
|
255
|
+
return auth.onAuthStateChanged((user) => {
|
|
256
|
+
const userId = user?.uid || null;
|
|
257
|
+
analytics.identify(userId);
|
|
258
|
+
callback(userId);
|
|
259
|
+
});
|
|
260
|
+
},
|
|
261
|
+
initializeSubscription: async (userId) => {
|
|
262
|
+
analytics.track('subscription_sync_start', { userId });
|
|
263
|
+
|
|
264
|
+
await Purchases.logIn(userId);
|
|
265
|
+
|
|
266
|
+
const customerInfo = await Purchases.getCustomerInfo();
|
|
267
|
+
const isPremium = !!customerInfo.entitlements.active.premium;
|
|
268
|
+
|
|
269
|
+
analytics.track('subscription_sync_complete', {
|
|
270
|
+
userId,
|
|
271
|
+
isPremium,
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
return <App />;
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### With User Switching
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
function AppWithUserSwitching() {
|
|
284
|
+
useAuthSubscriptionSync({
|
|
285
|
+
onAuthStateChanged: (callback) => {
|
|
286
|
+
return auth.onAuthStateChanged((user) => {
|
|
287
|
+
const newUserId = user?.uid || null;
|
|
288
|
+
console.log('User changed:', newUserId);
|
|
289
|
+
callback(newUserId);
|
|
290
|
+
});
|
|
291
|
+
},
|
|
292
|
+
initializeSubscription: async (userId) => {
|
|
293
|
+
if (!userId) {
|
|
294
|
+
// User signed out - clear subscription data
|
|
295
|
+
subscriptionService.clear();
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// New user signed in or account switch
|
|
300
|
+
// The hook handles detecting userId changes
|
|
301
|
+
await Purchases.logIn(userId);
|
|
302
|
+
await subscriptionService.loadForUser(userId);
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
return <App />;
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## How It Works
|
|
311
|
+
|
|
312
|
+
### Automatic Initialization
|
|
313
|
+
|
|
314
|
+
The hook automatically:
|
|
315
|
+
|
|
316
|
+
1. **Listens to auth changes** - Subscribes to your auth provider
|
|
317
|
+
2. **Detects user changes** - Identifies when user ID changes
|
|
318
|
+
3. **Initializes once** - Only initializes once per user session
|
|
319
|
+
4. **Re-initializes on user switch** - Detects account switching
|
|
320
|
+
5. **Cleans up** - Unsubscribes when component unmounts
|
|
321
|
+
|
|
322
|
+
### User Change Detection
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
// Initial mount with user A
|
|
326
|
+
auth.onAuthStateChanged => callback('user-a-id')
|
|
327
|
+
initializeSubscription('user-a-id') // ✅ Runs
|
|
328
|
+
|
|
329
|
+
// Same user, no change
|
|
330
|
+
auth.onAuthStateChanged => callback('user-a-id')
|
|
331
|
+
initializeSubscription('user-a-id') // ❌ Skipped (same user)
|
|
332
|
+
|
|
333
|
+
// User switches to user B
|
|
334
|
+
auth.onAuthStateChanged => callback('user-b-id')
|
|
335
|
+
initializeSubscription('user-b-id') // ✅ Runs (user changed)
|
|
336
|
+
|
|
337
|
+
// User signs out
|
|
338
|
+
auth.onAuthStateChanged => callback(null)
|
|
339
|
+
// ❌ No initialization (no user)
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Best Practices
|
|
343
|
+
|
|
344
|
+
1. **Configure at app root** - Place in root App component
|
|
345
|
+
2. **Handle errors gracefully** - Catch and log initialization errors
|
|
346
|
+
3. **Show loading state** - Display loading during sync
|
|
347
|
+
4. **Test user switching** - Verify account switching works
|
|
348
|
+
5. **Cleanup properly** - Let hook handle unsubscribe
|
|
349
|
+
6. **One-time setup** - Configure once, don't reinitialize
|
|
350
|
+
7. **Monitor logs** - Use dev logs to verify behavior
|
|
351
|
+
|
|
352
|
+
## Common Patterns
|
|
353
|
+
|
|
354
|
+
### Firebase + RevenueCat
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
useAuthSubscriptionSync({
|
|
358
|
+
onAuthStateChanged: (callback) => auth.onAuthStateChanged((user) => callback(user?.uid || null)),
|
|
359
|
+
initializeSubscription: (userId) => Purchases.logIn(userId),
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Custom Auth + Backend
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
useAuthSubscriptionSync({
|
|
367
|
+
onAuthStateChanged: (callback) => customAuth.onAuthChange((user) => callback(user?.id || null)),
|
|
368
|
+
initializeSubscription: (userId) => backend.syncSubscription(userId),
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Multi-Service Setup
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
useAuthSubscriptionSync({
|
|
376
|
+
onAuthStateChanged: (callback) => auth.onAuthStateChanged((user) => callback(user?.uid)),
|
|
377
|
+
initializeSubscription: async (userId) => {
|
|
378
|
+
await Promise.all([
|
|
379
|
+
Purchases.logIn(userId),
|
|
380
|
+
creditsService.init(userId),
|
|
381
|
+
subscriptionBackend.sync(userId),
|
|
382
|
+
]);
|
|
383
|
+
},
|
|
384
|
+
});
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## Related Hooks
|
|
388
|
+
|
|
389
|
+
- **useAuth** - For authentication state
|
|
390
|
+
- **usePremium** - For subscription status
|
|
391
|
+
- **useAuthAwarePurchase** - For auth-gated purchases
|
|
392
|
+
- **useUserTier** - For tier determination
|
|
393
|
+
|
|
394
|
+
## See Also
|
|
395
|
+
|
|
396
|
+
- [Auth Integration Guide](../../../docs/AUTH_INTEGRATION.md)
|
|
397
|
+
- [RevenueCat Setup](../../../docs/REVENUECAT_SETUP.md)
|
|
398
|
+
- [Subscription State Management](../providers/README.md)
|