@umituz/react-native-subscription 2.14.98 → 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 -395
- 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 +52 -0
- package/src/domains/README.md.bak +274 -0
- package/src/domains/config/README.md +93 -383
- package/src/domains/config/domain/README.md +37 -0
- package/src/domains/config/domain/entities/README.md +41 -0
- 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 +96 -156
- 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 +43 -0
- package/src/revenuecat/application/ports/README.md +41 -0
- package/src/revenuecat/domain/README.md +42 -141
- package/src/revenuecat/domain/constants/README.md +41 -0
- package/src/revenuecat/domain/entities/README.md +42 -0
- package/src/revenuecat/domain/errors/README.md +47 -191
- package/src/revenuecat/domain/types/README.md +41 -0
- package/src/revenuecat/domain/value-objects/README.md +41 -0
- package/src/revenuecat/infrastructure/README.md +41 -0
- package/src/revenuecat/infrastructure/config/README.md +32 -23
- package/src/revenuecat/infrastructure/handlers/README.md +41 -0
- package/src/revenuecat/infrastructure/managers/README.md +34 -42
- package/src/revenuecat/infrastructure/services/README.md +42 -0
- package/src/revenuecat/infrastructure/utils/README.md +41 -0
- package/src/revenuecat/presentation/README.md +42 -0
- package/src/revenuecat/presentation/hooks/README.md +29 -35
- package/src/utils/README.md +38 -525
|
@@ -2,397 +2,93 @@
|
|
|
2
2
|
|
|
3
3
|
Automatically synchronizes subscription state with authentication changes.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Location
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
import { useAuthSubscriptionSync } from '@umituz/react-native-subscription';
|
|
9
|
-
```
|
|
7
|
+
**Import Path**: `@umituz/react-native-subscription`
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
**File**: `src/presentation/hooks/useAuthSubscriptionSync.ts`
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
function useAuthSubscriptionSync(config: {
|
|
15
|
-
onAuthStateChanged: (callback: (userId: string | null) => void) => () => void;
|
|
16
|
-
initializeSubscription: (userId: string) => Promise<void>;
|
|
17
|
-
}): void
|
|
18
|
-
```
|
|
11
|
+
**Type**: Hook
|
|
19
12
|
|
|
20
|
-
##
|
|
13
|
+
## Strategy
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
|-----------|------|---------|-------------|
|
|
24
|
-
| `onAuthStateChanged` | `(callback) => () => void` | **Required** | Subscribe to auth changes, returns unsubscribe function |
|
|
25
|
-
| `initializeSubscription` | `(userId) => Promise<void>` | **Required** | Initialize subscription for user |
|
|
15
|
+
### Auth-Subscription Synchronization
|
|
26
16
|
|
|
27
|
-
|
|
17
|
+
1. **Auth Listener Setup**: Subscribe to auth state changes via provided callback
|
|
18
|
+
2. **User Change Detection**: Detect when userId changes (including sign out)
|
|
19
|
+
3. **Subscription Initialization**: Initialize subscription when user signs in
|
|
20
|
+
4. **One-Time Init**: Only initialize once per user session (skips duplicates)
|
|
21
|
+
5. **User Switching**: Re-initialize when switching between accounts
|
|
22
|
+
6. **Cleanup**: Unsubscribe from auth listener on unmount
|
|
28
23
|
|
|
29
|
-
|
|
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
|
-
});
|
|
24
|
+
### Integration Points
|
|
45
25
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
26
|
+
- **Auth Provider**: Any auth system (Firebase, Auth0, custom)
|
|
27
|
+
- **RevenueCat**: For subscription initialization with logIn
|
|
28
|
+
- **Subscription Service**: Backend subscription sync
|
|
29
|
+
- **Credits System**: Optional credits initialization
|
|
30
|
+
- **App Root**: Should be placed in root App component
|
|
49
31
|
|
|
50
|
-
##
|
|
32
|
+
## Restrictions
|
|
51
33
|
|
|
52
|
-
###
|
|
34
|
+
### REQUIRED
|
|
53
35
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const unsubscribe = auth.onAuthStateChanged((user) => {
|
|
59
|
-
callback(user?.uid || null);
|
|
60
|
-
});
|
|
61
|
-
return unsubscribe;
|
|
62
|
-
},
|
|
63
|
-
initializeSubscription: async (userId) => {
|
|
64
|
-
if (!userId) return;
|
|
36
|
+
- **Auth State Change Callback**: MUST provide onAuthStateChanged function
|
|
37
|
+
- **Subscription Init**: MUST provide initializeSubscription function
|
|
38
|
+
- **App Root Setup**: SHOULD be placed in root App component
|
|
39
|
+
- **Unsubscribe Handling**: Callback MUST return unsubscribe function
|
|
65
40
|
|
|
66
|
-
|
|
67
|
-
await Purchases.logIn(userId);
|
|
68
|
-
await syncSubscriptionWithBackend(userId);
|
|
69
|
-
},
|
|
70
|
-
});
|
|
41
|
+
### PROHIBITED
|
|
71
42
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
43
|
+
- **NEVER** place in individual screen components (use app root)
|
|
44
|
+
- **NEVER** call without proper auth callback
|
|
45
|
+
- **DO NOT** manually call initializeSubscription (hook handles it)
|
|
46
|
+
- **DO NOT** configure multiple times (one-time setup)
|
|
75
47
|
|
|
76
|
-
###
|
|
48
|
+
### CRITICAL SAFETY
|
|
77
49
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
50
|
+
- **ALWAYS** configure at app root level
|
|
51
|
+
- **MUST** handle user switching correctly
|
|
52
|
+
- **ALWAYS** return unsubscribe function from callback
|
|
53
|
+
- **NEVER** rely on manual subscription initialization
|
|
81
54
|
|
|
82
|
-
|
|
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
|
-
});
|
|
55
|
+
## AI Agent Guidelines
|
|
96
56
|
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
```
|
|
57
|
+
### When Implementing Auth-Subscription Sync
|
|
100
58
|
|
|
101
|
-
|
|
59
|
+
1. **Always** place in root App component
|
|
60
|
+
2. **Always** provide onAuthStateChanged that returns unsubscribe
|
|
61
|
+
3. **Always** provide initializeSubscription for user ID
|
|
62
|
+
4. **Always** test user switching scenarios
|
|
63
|
+
5. **Never** place in child components
|
|
102
64
|
|
|
103
|
-
|
|
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);
|
|
65
|
+
### Integration Checklist
|
|
114
66
|
|
|
115
|
-
|
|
116
|
-
|
|
67
|
+
- [ ] Import from correct path: `@umituz/react-native-subscription`
|
|
68
|
+
- [ ] Place in root App component
|
|
69
|
+
- [ ] Provide onAuthStateChanged callback
|
|
70
|
+
- [ ] Ensure callback returns unsubscribe function
|
|
71
|
+
- [ ] Provide initializeSubscription function
|
|
72
|
+
- [ ] Test with initial user sign-in
|
|
73
|
+
- [ ] Test with user sign-out
|
|
74
|
+
- [ ] Test with account switching
|
|
75
|
+
- [ ] Verify subscription initializes only once per user
|
|
76
|
+
- [ ] Test cleanup on unmount
|
|
117
77
|
|
|
118
|
-
|
|
119
|
-
await subscriptionSyncService.sync(userId);
|
|
120
|
-
},
|
|
121
|
-
});
|
|
78
|
+
### Common Patterns
|
|
122
79
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
80
|
+
1. **Firebase + RevenueCat**: Sync Firebase auth with RevenueCat
|
|
81
|
+
2. **Custom Auth + Backend**: Use custom auth with backend sync
|
|
82
|
+
3. **Multi-Service Setup**: Initialize multiple services (RevenueCat, credits, backend)
|
|
83
|
+
4. **Error Handling**: Handle initialization failures gracefully
|
|
84
|
+
5. **Loading State**: Show loading during sync
|
|
85
|
+
6. **Analytics Tracking**: Track auth and subscription events
|
|
126
86
|
|
|
127
|
-
|
|
87
|
+
## Related Documentation
|
|
128
88
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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)
|
|
89
|
+
- **useAuth**: For authentication state
|
|
90
|
+
- **usePremium**: For subscription status
|
|
91
|
+
- **useAuthAwarePurchase**: For auth-gated purchases
|
|
92
|
+
- **useUserTier**: For tier determination
|
|
93
|
+
- **Auth Integration Guide**: `src/docs/AUTH_INTEGRATION.md`
|
|
94
|
+
- **RevenueCat Setup**: `src/docs/REVENUECAT_SETUP.md`
|