@umituz/react-native-subscription 2.14.99 → 2.14.101
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 +3 -3
- 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/entities/SubscriptionStatus.ts +1 -1
- 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/components/TransactionItem.tsx +1 -1
- 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/ActivationHandler.ts +1 -1
- package/src/infrastructure/services/README.md +95 -370
- package/src/infrastructure/services/SubscriptionService.ts +1 -1
- 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/useDeductCredit.ts +1 -1
- 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/presentation/utils/subscriptionDateUtils.ts +1 -1
- 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,457 +2,91 @@
|
|
|
2
2
|
|
|
3
3
|
TanStack Query mutation hook for initializing credits after purchase.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Location
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
import { useInitializeCredits } from '@umituz/react-native-subscription';
|
|
9
|
-
```
|
|
7
|
+
**Import Path**: `@umituz/react-native-subscription`
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
**File**: `src/presentation/hooks/useInitializeCredits.ts`
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
function useInitializeCredits(params: {
|
|
15
|
-
userId: string | undefined;
|
|
16
|
-
}): {
|
|
17
|
-
initializeCredits: (options?: {
|
|
18
|
-
purchaseId?: string;
|
|
19
|
-
productId?: string;
|
|
20
|
-
}) => Promise<boolean>;
|
|
21
|
-
isInitializing: boolean;
|
|
22
|
-
}
|
|
23
|
-
```
|
|
11
|
+
**Type**: Hook
|
|
24
12
|
|
|
25
|
-
##
|
|
13
|
+
## Strategy
|
|
26
14
|
|
|
27
|
-
|
|
28
|
-
|-----------|------|---------|-------------|
|
|
29
|
-
| `userId` | `string \| undefined` | **Required** | User ID for credit initialization |
|
|
15
|
+
### Credit Initialization Flow
|
|
30
16
|
|
|
31
|
-
|
|
17
|
+
1. **User Validation**: Verify user is authenticated before initialization
|
|
18
|
+
2. **Repository Call**: Call credits repository to initialize credits
|
|
19
|
+
3. **Duplicate Protection**: Repository prevents duplicate initialization with same purchase ID
|
|
20
|
+
4. **Loading State**: Track initialization progress with isInitializing flag
|
|
21
|
+
5. **Error Handling**: Handle and report initialization failures
|
|
22
|
+
6. **Success Tracking**: Return success boolean for caller to handle
|
|
32
23
|
|
|
33
|
-
|
|
34
|
-
|----------|------|-------------|
|
|
35
|
-
| `initializeCredits` | `(options?) => Promise<boolean>` | Initialize credits function |
|
|
36
|
-
| `isInitializing` | `boolean` | Mutation is in progress |
|
|
24
|
+
### Integration Points
|
|
37
25
|
|
|
38
|
-
|
|
26
|
+
- **Credits Repository**: `src/domains/wallet/infrastructure/repositories/CreditsRepository.ts`
|
|
27
|
+
- **Credits Entity**: `src/domains/wallet/domain/entities/UserCredits.ts`
|
|
28
|
+
- **TanStack Query**: For mutation and optimistic updates
|
|
29
|
+
- **Purchase Flow**: Called after successful subscription purchase
|
|
39
30
|
|
|
40
|
-
|
|
41
|
-
|-----------|------|---------|-------------|
|
|
42
|
-
| `purchaseId` | `string` | `undefined` | Optional purchase/renewal ID |
|
|
43
|
-
| `productId` | `string` | `undefined` | Optional product ID |
|
|
31
|
+
## Restrictions
|
|
44
32
|
|
|
45
|
-
|
|
33
|
+
### REQUIRED
|
|
46
34
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
35
|
+
- **User ID**: MUST provide valid userId parameter
|
|
36
|
+
- **Authentication**: User MUST be authenticated
|
|
37
|
+
- **Error Handling**: MUST handle initialization failures
|
|
38
|
+
- **Loading State**: MUST show loading indicator during initialization
|
|
50
39
|
|
|
51
|
-
|
|
52
|
-
userId: user?.uid,
|
|
53
|
-
});
|
|
40
|
+
### PROHIBITED
|
|
54
41
|
|
|
55
|
-
|
|
56
|
-
|
|
42
|
+
- **NEVER** initialize credits without valid userId
|
|
43
|
+
- **NEVER** call for unauthenticated users
|
|
44
|
+
- **DO NOT** assume successful initialization (check return value)
|
|
45
|
+
- **DO NOT** call excessively (repository handles duplicates)
|
|
57
46
|
|
|
58
|
-
|
|
59
|
-
Alert.alert('Success', 'Credits initialized successfully');
|
|
60
|
-
} else {
|
|
61
|
-
Alert.alert('Error', 'Failed to initialize credits');
|
|
62
|
-
}
|
|
63
|
-
};
|
|
47
|
+
### CRITICAL SAFETY
|
|
64
48
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
title={isInitializing ? 'Initializing...' : 'Initialize Credits'}
|
|
70
|
-
/>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
```
|
|
49
|
+
- **ALWAYS** validate userId before initialization
|
|
50
|
+
- **MUST** handle errors gracefully
|
|
51
|
+
- **ALWAYS** check return value
|
|
52
|
+
- **NEVER** rely on side effects without checking success
|
|
74
53
|
|
|
75
|
-
##
|
|
54
|
+
## AI Agent Guidelines
|
|
76
55
|
|
|
77
|
-
###
|
|
56
|
+
### When Implementing Credit Initialization
|
|
78
57
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
58
|
+
1. **Always** validate userId before calling initializeCredits
|
|
59
|
+
2. **Always** handle loading state
|
|
60
|
+
3. **Always** check return value
|
|
61
|
+
4. **Always** provide purchaseId and productId when available
|
|
62
|
+
5. **Never** initialize credits for unauthenticated users
|
|
82
63
|
|
|
83
|
-
|
|
84
|
-
userId: user?.uid,
|
|
85
|
-
});
|
|
64
|
+
### Integration Checklist
|
|
86
65
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
66
|
+
- [ ] Import from correct path: `@umituz/react-native-subscription`
|
|
67
|
+
- [ ] Validate userId is not undefined
|
|
68
|
+
- [ ] Handle isInitializing state
|
|
69
|
+
- [ ] Check return value from initializeCredits
|
|
70
|
+
- [ ] Provide purchaseId when available
|
|
71
|
+
- [ ] Provide productId when available
|
|
72
|
+
- [ ] Test with premium user (no existing credits)
|
|
73
|
+
- [ ] Test with premium user (existing credits)
|
|
74
|
+
- [ ] Test duplicate protection
|
|
75
|
+
- [ ] Test error scenarios
|
|
92
76
|
|
|
93
|
-
|
|
94
|
-
analytics.track('credits_initialized', {
|
|
95
|
-
userId: user?.uid,
|
|
96
|
-
purchaseId: transaction.transactionId,
|
|
97
|
-
});
|
|
98
|
-
}
|
|
77
|
+
### Common Patterns
|
|
99
78
|
|
|
100
|
-
|
|
101
|
-
|
|
79
|
+
1. **Post-Purchase Init**: Initialize after successful purchase
|
|
80
|
+
2. **Auto-Init for Premium**: Automatically initialize for premium users without credits
|
|
81
|
+
3. **Product-Specific Allocation**: Different products provide different credit amounts
|
|
82
|
+
4. **Retry Logic**: Implement retry mechanism on failure
|
|
83
|
+
5. **Admin Init**: Manual initialization for admin users
|
|
102
84
|
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
```
|
|
85
|
+
## Related Documentation
|
|
106
86
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const { credits } = useCredits();
|
|
114
|
-
|
|
115
|
-
const { initializeCredits, isInitializing } = useInitializeCredits({
|
|
116
|
-
userId: user?.uid,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
useEffect(() => {
|
|
120
|
-
// Auto-initialize credits for premium users who don't have them yet
|
|
121
|
-
if (isPremium && !credits && !isInitializing) {
|
|
122
|
-
const init = async () => {
|
|
123
|
-
const success = await initializeCredits();
|
|
124
|
-
if (success) {
|
|
125
|
-
console.log('Credits initialized for premium user');
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
init();
|
|
129
|
-
}
|
|
130
|
-
}, [isPremium, credits]);
|
|
131
|
-
|
|
132
|
-
return <YourAppContent />;
|
|
133
|
-
}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### With Product-Specific Allocations
|
|
137
|
-
|
|
138
|
-
```typescript
|
|
139
|
-
function ProductBasedAllocation() {
|
|
140
|
-
const { user } = useAuth();
|
|
141
|
-
|
|
142
|
-
const { initializeCredits } = useInitializeCredits({
|
|
143
|
-
userId: user?.uid,
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
const handlePurchase = async (productId: string) => {
|
|
147
|
-
// Different products provide different credit amounts
|
|
148
|
-
const productConfig = {
|
|
149
|
-
'premium_monthly': { credits: 100 },
|
|
150
|
-
'premium_yearly': { credits: 1200 },
|
|
151
|
-
'credits_small': { credits: 50 },
|
|
152
|
-
'credits_large': { credits: 500 },
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
const config = productConfig[productId];
|
|
156
|
-
if (!config) {
|
|
157
|
-
Alert.alert('Error', 'Unknown product');
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const success = await initializeCredits({
|
|
162
|
-
purchaseId: `purchase_${Date.now()}`,
|
|
163
|
-
productId,
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
if (success) {
|
|
167
|
-
Alert.alert('Success', `You received ${config.credits} credits!`);
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
return <PackageList onSelectPackage={handlePurchase} />;
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### With Error Handling
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
function RobustInitialization() {
|
|
179
|
-
const { user } = useAuth();
|
|
180
|
-
|
|
181
|
-
const {
|
|
182
|
-
initializeCredits,
|
|
183
|
-
isInitializing,
|
|
184
|
-
} = useInitializeCredits({
|
|
185
|
-
userId: user?.uid,
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
const handleInitialize = async () => {
|
|
189
|
-
if (!user?.uid) {
|
|
190
|
-
Alert.alert('Error', 'User not authenticated');
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
try {
|
|
195
|
-
const success = await initializeCredits({
|
|
196
|
-
purchaseId: `init_${Date.now()}`,
|
|
197
|
-
productId: 'premium_subscription',
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
if (success) {
|
|
201
|
-
Alert.alert('Success', 'Credits initialized');
|
|
202
|
-
} else {
|
|
203
|
-
Alert.alert('Failed', 'Could not initialize credits');
|
|
204
|
-
}
|
|
205
|
-
} catch (error) {
|
|
206
|
-
console.error('Initialization error:', error);
|
|
207
|
-
Alert.alert(
|
|
208
|
-
'Error',
|
|
209
|
-
'Failed to initialize credits. Please try again.'
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
return (
|
|
215
|
-
<Button
|
|
216
|
-
onPress={handleInitialize}
|
|
217
|
-
disabled={isInitializing}
|
|
218
|
-
title="Initialize Credits"
|
|
219
|
-
/>
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
### With Retry Logic
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
function InitializationWithRetry() {
|
|
228
|
-
const { user } = useAuth();
|
|
229
|
-
|
|
230
|
-
const { initializeCredits, isInitializing } = useInitializeCredits({
|
|
231
|
-
userId: user?.uid,
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
const handleInitializeWithRetry = async (retries = 3) => {
|
|
235
|
-
for (let i = 0; i < retries; i++) {
|
|
236
|
-
const success = await initializeCredits();
|
|
237
|
-
|
|
238
|
-
if (success) {
|
|
239
|
-
Alert.alert('Success', 'Credits initialized');
|
|
240
|
-
return true;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Wait before retry
|
|
244
|
-
if (i < retries - 1) {
|
|
245
|
-
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
Alert.alert('Failed', 'Could not initialize credits after retries');
|
|
250
|
-
return false;
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
return (
|
|
254
|
-
<Button
|
|
255
|
-
onPress={() => handleInitializeWithRetry()}
|
|
256
|
-
disabled={isInitializing}
|
|
257
|
-
title="Initialize (with retry)"
|
|
258
|
-
/>
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
## Examples
|
|
264
|
-
|
|
265
|
-
### Post-Purchase Flow
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
function PostPurchaseFlow() {
|
|
269
|
-
const { user } = useAuth();
|
|
270
|
-
const navigation = useNavigation();
|
|
271
|
-
|
|
272
|
-
const { initializeCredits, isInitializing } = useInitializeCredits({
|
|
273
|
-
userId: user?.uid,
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
useEffect(() => {
|
|
277
|
-
const handlePurchase = async (purchase: any) => {
|
|
278
|
-
console.log('Purchase completed:', purchase);
|
|
279
|
-
|
|
280
|
-
const success = await initializeCredits({
|
|
281
|
-
purchaseId: purchase.transactionId,
|
|
282
|
-
productId: purchase.productId,
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
if (success) {
|
|
286
|
-
// Navigate to success screen
|
|
287
|
-
navigation.replace('PurchaseSuccess', {
|
|
288
|
-
credits: purchase.credits,
|
|
289
|
-
});
|
|
290
|
-
} else {
|
|
291
|
-
// Show error
|
|
292
|
-
Alert.alert(
|
|
293
|
-
'Setup Required',
|
|
294
|
-
'Could not initialize credits. Please contact support.'
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
const subscription = purchasesEmitter.on('purchase_complete', handlePurchase);
|
|
300
|
-
|
|
301
|
-
return () => subscription.remove();
|
|
302
|
-
}, []);
|
|
303
|
-
|
|
304
|
-
if (isInitializing) {
|
|
305
|
-
return (
|
|
306
|
-
<View>
|
|
307
|
-
<ActivityIndicator size="large" />
|
|
308
|
-
<Text>Setting up your credits...</Text>
|
|
309
|
-
</View>
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return <YourAppContent />;
|
|
314
|
-
}
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### Subscription Renewal Handler
|
|
318
|
-
|
|
319
|
-
```typescript
|
|
320
|
-
function RenewalHandler() {
|
|
321
|
-
const { user } = useAuth();
|
|
322
|
-
|
|
323
|
-
const { initializeCredits } = useInitializeCredits({
|
|
324
|
-
userId: user?.uid,
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
useEffect(() => {
|
|
328
|
-
const handleRenewal = async (renewalInfo: RenewalEvent) => {
|
|
329
|
-
console.log('Subscription renewed:', renewalInfo);
|
|
330
|
-
|
|
331
|
-
const success = await initializeCredits({
|
|
332
|
-
purchaseId: renewalInfo.renewalId,
|
|
333
|
-
productId: renewalInfo.productId,
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
if (success) {
|
|
337
|
-
analytics.track('subscription_renewed', {
|
|
338
|
-
userId: user?.uid,
|
|
339
|
-
renewalId: renewalInfo.renewalId,
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
// Notify user
|
|
343
|
-
showNotification('Credits Added!', 'Your subscription has renewed');
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
const subscription = subscriptionEmitter.on('renewal', handleRenewal);
|
|
348
|
-
|
|
349
|
-
return () => subscription.remove();
|
|
350
|
-
}, []);
|
|
351
|
-
|
|
352
|
-
return null;
|
|
353
|
-
}
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
### Manual Admin Initialization
|
|
357
|
-
|
|
358
|
-
```typescript
|
|
359
|
-
function AdminCreditInitializer() {
|
|
360
|
-
const { user } = useAuth();
|
|
361
|
-
const { isAdmin } = useAdmin();
|
|
362
|
-
|
|
363
|
-
const { initializeCredits, isInitializing } = useInitializeCredits({
|
|
364
|
-
userId: targetUserId, // Admin can initialize for other users
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
const handleAdminInit = async () => {
|
|
368
|
-
if (!isAdmin) {
|
|
369
|
-
Alert.alert('Access Denied', 'Admin access required');
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
Alert.alert(
|
|
374
|
-
'Confirm Initialization',
|
|
375
|
-
'Initialize credits for this user?',
|
|
376
|
-
[
|
|
377
|
-
{ text: 'Cancel', style: 'cancel' },
|
|
378
|
-
{
|
|
379
|
-
text: 'Initialize',
|
|
380
|
-
onPress: async () => {
|
|
381
|
-
const success = await initializeCredits({
|
|
382
|
-
purchaseId: `admin_init_${Date.now()}`,
|
|
383
|
-
productId: 'admin_grant',
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
Alert.alert(
|
|
387
|
-
success ? 'Success' : 'Failed',
|
|
388
|
-
success ? 'Credits initialized' : 'Could not initialize credits'
|
|
389
|
-
);
|
|
390
|
-
},
|
|
391
|
-
},
|
|
392
|
-
]
|
|
393
|
-
);
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
if (!isAdmin) return null;
|
|
397
|
-
|
|
398
|
-
return (
|
|
399
|
-
<Button
|
|
400
|
-
onPress={handleAdminInit}
|
|
401
|
-
disabled={isInitializing}
|
|
402
|
-
title="Initialize Credits (Admin)"
|
|
403
|
-
/>
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
## Development Logging
|
|
409
|
-
|
|
410
|
-
In development mode, the hook logs useful information:
|
|
411
|
-
|
|
412
|
-
```typescript
|
|
413
|
-
// Initialization starts
|
|
414
|
-
[useInitializeCredits] Initializing: { userId: 'user-123', purchaseId: 'purchase-456', productId: 'premium_monthly' }
|
|
415
|
-
|
|
416
|
-
// Success
|
|
417
|
-
[useInitializeCredits] Success: { credits: 100, purchasedAt: '2024-01-15T10:30:00Z' }
|
|
418
|
-
|
|
419
|
-
// Error
|
|
420
|
-
[useInitializeCredits] Error: Some error message
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
## Best Practices
|
|
424
|
-
|
|
425
|
-
1. **Validate userId** - Always check user is authenticated
|
|
426
|
-
2. **Provide purchase info** - Include purchaseId and productId when possible
|
|
427
|
-
3. **Handle loading** - Show loading state during initialization
|
|
428
|
-
4. **Track success** - Log successful initializations
|
|
429
|
-
5. **Retry on failure** - Implement retry logic for reliability
|
|
430
|
-
6. **Use duplicate protection** - Repository handles duplicate purchase IDs
|
|
431
|
-
7. **Test scenarios** - Test new purchase, renewal, admin init
|
|
432
|
-
|
|
433
|
-
## Duplicate Protection
|
|
434
|
-
|
|
435
|
-
The repository prevents duplicate initialization with the same purchase ID:
|
|
436
|
-
|
|
437
|
-
```typescript
|
|
438
|
-
// First call
|
|
439
|
-
await initializeCredits({ purchaseId: 'renewal_123', productId: 'premium' });
|
|
440
|
-
// Returns: success, credits: 100 ✅
|
|
441
|
-
|
|
442
|
-
// Second call with same purchaseId
|
|
443
|
-
await initializeCredits({ purchaseId: 'renewal_123', productId: 'premium' });
|
|
444
|
-
// Returns: success, credits: 100 (same as before, not added again) ✅
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
## Related Hooks
|
|
448
|
-
|
|
449
|
-
- **useCredits** - For accessing credits balance
|
|
450
|
-
- **useDeductCredit** - For deducting credits
|
|
451
|
-
- **usePremiumWithCredits** - For premium + credits integration
|
|
452
|
-
- **useDevTestCallbacks** - For testing credit initialization
|
|
453
|
-
|
|
454
|
-
## See Also
|
|
455
|
-
|
|
456
|
-
- [Credits Repository](../../infrastructure/repositories/CreditsRepository.md)
|
|
457
|
-
- [Credits Entity](../../../domains/wallet/domain/entities/Credits.md)
|
|
458
|
-
- [Credits README](../../../domains/wallet/README.md)
|
|
87
|
+
- **useCredits**: For accessing credits balance
|
|
88
|
+
- **useDeductCredit**: For deducting credits
|
|
89
|
+
- **usePremiumWithCredits**: For premium + credits integration
|
|
90
|
+
- **useDevTestCallbacks**: For testing credit initialization
|
|
91
|
+
- **Credits Repository**: `src/domains/wallet/infrastructure/repositories/README.md`
|
|
92
|
+
- **Wallet Domain**: `src/domains/wallet/README.md`
|