@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,345 +2,93 @@
|
|
|
2
2
|
|
|
3
3
|
Hook for gating features behind credit requirements.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Location
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
import { useCreditsGate } from '@umituz/react-native-subscription';
|
|
9
|
-
```
|
|
7
|
+
**Import Path**: `@umituz/react-native-subscription`
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
**File**: `src/presentation/hooks/useCreditsGate.ts`
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
function useCreditsGate(config: {
|
|
15
|
-
creditCost: number;
|
|
16
|
-
featureId: string;
|
|
17
|
-
}): {
|
|
18
|
-
hasCredits: boolean;
|
|
19
|
-
credits: number;
|
|
20
|
-
consumeCredit: () => Promise<CreditsResult>;
|
|
21
|
-
isLoading: boolean;
|
|
22
|
-
showPurchasePrompt: () => void;
|
|
23
|
-
}
|
|
24
|
-
```
|
|
11
|
+
**Type**: Hook
|
|
25
12
|
|
|
26
|
-
##
|
|
13
|
+
## Strategy
|
|
27
14
|
|
|
28
|
-
|
|
29
|
-
|-----------|------|----------|-------------|
|
|
30
|
-
| `config.creditCost` | `number` | Yes | Number of credits required |
|
|
31
|
-
| `config.featureId` | `string` | Yes | Unique identifier for the feature |
|
|
15
|
+
### Credit Gating Flow
|
|
32
16
|
|
|
33
|
-
|
|
17
|
+
1. **Credit Check**: Verify user has sufficient credits for feature
|
|
18
|
+
2. **Balance Display**: Show current credit balance to user
|
|
19
|
+
3. **Feature Access Control**: Enable/disable features based on credit availability
|
|
20
|
+
4. **Consumption**: Deduct credits when feature is used
|
|
21
|
+
5. **Purchase Prompt**: Guide users to purchase when insufficient
|
|
22
|
+
6. **Transaction Tracking**: Record all credit transactions
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
|----------|------|-------------|
|
|
37
|
-
| `hasCredits` | `boolean` | Whether user has enough credits |
|
|
38
|
-
| `credits` | `number` | Current credit balance |
|
|
39
|
-
| `consumeCredit` | `() => Promise<CreditsResult>` | Function to consume credits |
|
|
40
|
-
| `isLoading` | `boolean` | Whether hook is loading |
|
|
41
|
-
| `showPurchasePrompt` | `() => void` | Show purchase prompt UI |
|
|
24
|
+
### Integration Points
|
|
42
25
|
|
|
43
|
-
|
|
26
|
+
- **Credits Repository**: `src/domains/wallet/infrastructure/repositories/CreditsRepository.ts`
|
|
27
|
+
- **Credits Entity**: `src/domains/wallet/domain/entities/UserCredits.ts`
|
|
28
|
+
- **TanStack Query**: For optimistic updates and caching
|
|
29
|
+
- **Paywall Domain**: For purchase flow integration
|
|
44
30
|
|
|
45
|
-
|
|
46
|
-
function CreditFeature() {
|
|
47
|
-
const { hasCredits, credits, consumeCredit } = useCreditsGate({
|
|
48
|
-
creditCost: 5,
|
|
49
|
-
featureId: 'export_data',
|
|
50
|
-
});
|
|
31
|
+
## Restrictions
|
|
51
32
|
|
|
52
|
-
|
|
53
|
-
if (!hasCredits) {
|
|
54
|
-
Alert.alert('Insufficient Credits', `You need 5 credits, have ${credits}`);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
33
|
+
### REQUIRED
|
|
57
34
|
|
|
58
|
-
|
|
35
|
+
- **Credit Cost**: MUST specify credit cost for feature
|
|
36
|
+
- **Feature ID**: MUST provide unique feature identifier
|
|
37
|
+
- **Balance Check**: MUST verify hasCredits before allowing action
|
|
38
|
+
- **Error Handling**: MUST handle consumption failures
|
|
59
39
|
|
|
60
|
-
|
|
61
|
-
await exportData();
|
|
62
|
-
Alert.alert('Success', `Data exported! ${result.newBalance} credits remaining`);
|
|
63
|
-
} else {
|
|
64
|
-
Alert.alert('Error', result.error?.message || 'Failed to consume credits');
|
|
65
|
-
}
|
|
66
|
-
};
|
|
40
|
+
### PROHIBITED
|
|
67
41
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
disabled={!hasCredits}
|
|
73
|
-
/>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
```
|
|
42
|
+
- **NEVER** allow feature access when hasCredits is false
|
|
43
|
+
- **NEVER** consume credits without checking balance first
|
|
44
|
+
- **NEVER** assume credits will be sufficient (always check)
|
|
45
|
+
- **DO NOT** use for security decisions without server validation
|
|
77
46
|
|
|
78
|
-
|
|
47
|
+
### CRITICAL SAFETY
|
|
79
48
|
|
|
80
|
-
|
|
49
|
+
- **ALWAYS** check return value from consumeCredit
|
|
50
|
+
- **NEVER** allow negative credit balance
|
|
51
|
+
- **MUST** handle insufficient credits gracefully
|
|
52
|
+
- **ALWAYS** show credit cost to user before action
|
|
81
53
|
|
|
82
|
-
|
|
83
|
-
function AdvancedCreditFeature() {
|
|
84
|
-
const { hasCredits, credits, consumeCredit, showPurchasePrompt } =
|
|
85
|
-
useCreditsGate({
|
|
86
|
-
creditCost: 10,
|
|
87
|
-
featureId: 'ai_analysis',
|
|
88
|
-
});
|
|
54
|
+
## AI Agent Guidelines
|
|
89
55
|
|
|
90
|
-
|
|
91
|
-
if (!hasCredits) {
|
|
92
|
-
showPurchasePrompt();
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
56
|
+
### When Implementing Credit Gates
|
|
95
57
|
|
|
96
|
-
|
|
58
|
+
1. **Always** display credit cost to user before action
|
|
59
|
+
2. **Always** check hasCredits before enabling buttons
|
|
60
|
+
3. **Always** handle consumeCredit result
|
|
61
|
+
4. **Never** allow action when credits are insufficient
|
|
62
|
+
5. **Always** provide purchase path for credits
|
|
97
63
|
|
|
98
|
-
|
|
99
|
-
await performAIAnalysis();
|
|
100
|
-
}
|
|
101
|
-
};
|
|
64
|
+
### Integration Checklist
|
|
102
65
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
66
|
+
- [ ] Import from correct path: `@umituz/react-native-subscription`
|
|
67
|
+
- [ ] Specify credit cost in config
|
|
68
|
+
- [ ] Provide unique feature ID
|
|
69
|
+
- [ ] Check hasCredits before enabling feature
|
|
70
|
+
- [ ] Handle consumeCredit result
|
|
71
|
+
- [ ] Show credit cost in UI
|
|
72
|
+
- [ ] Display current balance
|
|
73
|
+
- [ ] Implement purchase prompt for insufficient credits
|
|
74
|
+
- [ ] Test with zero balance
|
|
75
|
+
- [ ] Test with insufficient credits
|
|
76
|
+
- [ ] Test with sufficient credits
|
|
107
77
|
|
|
108
|
-
|
|
109
|
-
onPress={handleAnalyze}
|
|
110
|
-
title={hasCredits ? 'Analyze (10 credits)' : 'Get More Credits'}
|
|
111
|
-
disabled={!hasCredits && credits < 10}
|
|
112
|
-
/>
|
|
113
|
-
</View>
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
```
|
|
78
|
+
### Common Patterns
|
|
117
79
|
|
|
118
|
-
|
|
80
|
+
1. **Pre-check**: Verify balance before showing feature
|
|
81
|
+
2. **Confirmation**: Ask user before expensive operations
|
|
82
|
+
3. **Success Feedback**: Show message after successful consumption
|
|
83
|
+
4. **Failure Handling**: Display appropriate error on failure
|
|
84
|
+
5. **Purchase Flow**: Navigate to purchase screen on exhaustion
|
|
119
85
|
|
|
120
|
-
|
|
121
|
-
function TrackedCreditFeature() {
|
|
122
|
-
const { consumeCredit, hasCredits } = useCreditsGate({
|
|
123
|
-
creditCost: 3,
|
|
124
|
-
featureId: 'filter_apply',
|
|
125
|
-
});
|
|
86
|
+
## Related Documentation
|
|
126
87
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
amount: 3,
|
|
135
|
-
transaction_id: result.transaction?.id,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// Apply filter
|
|
139
|
-
await applyFilter();
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
return <Button onPress={handleApplyFilter} title="Apply Filter (3 credits)" />;
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### With Loading State
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
function CreditFeatureWithLoading() {
|
|
151
|
-
const { consumeCredit, isLoading, hasCredits } = useCreditsGate({
|
|
152
|
-
creditCost: 5,
|
|
153
|
-
featureId: 'premium_template',
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
const handleUse = async () => {
|
|
157
|
-
if (!hasCredits) return;
|
|
158
|
-
|
|
159
|
-
const result = await consumeCredit();
|
|
160
|
-
|
|
161
|
-
if (result.success) {
|
|
162
|
-
// Show loading while processing
|
|
163
|
-
await processFeature();
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
return (
|
|
168
|
-
<View>
|
|
169
|
-
<Button
|
|
170
|
-
onPress={handleUse}
|
|
171
|
-
disabled={isLoading || !hasCredits}
|
|
172
|
-
title={isLoading ? 'Processing...' : 'Use Feature (5 credits)'}
|
|
173
|
-
/>
|
|
174
|
-
</View>
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
## Examples
|
|
180
|
-
|
|
181
|
-
### Credit-Based Action Button
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
function CreditActionButton({ featureId, cost, action, label }) {
|
|
185
|
-
const { hasCredits, credits, consumeCredit } = useCreditsGate({
|
|
186
|
-
creditCost: cost,
|
|
187
|
-
featureId,
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
const handlePress = async () => {
|
|
191
|
-
if (!hasCredits) {
|
|
192
|
-
showInsufficientCreditsDialog(cost, credits);
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const result = await consumeCredit();
|
|
197
|
-
if (result.success) {
|
|
198
|
-
await action();
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
return (
|
|
203
|
-
<TouchableOpacity
|
|
204
|
-
onPress={handlePress}
|
|
205
|
-
disabled={!hasCredits}
|
|
206
|
-
style={hasCredits ? styles.buttonEnabled : styles.buttonDisabled}
|
|
207
|
-
>
|
|
208
|
-
<Text style={styles.buttonText}>{label}</Text>
|
|
209
|
-
<Text style={styles.costText}>{cost} credits</Text>
|
|
210
|
-
</TouchableOpacity>
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### Credit Balance Display
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
function CreditBalanceDisplay() {
|
|
219
|
-
const { credits, isLoading } = useCreditsGate({
|
|
220
|
-
creditCost: 1,
|
|
221
|
-
featureId: 'any',
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
return (
|
|
225
|
-
<View style={styles.balanceContainer}>
|
|
226
|
-
<Text style={styles.balanceLabel}>Your Credits:</Text>
|
|
227
|
-
|
|
228
|
-
{isLoading ? (
|
|
229
|
-
<ActivityIndicator size="small" />
|
|
230
|
-
) : (
|
|
231
|
-
<Text style={styles.balanceValue}>{credits}</Text>
|
|
232
|
-
)}
|
|
233
|
-
</View>
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Multiple Credit Tiers
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
function TieredFeatureAccess() {
|
|
242
|
-
const { credits: basicCredits, hasCredits: hasBasic } = useCreditsGate({
|
|
243
|
-
creditCost: 5,
|
|
244
|
-
featureId: 'basic_feature',
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
const { credits: proCredits, hasCredits: hasPro } = useCreditsGate({
|
|
248
|
-
creditCost: 20,
|
|
249
|
-
featureId: 'pro_feature',
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
return (
|
|
253
|
-
<View>
|
|
254
|
-
<Button
|
|
255
|
-
onPress={handleBasicFeature}
|
|
256
|
-
disabled={!hasBasic}
|
|
257
|
-
title={`Basic Feature (5 credits)`}
|
|
258
|
-
/>
|
|
259
|
-
|
|
260
|
-
<Button
|
|
261
|
-
onPress={handleProFeature}
|
|
262
|
-
disabled={!hasPro}
|
|
263
|
-
title={`Pro Feature (20 credits)`}
|
|
264
|
-
/>
|
|
265
|
-
|
|
266
|
-
<Text>Balance: {basicCredits} credits</Text>
|
|
267
|
-
</View>
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
## Result Type
|
|
273
|
-
|
|
274
|
-
```typescript
|
|
275
|
-
interface CreditsResult {
|
|
276
|
-
success: boolean;
|
|
277
|
-
newBalance?: number;
|
|
278
|
-
transaction?: {
|
|
279
|
-
id: string;
|
|
280
|
-
amount: number;
|
|
281
|
-
reason: string;
|
|
282
|
-
timestamp: string;
|
|
283
|
-
};
|
|
284
|
-
error?: Error;
|
|
285
|
-
}
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
## Error Handling
|
|
289
|
-
|
|
290
|
-
```typescript
|
|
291
|
-
function RobustCreditFeature() {
|
|
292
|
-
const { consumeCredit } = useCreditsGate({
|
|
293
|
-
creditCost: 10,
|
|
294
|
-
featureId: 'robust_feature',
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
const handleAction = async () => {
|
|
298
|
-
const result = await consumeCredit();
|
|
299
|
-
|
|
300
|
-
if (!result.success) {
|
|
301
|
-
if (result.error?.message.includes('Insufficient')) {
|
|
302
|
-
Alert.alert('Insufficient Credits', 'Please purchase more credits');
|
|
303
|
-
} else if (result.error?.message.includes('Network')) {
|
|
304
|
-
Alert.alert('Network Error', 'Please check your connection');
|
|
305
|
-
} else {
|
|
306
|
-
Alert.alert('Error', 'Failed to process. Please try again');
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Log error
|
|
310
|
-
analytics.track('credit_consumption_failed', {
|
|
311
|
-
feature_id: 'robust_feature',
|
|
312
|
-
error: result.error?.message,
|
|
313
|
-
});
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// Success
|
|
318
|
-
await executeFeature();
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
return <Button onPress={handleAction} title="Execute (10 credits)" />;
|
|
322
|
-
}
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
## Best Practices
|
|
326
|
-
|
|
327
|
-
1. **Always check `hasCredits`** before enabling actions
|
|
328
|
-
2. **Show credit cost** in UI
|
|
329
|
-
3. **Handle errors gracefully**
|
|
330
|
-
4. **Provide purchase prompt** when credits are insufficient
|
|
331
|
-
5. **Display current balance**
|
|
332
|
-
6. **Track credit consumption** in analytics
|
|
333
|
-
7. **Refetch balance** after consumption
|
|
334
|
-
|
|
335
|
-
## Related Hooks
|
|
336
|
-
|
|
337
|
-
- **useCredits** - For credit balance only
|
|
338
|
-
- **useDeductCredit** - For manual credit deduction
|
|
339
|
-
- **usePremiumWithCredits** - For premium OR credits access
|
|
340
|
-
- **useCreditChecker** - For simple credit checks
|
|
341
|
-
|
|
342
|
-
## See Also
|
|
343
|
-
|
|
344
|
-
- [useCredits](./useCredits.md)
|
|
345
|
-
- [useDeductCredit](./useDeductCredit.md)
|
|
346
|
-
- [usePremiumWithCredits](./usePremiumWithCredits.md)
|
|
88
|
+
- **useCredits**: Access current credit balance
|
|
89
|
+
- **useDeductCredit**: Manual credit deduction with optimistic updates
|
|
90
|
+
- **useCreditChecker**: Simple credit validation
|
|
91
|
+
- **usePremiumWithCredits**: Hybrid premium/credits access
|
|
92
|
+
- **useFeatureGate**: Unified feature gating
|
|
93
|
+
- **Credits Repository**: `src/domains/wallet/infrastructure/repositories/README.md`
|
|
94
|
+
- **Wallet Domain**: `src/domains/wallet/README.md`
|
|
@@ -60,82 +60,6 @@ Hook for deducting credits from user balance with optimistic updates.
|
|
|
60
60
|
- **NEVER** assume deduction succeeded without checking return value
|
|
61
61
|
- **MUST** implement error boundaries when using this hook
|
|
62
62
|
|
|
63
|
-
## Rules
|
|
64
|
-
|
|
65
|
-
### Initialization
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
// CORRECT
|
|
69
|
-
const { deductCredit, isDeducting } = useDeductCredit({
|
|
70
|
-
userId: user?.uid,
|
|
71
|
-
onCreditsExhausted: () => showPaywall(),
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// INCORRECT - Missing callback
|
|
75
|
-
const { deductCredit } = useDeductCredit({
|
|
76
|
-
userId: user?.uid,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// INCORRECT - userId undefined
|
|
80
|
-
const { deductCredit } = useDeductCredit({
|
|
81
|
-
userId: undefined,
|
|
82
|
-
});
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Deduction Execution
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
// CORRECT - Check return value
|
|
89
|
-
const success = await deductCredit(5);
|
|
90
|
-
if (success) {
|
|
91
|
-
executeFeature();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// INCORRECT - No return value check
|
|
95
|
-
await deductCredit(5);
|
|
96
|
-
executeFeature(); // May execute even if deduction failed
|
|
97
|
-
|
|
98
|
-
// INCORRECT - Multiple simultaneous calls
|
|
99
|
-
Promise.all([
|
|
100
|
-
deductCredit(5),
|
|
101
|
-
deductCredit(3), // Race condition!
|
|
102
|
-
]);
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Loading States
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
// CORRECT - Respect loading state
|
|
109
|
-
<Button onPress={handleDeduct} disabled={isDeducting}>
|
|
110
|
-
{isDeducting ? 'Deducting...' : 'Use Feature'}
|
|
111
|
-
</Button>
|
|
112
|
-
|
|
113
|
-
// INCORRECT - Ignore loading state
|
|
114
|
-
<Button onPress={handleDeduct}>
|
|
115
|
-
Use Feature
|
|
116
|
-
</Button>
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### Credit Exhaustion Handling
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
// CORRECT - Implement callback
|
|
123
|
-
const { deductCredit } = useDeductCredit({
|
|
124
|
-
userId: user?.uid,
|
|
125
|
-
onCreditsExhausted: () => {
|
|
126
|
-
navigation.navigate('CreditPackages');
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// MINIMUM - Show alert
|
|
131
|
-
const { deductCredit } = useDeductCredit({
|
|
132
|
-
userId: user?.uid,
|
|
133
|
-
onCreditsExhausted: () => {
|
|
134
|
-
Alert.alert('No Credits', 'Please purchase more credits');
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
```
|
|
138
|
-
|
|
139
63
|
## AI Agent Guidelines
|
|
140
64
|
|
|
141
65
|
### When Implementing Features
|
|
@@ -9,7 +9,7 @@ import type { UserCredits } from "../../domain/entities/Credits";
|
|
|
9
9
|
import { getCreditsRepository } from "../../infrastructure/repositories/CreditsRepositoryProvider";
|
|
10
10
|
import { creditsQueryKeys } from "./useCredits";
|
|
11
11
|
|
|
12
|
-
import { timezoneService } from "@umituz/react-native-
|
|
12
|
+
import { timezoneService } from "@umituz/react-native-design-system";
|
|
13
13
|
|
|
14
14
|
export interface UseDeductCreditParams {
|
|
15
15
|
userId: string | undefined;
|