@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.
Files changed (92) hide show
  1. package/README.md +211 -395
  2. package/package.json +1 -1
  3. package/src/application/README.md +46 -225
  4. package/src/application/ports/README.md +42 -97
  5. package/src/domain/README.md +36 -384
  6. package/src/domain/constants/README.md +0 -56
  7. package/src/domain/entities/README.md +43 -169
  8. package/src/domain/errors/README.md +33 -287
  9. package/src/domain/value-objects/README.md +43 -179
  10. package/src/domains/README.md +52 -0
  11. package/src/domains/README.md.bak +274 -0
  12. package/src/domains/config/README.md +93 -383
  13. package/src/domains/config/domain/README.md +37 -0
  14. package/src/domains/config/domain/entities/README.md +41 -0
  15. package/src/domains/paywall/README.md +99 -369
  16. package/src/domains/paywall/components/README.md +34 -178
  17. package/src/domains/paywall/entities/README.md +34 -193
  18. package/src/domains/paywall/hooks/README.md +34 -122
  19. package/src/domains/wallet/README.md +34 -275
  20. package/src/domains/wallet/README.md.bak +209 -0
  21. package/src/domains/wallet/domain/README.md +34 -101
  22. package/src/domains/wallet/domain/entities/README.md +34 -115
  23. package/src/domains/wallet/domain/errors/README.md +34 -151
  24. package/src/domains/wallet/infrastructure/README.md +34 -89
  25. package/src/domains/wallet/presentation/components/README.md +34 -224
  26. package/src/domains/wallet/presentation/hooks/README.md +34 -248
  27. package/src/infrastructure/README.md +37 -496
  28. package/src/infrastructure/mappers/README.md +0 -13
  29. package/src/infrastructure/repositories/README.md +74 -360
  30. package/src/infrastructure/services/README.md +95 -370
  31. package/src/presentation/README.md +123 -408
  32. package/src/presentation/README.md.bak +172 -0
  33. package/src/presentation/components/README.md +151 -179
  34. package/src/presentation/components/README.md.bak +217 -0
  35. package/src/presentation/components/details/CreditRow.md +65 -310
  36. package/src/presentation/components/details/DetailRow.md +63 -255
  37. package/src/presentation/components/details/PremiumDetailsCard.md +65 -238
  38. package/src/presentation/components/details/PremiumStatusBadge.md +64 -239
  39. package/src/presentation/components/details/README.md +97 -447
  40. package/src/presentation/components/feedback/PaywallFeedbackModal.md +63 -287
  41. package/src/presentation/components/feedback/README.md +97 -445
  42. package/src/presentation/components/paywall/PaywallModal.md +66 -416
  43. package/src/presentation/components/paywall/README.md +50 -186
  44. package/src/presentation/components/sections/README.md +97 -466
  45. package/src/presentation/components/sections/SubscriptionSection.md +92 -244
  46. package/src/presentation/hooks/README.md +154 -741
  47. package/src/presentation/hooks/useAuthAwarePurchase.md +58 -325
  48. package/src/presentation/hooks/useAuthGate.md +61 -375
  49. package/src/presentation/hooks/useAuthSubscriptionSync.md +66 -370
  50. package/src/presentation/hooks/useCreditChecker.md +73 -378
  51. package/src/presentation/hooks/useCredits.md +74 -313
  52. package/src/presentation/hooks/useCredits.md.bak +231 -0
  53. package/src/presentation/hooks/useCreditsGate.md +66 -318
  54. package/src/presentation/hooks/useDeductCredit.md +96 -156
  55. package/src/presentation/hooks/useDevTestCallbacks.md +63 -394
  56. package/src/presentation/hooks/useFeatureGate.md +105 -150
  57. package/src/presentation/hooks/useFeatureGate.md.bak +284 -0
  58. package/src/presentation/hooks/useInitializeCredits.md +64 -430
  59. package/src/presentation/hooks/usePaywall.md +61 -306
  60. package/src/presentation/hooks/usePaywallOperations.md +64 -458
  61. package/src/presentation/hooks/usePaywallVisibility.md +67 -316
  62. package/src/presentation/hooks/usePremium.md +84 -226
  63. package/src/presentation/hooks/usePremiumGate.md +60 -395
  64. package/src/presentation/hooks/usePremiumWithCredits.md +64 -401
  65. package/src/presentation/hooks/useSubscription.md +66 -422
  66. package/src/presentation/hooks/useSubscriptionDetails.md +65 -410
  67. package/src/presentation/hooks/useSubscriptionGate.md +80 -164
  68. package/src/presentation/hooks/useSubscriptionSettingsConfig.md +66 -346
  69. package/src/presentation/hooks/useSubscriptionStatus.md +66 -396
  70. package/src/presentation/hooks/useUserTier.md +63 -328
  71. package/src/presentation/hooks/useUserTierWithRepository.md +64 -424
  72. package/src/presentation/screens/README.md +48 -190
  73. package/src/presentation/types/README.md +0 -16
  74. package/src/presentation/utils/README.md +0 -21
  75. package/src/revenuecat/README.md +99 -518
  76. package/src/revenuecat/application/README.md +43 -0
  77. package/src/revenuecat/application/ports/README.md +41 -0
  78. package/src/revenuecat/domain/README.md +42 -141
  79. package/src/revenuecat/domain/constants/README.md +41 -0
  80. package/src/revenuecat/domain/entities/README.md +42 -0
  81. package/src/revenuecat/domain/errors/README.md +47 -191
  82. package/src/revenuecat/domain/types/README.md +41 -0
  83. package/src/revenuecat/domain/value-objects/README.md +41 -0
  84. package/src/revenuecat/infrastructure/README.md +41 -0
  85. package/src/revenuecat/infrastructure/config/README.md +32 -23
  86. package/src/revenuecat/infrastructure/handlers/README.md +41 -0
  87. package/src/revenuecat/infrastructure/managers/README.md +34 -42
  88. package/src/revenuecat/infrastructure/services/README.md +42 -0
  89. package/src/revenuecat/infrastructure/utils/README.md +41 -0
  90. package/src/revenuecat/presentation/README.md +42 -0
  91. package/src/revenuecat/presentation/hooks/README.md +29 -35
  92. 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
- ## Import
5
+ ## Location
6
6
 
7
- ```typescript
8
- import { useCreditsGate } from '@umituz/react-native-subscription';
9
- ```
7
+ **Import Path**: `@umituz/react-native-subscription`
10
8
 
11
- ## Signature
9
+ **File**: `src/presentation/hooks/useCreditsGate.ts`
12
10
 
13
- ```typescript
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
- ## Parameters
13
+ ## Strategy
27
14
 
28
- | Parameter | Type | Required | Description |
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
- ## Returns
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
- | Property | Type | Description |
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
- ## Basic Usage
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
- ```typescript
46
- function CreditFeature() {
47
- const { hasCredits, credits, consumeCredit } = useCreditsGate({
48
- creditCost: 5,
49
- featureId: 'export_data',
50
- });
31
+ ## Restrictions
51
32
 
52
- const handleExport = async () => {
53
- if (!hasCredits) {
54
- Alert.alert('Insufficient Credits', `You need 5 credits, have ${credits}`);
55
- return;
56
- }
33
+ ### REQUIRED
57
34
 
58
- const result = await consumeCredit();
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
- if (result.success) {
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
- return (
69
- <Button
70
- onPress={handleExport}
71
- title={`Export Data (5 credits)`}
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
- ## Advanced Usage
47
+ ### CRITICAL SAFETY
79
48
 
80
- ### With Purchase Prompt
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
- ```typescript
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
- const handleAnalyze = async () => {
91
- if (!hasCredits) {
92
- showPurchasePrompt();
93
- return;
94
- }
56
+ ### When Implementing Credit Gates
95
57
 
96
- const result = await consumeCredit();
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
- if (result.success) {
99
- await performAIAnalysis();
100
- }
101
- };
64
+ ### Integration Checklist
102
65
 
103
- return (
104
- <View>
105
- <Text>Credits: {credits}</Text>
106
- <Text>Cost: 10 credits</Text>
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
- <Button
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
- ### With Transaction Tracking
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
- ```typescript
121
- function TrackedCreditFeature() {
122
- const { consumeCredit, hasCredits } = useCreditsGate({
123
- creditCost: 3,
124
- featureId: 'filter_apply',
125
- });
86
+ ## Related Documentation
126
87
 
127
- const handleApplyFilter = async () => {
128
- const result = await consumeCredit();
129
-
130
- if (result.success) {
131
- // Track usage
132
- analytics.track('credit_consumed', {
133
- feature_id: 'filter_apply',
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`
@@ -2,159 +2,99 @@
2
2
 
3
3
  Hook for deducting credits from user balance with optimistic updates.
4
4
 
5
- ## Import
6
-
7
- ```typescript
8
- import { useDeductCredit } from '@umituz/react-native-subscription';
9
- ```
10
-
11
- ## Signature
12
-
13
- ```typescript
14
- function useDeductCredit(params: {
15
- userId: string | undefined;
16
- onCreditsExhausted?: () => void;
17
- }): {
18
- deductCredit: (cost?: number) => Promise<boolean>;
19
- deductCredits: (cost: number) => Promise<boolean>;
20
- isDeducting: boolean;
21
- }
22
- ```
23
-
24
- ## Parameters
25
-
26
- | Parameter | Type | Default | Description |
27
- |-----------|------|---------|-------------|
28
- | `userId` | `string \| undefined` | **Required** | User ID for credit deduction |
29
- | `onCreditsExhausted` | `() => void` | `undefined` | Callback when credits are exhausted |
30
-
31
- ## Returns
32
-
33
- | Property | Type | Description |
34
- |----------|------|-------------|
35
- | `deductCredit` | `(cost?: number) => Promise<boolean>` | Deduct credits (defaults to 1) |
36
- | `deductCredits` | `(cost: number) => Promise<boolean>` | Deduct specific amount |
37
- | `isDeducting` | `boolean` | Mutation is in progress |
38
-
39
- ## Basic Usage
40
-
41
- ```typescript
42
- function CreditButton() {
43
- const { user } = useAuth();
44
- const { deductCredit, isDeducting } = useDeductCredit({
45
- userId: user?.uid,
46
- onCreditsExhausted: () => {
47
- Alert.alert('Low Credits', 'Please purchase more credits');
48
- },
49
- });
50
-
51
- const handleUseFeature = async () => {
52
- const success = await deductCredit(1);
53
- if (success) {
54
- executePremiumFeature();
55
- }
56
- };
57
-
58
- return (
59
- <Button onPress={handleUseFeature} disabled={isDeducting}>
60
- Use Feature (1 Credit)
61
- </Button>
62
- );
63
- }
64
- ```
65
-
66
- ## Advanced Usage
67
-
68
- ### With Custom Cost
69
-
70
- ```typescript
71
- function FeatureWithCost() {
72
- const { deductCredit } = useDeductCredit({
73
- userId: user?.uid,
74
- });
75
-
76
- const features = {
77
- basic: { cost: 1, name: 'Basic Generation' },
78
- advanced: { cost: 5, name: 'Advanced Generation' },
79
- premium: { cost: 10, name: 'Premium Generation' },
80
- };
81
-
82
- const handleFeature = async (cost: number) => {
83
- const success = await deductCredit(cost);
84
- if (success) {
85
- console.log('Feature used');
86
- }
87
- };
88
-
89
- return (
90
- <View>
91
- {Object.entries(features).map(([key, { cost, name }]) => (
92
- <Button
93
- key={key}
94
- onPress={() => handleFeature(cost)}
95
- title={`${name} (${cost} credits)`}
96
- />
97
- ))}
98
- </View>
99
- );
100
- }
101
- ```
102
-
103
- ### With Confirmation
104
-
105
- ```typescript
106
- function CreditDeductionWithConfirmation() {
107
- const { deductCredit } = useDeductCredit({
108
- userId: user?.uid,
109
- });
110
-
111
- const handleActionWithConfirmation = async (cost: number, action: string) => {
112
- Alert.alert(
113
- 'Confirm Action',
114
- `This will cost ${cost} credit${cost > 1 ? 's' : ''}. Continue?`,
115
- [
116
- { text: 'Cancel', style: 'cancel' },
117
- {
118
- text: 'Confirm',
119
- onPress: async () => {
120
- const success = await deductCredit(cost);
121
- if (success) {
122
- await performAction(action);
123
- }
124
- },
125
- },
126
- ]
127
- );
128
- };
129
-
130
- return (
131
- <Button
132
- onPress={() => handleActionWithConfirmation(5, 'export')}
133
- title="Export Data (5 Credits)"
134
- />
135
- );
136
- }
137
- ```
138
-
139
- ## Best Practices
140
-
141
- 1. **Check balance first** - Show user if they have enough credits
142
- 2. **Handle exhausted credits** - Provide purchase option
143
- 3. **Show loading state** - Disable button during deduction
144
- 4. **Optimistic updates** - UI updates automatically
145
- 5. **Error handling** - Handle deduction failures gracefully
146
- 6. **Confirm expensive actions** - Ask before large deductions
147
- 7. **Clear messaging** - Tell users cost before deducting
148
-
149
- ## Related Hooks
150
-
151
- - **useCredits** - For accessing credits balance
152
- - **useCreditsGate** - For gating features with credits
153
- - **useInitializeCredits** - For initializing credits after purchase
154
- - **useCreditChecker** - For checking credit availability
155
-
156
- ## See Also
157
-
158
- - [Credits README](../../../domains/wallet/README.md)
159
- - [Credits Entity](../../../domains/wallet/domain/entities/Credits.md)
160
- - [Credits Repository](../../../infrastructure/repositories/CreditsRepository.md)
5
+ ## Location
6
+
7
+ **Import Path**: `@umituz/react-native-subscription`
8
+
9
+ **File**: `src/presentation/hooks/useDeductCredit.ts`
10
+
11
+ ## Strategy
12
+
13
+ ### Credit Deduction Flow
14
+
15
+ 1. **Pre-deduction Validation**
16
+ - Verify user is authenticated (userId must be defined)
17
+ - Check if sufficient credits exist
18
+ - Validate deduction amount is positive
19
+
20
+ 2. **Optimistic Update**
21
+ - Immediately update UI with new balance
22
+ - Store previous state for potential rollback
23
+ - Update TanStack Query cache
24
+
25
+ 3. **Server Synchronization**
26
+ - Send deduction request to backend
27
+ - Handle success/failure responses
28
+ - Rollback on failure
29
+
30
+ 4. **Post-deduction Handling**
31
+ - Trigger `onCreditsExhausted` callback if balance reaches zero
32
+ - Return success/failure boolean
33
+ - Reset loading state
34
+
35
+ ### Integration Points
36
+
37
+ - **Credits Repository**: `src/domains/wallet/infrastructure/repositories/CreditsRepository.ts`
38
+ - **Credits Entity**: `src/domains/wallet/domain/entities/UserCredits.ts`
39
+ - **TanStack Query**: For cache management and optimistic updates
40
+
41
+ ## Restrictions
42
+
43
+ ### REQUIRED
44
+
45
+ - **User Authentication**: `userId` parameter MUST be provided and cannot be undefined
46
+ - **Positive Amount**: Credit cost MUST be greater than zero
47
+ - **Callback Implementation**: `onCreditsExhausted` callback SHOULD be implemented to handle zero balance scenarios
48
+
49
+ ### PROHIBITED
50
+
51
+ - **NEVER** call `deductCredit` or `deductCredits` without checking `isDeducting` state first
52
+ - **NEVER** allow multiple simultaneous deduction calls for the same user
53
+ - **NEVER** deduce credits when balance is insufficient (should check with `useCreditChecker` first)
54
+ - **DO NOT** use this hook for guest users (userId undefined)
55
+
56
+ ### CRITICAL SAFETY
57
+
58
+ - **ALWAYS** check return value before proceeding with feature execution
59
+ - **ALWAYS** handle the case where deduction returns `false`
60
+ - **NEVER** assume deduction succeeded without checking return value
61
+ - **MUST** implement error boundaries when using this hook
62
+
63
+ ## AI Agent Guidelines
64
+
65
+ ### When Implementing Features
66
+
67
+ 1. **Always** check if user has sufficient credits BEFORE allowing action
68
+ 2. **Always** show the credit cost to user before deducting
69
+ 3. **Always** disable buttons while `isDeducting` is true
70
+ 4. **Always** handle the case where deduction returns false
71
+ 5. **Never** allow zero or negative credit costs
72
+
73
+ ### Integration Checklist
74
+
75
+ - [ ] Import from correct path: `@umituz/react-native-subscription`
76
+ - [ ] Provide valid `userId` from authentication context
77
+ - [ ] Implement `onCreditsExhausted` callback
78
+ - [ ] Check `isDeducting` before calling deduct functions
79
+ - [ ] Validate return value before proceeding
80
+ - [ ] Show credit cost to user before action
81
+ - [ ] Handle error cases gracefully
82
+ - [ ] Test with insufficient credits
83
+ - [ ] Test with zero balance
84
+
85
+ ### Common Patterns to Implement
86
+
87
+ 1. **Pre-check**: Use `useCreditChecker` before showing feature button
88
+ 2. **Confirmation Dialog**: Ask user before expensive operations (>5 credits)
89
+ 3. **Success Feedback**: Show success message after deduction
90
+ 4. **Failure Handling**: Show appropriate error message on failure
91
+ 5. **Purchase Flow**: Navigate to purchase screen on exhaustion
92
+
93
+ ## Related Documentation
94
+
95
+ - **useCredits**: Access current credit balance
96
+ - **useCreditChecker**: Check credit availability before operations
97
+ - **useInitializeCredits**: Initialize credits after purchase
98
+ - **useFeatureGate**: Unified feature gating with credits
99
+ - **Credits Repository**: `src/domains/wallet/infrastructure/repositories/README.md`
100
+ - **Wallet Domain**: `src/domains/wallet/README.md`