@umituz/react-native-subscription 2.26.14 โ 2.26.16
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/package.json +1 -1
- package/src/domains/paywall/components/PaywallModal.tsx +36 -13
- package/src/domains/paywall/components/PlanCard.tsx +16 -3
- package/src/domains/paywall/entities/types.ts +4 -0
- package/src/domains/paywall/hooks/usePaywallTranslations.ts +8 -0
- package/src/presentation/hooks/index.ts +0 -13
- package/src/presentation/hooks/useFeatureGate.ts +12 -33
- package/src/revenuecat/domain/types/RevenueCatTypes.ts +32 -0
- package/src/revenuecat/index.ts +1 -0
- package/src/revenuecat/presentation/hooks/useRevenueCatTrialEligibility.ts +179 -0
- package/src/presentation/hooks/useAuthAwarePurchase.md +0 -92
- package/src/presentation/hooks/useAuthGate.md +0 -89
- package/src/presentation/hooks/useAuthGate.ts +0 -65
- package/src/presentation/hooks/useCreditChecker.md +0 -102
- package/src/presentation/hooks/useCreditChecker.ts +0 -41
- package/src/presentation/hooks/useCreditsGate.md +0 -94
- package/src/presentation/hooks/useCreditsGate.ts +0 -67
- package/src/presentation/hooks/useDevTestCallbacks.md +0 -91
- package/src/presentation/hooks/useDevTestCallbacks.ts +0 -142
- package/src/presentation/hooks/useInitializeCredits.md +0 -92
- package/src/presentation/hooks/useInitializeCredits.ts +0 -57
- package/src/presentation/hooks/usePremiumGate.md +0 -88
- package/src/presentation/hooks/usePremiumGate.ts +0 -116
- package/src/presentation/hooks/usePremiumWithCredits.md +0 -92
- package/src/presentation/hooks/usePremiumWithCredits.ts +0 -48
- package/src/presentation/hooks/useSubscription.md +0 -94
- package/src/presentation/hooks/useSubscription.ts +0 -119
- package/src/presentation/hooks/useSubscriptionDetails.md +0 -93
- package/src/presentation/hooks/useSubscriptionDetails.ts +0 -85
- package/src/presentation/hooks/useSubscriptionGate.md +0 -84
- package/src/presentation/hooks/useSubscriptionGate.ts +0 -67
- package/src/presentation/hooks/useSubscriptionStatus.md +0 -94
- package/src/presentation/hooks/useTrialEligibility.ts +0 -66
- package/src/presentation/hooks/useUserTier.md +0 -91
- package/src/presentation/hooks/useUserTier.ts +0 -78
- package/src/presentation/hooks/useUserTierWithRepository.md +0 -92
- package/src/presentation/hooks/useUserTierWithRepository.ts +0 -151
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# useAuthGate Hook
|
|
2
|
-
|
|
3
|
-
Hook for combining authentication and subscription gating.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
**Import Path**: `@umituz/react-native-subscription`
|
|
8
|
-
|
|
9
|
-
**File**: `src/presentation/hooks/useAuthGate.ts`
|
|
10
|
-
|
|
11
|
-
**Type**: Hook
|
|
12
|
-
|
|
13
|
-
## Strategy
|
|
14
|
-
|
|
15
|
-
### Auth Gate Flow
|
|
16
|
-
|
|
17
|
-
1. **Authentication Check**: Verify if user is authenticated
|
|
18
|
-
2. **Subscription Check**: Verify if user has required subscription
|
|
19
|
-
3. **Authorization Evaluation**: Combine auth + subscription status
|
|
20
|
-
4. **Gate Actions**: Provide functions to gate features
|
|
21
|
-
5. **Sign In Flow**: Trigger authentication when required
|
|
22
|
-
6. **Upgrade Flow**: Trigger subscription when required
|
|
23
|
-
|
|
24
|
-
### Integration Points
|
|
25
|
-
|
|
26
|
-
- **Auth Context**: User authentication state
|
|
27
|
-
- **Subscription Repository**: `src/infrastructure/repositories/SubscriptionRepository.ts`
|
|
28
|
-
- **Paywall Domain**: For subscription upgrade flow
|
|
29
|
-
- **Auth UI**: For sign-in/sign-up flows
|
|
30
|
-
|
|
31
|
-
## Restrictions
|
|
32
|
-
|
|
33
|
-
### REQUIRED
|
|
34
|
-
|
|
35
|
-
- **Loading State**: MUST handle loading state
|
|
36
|
-
- **Authorization Check**: MUST verify isAuthorized before showing protected content
|
|
37
|
-
- **Callback Implementation**: MUST implement onAuthRequired/onSubscriptionRequired callbacks
|
|
38
|
-
|
|
39
|
-
### PROHIBITED
|
|
40
|
-
|
|
41
|
-
- **NEVER** show protected content without checking isAuthorized
|
|
42
|
-
- **NEVER** use for security decisions without server validation
|
|
43
|
-
- **DO NOT** assume user is authenticated or subscribed
|
|
44
|
-
|
|
45
|
-
### CRITICAL SAFETY
|
|
46
|
-
|
|
47
|
-
- **ALWAYS** check isAuthorized before showing protected features
|
|
48
|
-
- **NEVER** trust client-side state for security
|
|
49
|
-
- **MUST** implement proper auth flow
|
|
50
|
-
- **ALWAYS** handle all states (loading, authorized, unauthorized)
|
|
51
|
-
|
|
52
|
-
## AI Agent Guidelines
|
|
53
|
-
|
|
54
|
-
### When Implementing Auth Gates
|
|
55
|
-
|
|
56
|
-
1. **Always** check loading state first
|
|
57
|
-
2. **Always** verify isAuthorized before showing content
|
|
58
|
-
3. **Always** provide sign-in option for unauthenticated users
|
|
59
|
-
4. **Always** provide upgrade option for non-subscribed users
|
|
60
|
-
5. **Never** bypass auth checks for convenience
|
|
61
|
-
|
|
62
|
-
### Integration Checklist
|
|
63
|
-
|
|
64
|
-
- [ ] Import from correct path: `@umituz/react-native-subscription`
|
|
65
|
-
- [ ] Configure requireAuth and requireSubscription
|
|
66
|
-
- [ ] Handle loading state
|
|
67
|
-
- [ ] Check isAuthorized before showing content
|
|
68
|
-
- [ ] Implement sign-in callback
|
|
69
|
-
- [ ] Implement subscription upgrade callback
|
|
70
|
-
- [ ] Test with unauthenticated user
|
|
71
|
-
- [ ] Test with authenticated non-subscribed user
|
|
72
|
-
- [ ] Test with authenticated subscribed user
|
|
73
|
-
- [ ] Test loading states
|
|
74
|
-
|
|
75
|
-
### Common Patterns
|
|
76
|
-
|
|
77
|
-
1. **Auth Only**: Require authentication only
|
|
78
|
-
2. **Subscription Only**: Require subscription only (auth handled internally)
|
|
79
|
-
3. **Both**: Require both auth and subscription
|
|
80
|
-
4. **Conditional Gates**: Different requirements per feature
|
|
81
|
-
5. **Nested Gates**: Layer multiple gate conditions
|
|
82
|
-
|
|
83
|
-
## Related Documentation
|
|
84
|
-
|
|
85
|
-
- **useAuth**: Authentication state
|
|
86
|
-
- **usePremiumGate**: Premium-only gating
|
|
87
|
-
- **useSubscriptionGate**: Subscription-only gating
|
|
88
|
-
- **useFeatureGate**: Unified feature gating
|
|
89
|
-
- **Auth Domain**: `src/domains/config/README.md`
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useAuthGate Hook
|
|
3
|
-
*
|
|
4
|
-
* Single responsibility: Authentication gating
|
|
5
|
-
* Checks if user is authenticated before allowing actions.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* const { requireAuth, isAuthenticated } = useAuthGate({
|
|
10
|
-
* isAuthenticated: !!user && !user.isAnonymous,
|
|
11
|
-
* onAuthRequired: (callback) => showAuthModal(callback),
|
|
12
|
-
* });
|
|
13
|
-
*
|
|
14
|
-
* const handleAction = () => {
|
|
15
|
-
* requireAuth(() => doSomething());
|
|
16
|
-
* };
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { useCallback } from "react";
|
|
21
|
-
|
|
22
|
-
declare const __DEV__: boolean;
|
|
23
|
-
|
|
24
|
-
export interface UseAuthGateParams {
|
|
25
|
-
/** Whether user is authenticated (not guest/anonymous) */
|
|
26
|
-
isAuthenticated: boolean;
|
|
27
|
-
/** Callback when auth is required - receives pending action callback */
|
|
28
|
-
onAuthRequired: (pendingCallback: () => void | Promise<void>) => void;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface UseAuthGateResult {
|
|
32
|
-
/** Whether user is authenticated */
|
|
33
|
-
isAuthenticated: boolean;
|
|
34
|
-
/** Gate action behind auth - executes if authenticated, else shows auth modal */
|
|
35
|
-
requireAuth: (action: () => void | Promise<void>) => boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function useAuthGate(params: UseAuthGateParams): UseAuthGateResult {
|
|
39
|
-
const { isAuthenticated, onAuthRequired } = params;
|
|
40
|
-
|
|
41
|
-
const requireAuth = useCallback(
|
|
42
|
-
(action: () => void | Promise<void>): boolean => {
|
|
43
|
-
if (!isAuthenticated) {
|
|
44
|
-
if (__DEV__) {
|
|
45
|
-
|
|
46
|
-
console.log("[useAuthGate] Not authenticated, showing auth modal");
|
|
47
|
-
}
|
|
48
|
-
onAuthRequired(action);
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (__DEV__) {
|
|
53
|
-
|
|
54
|
-
console.log("[useAuthGate] Authenticated, proceeding");
|
|
55
|
-
}
|
|
56
|
-
return true;
|
|
57
|
-
},
|
|
58
|
-
[isAuthenticated, onAuthRequired]
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
isAuthenticated,
|
|
63
|
-
requireAuth,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
# useCreditChecker Hook
|
|
2
|
-
|
|
3
|
-
Simple hook for checking if user has sufficient credits before operations.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
**Import Path**: `@umituz/react-native-subscription`
|
|
8
|
-
|
|
9
|
-
**File**: `src/presentation/hooks/useCreditChecker.ts`
|
|
10
|
-
|
|
11
|
-
**Type**: Hook
|
|
12
|
-
|
|
13
|
-
## Strategy
|
|
14
|
-
|
|
15
|
-
### Credit Validation Flow
|
|
16
|
-
|
|
17
|
-
1. **Initial Check**
|
|
18
|
-
- Compare current balance against required amount
|
|
19
|
-
- Return boolean result immediately
|
|
20
|
-
- No network calls required (uses cached balance)
|
|
21
|
-
|
|
22
|
-
2. **Real-time Updates**
|
|
23
|
-
- Automatically re-checks when credits change
|
|
24
|
-
- Updates result via `useCredits` hook
|
|
25
|
-
- Triggers re-renders on balance changes
|
|
26
|
-
|
|
27
|
-
3. **Manual Refresh**
|
|
28
|
-
- Optionally trigger manual credit check
|
|
29
|
-
- Useful before expensive operations
|
|
30
|
-
- Validates current state before action
|
|
31
|
-
|
|
32
|
-
### Integration Points
|
|
33
|
-
|
|
34
|
-
- **useCredits**: For fetching current credit balance
|
|
35
|
-
- **useDeductCredit**: For deducting credits after check
|
|
36
|
-
- **Credit Checking UI**: Pre-action validation displays
|
|
37
|
-
- **Purchase Flows**: Redirect to credit packages
|
|
38
|
-
|
|
39
|
-
## Restrictions
|
|
40
|
-
|
|
41
|
-
### REQUIRED
|
|
42
|
-
|
|
43
|
-
- **Required Amount**: MUST specify positive credit cost
|
|
44
|
-
- **Balance Check**: MUST verify `hasEnoughCredits` before action
|
|
45
|
-
- **User Feedback**: MUST show credit cost to user
|
|
46
|
-
|
|
47
|
-
### PROHIBITED
|
|
48
|
-
|
|
49
|
-
- **NEVER** assume credits are sufficient without checking
|
|
50
|
-
- **NEVER** use for security decisions (server-side validation required)
|
|
51
|
-
- **DO NOT** deduct credits with this hook (use `useDeductCredit`)
|
|
52
|
-
- **NEVER** hardcode credit costs (should be configurable)
|
|
53
|
-
|
|
54
|
-
### CRITICAL SAFETY
|
|
55
|
-
|
|
56
|
-
- **ALWAYS** check return value before proceeding with action
|
|
57
|
-
- **ALWAYS** show credit cost to user before execution
|
|
58
|
-
- **NEVER** trust client-side check for security (server must validate)
|
|
59
|
-
- **MUST** handle case where credits become insufficient between check and action
|
|
60
|
-
|
|
61
|
-
## AI Agent Guidelines
|
|
62
|
-
|
|
63
|
-
### When Implementing Credit Checks
|
|
64
|
-
|
|
65
|
-
1. **Always** specify positive credit cost
|
|
66
|
-
2. **Always** check `hasEnoughCredits` before action
|
|
67
|
-
3. **Always** show credit cost to user in UI
|
|
68
|
-
4. **Always** provide upgrade path when insufficient
|
|
69
|
-
5. **Never** use for security decisions (server validation required)
|
|
70
|
-
|
|
71
|
-
### Integration Checklist
|
|
72
|
-
|
|
73
|
-
- [ ] Import from correct path: `@umituz/react-native-subscription`
|
|
74
|
-
- [ ] Specify positive credit cost
|
|
75
|
-
- [ ] Check `hasEnoughCredits` before action
|
|
76
|
-
- [ ] Display credit cost to user
|
|
77
|
-
- [ ] Show upgrade/purchase option when insufficient
|
|
78
|
-
- [ ] Validate credit cost is positive number
|
|
79
|
-
- [ ] Test with sufficient credits
|
|
80
|
-
- [ ] Test with insufficient credits
|
|
81
|
-
- [ ] Test with zero credits
|
|
82
|
-
- [ ] Test credit changes between check and action
|
|
83
|
-
|
|
84
|
-
### Common Patterns to Implement
|
|
85
|
-
|
|
86
|
-
1. **Pre-action Validation**: Check before showing button
|
|
87
|
-
2. **Cost Display**: Always show credit cost to user
|
|
88
|
-
3. **Upgrade Prompts**: Link to credit packages when low
|
|
89
|
-
4. **Manual Refresh**: Check again before expensive operations
|
|
90
|
-
5. **Credit Deduction**: Use with `useDeductCredit` for complete flow
|
|
91
|
-
6. **Visual Feedback**: Disable buttons when insufficient
|
|
92
|
-
7. **Warning Messages**: Alert user before high-cost operations
|
|
93
|
-
8. **Balance Display**: Show current balance alongside cost
|
|
94
|
-
|
|
95
|
-
## Related Documentation
|
|
96
|
-
|
|
97
|
-
- **useCredits**: Access current credit balance
|
|
98
|
-
- **useDeductCredit**: Deduct credits after check passes
|
|
99
|
-
- **useCreditsGate**: Complete credit gating with deduction
|
|
100
|
-
- **useFeatureGate**: Unified feature gating with credits
|
|
101
|
-
- **Credits Repository**: `src/domains/wallet/infrastructure/repositories/README.md`
|
|
102
|
-
- **Wallet Domain**: `src/domains/wallet/README.md`
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useCreditChecker Hook
|
|
3
|
-
*
|
|
4
|
-
* Provides credit checking utilities using module-level repository.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { useMemo } from "react";
|
|
8
|
-
import { getCreditsRepository } from "../../infrastructure/repositories/CreditsRepositoryProvider";
|
|
9
|
-
import {
|
|
10
|
-
createCreditChecker,
|
|
11
|
-
type CreditCheckResult,
|
|
12
|
-
} from "../../utils/creditChecker";
|
|
13
|
-
|
|
14
|
-
export interface UseCreditCheckerParams {
|
|
15
|
-
onCreditDeducted?: (userId: string, cost: number) => void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface UseCreditCheckerResult {
|
|
19
|
-
checkCreditsAvailable: (
|
|
20
|
-
userId: string | undefined,
|
|
21
|
-
cost?: number
|
|
22
|
-
) => Promise<CreditCheckResult>;
|
|
23
|
-
deductCreditsAfterSuccess: (
|
|
24
|
-
userId: string | undefined,
|
|
25
|
-
cost?: number
|
|
26
|
-
) => Promise<void>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const useCreditChecker = (
|
|
30
|
-
params?: UseCreditCheckerParams
|
|
31
|
-
): UseCreditCheckerResult => {
|
|
32
|
-
const repository = getCreditsRepository();
|
|
33
|
-
const onCreditDeducted = params?.onCreditDeducted;
|
|
34
|
-
|
|
35
|
-
const checker = useMemo(
|
|
36
|
-
() => createCreditChecker({ repository, onCreditDeducted }),
|
|
37
|
-
[repository, onCreditDeducted]
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
return checker;
|
|
41
|
-
};
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# useCreditsGate Hook
|
|
2
|
-
|
|
3
|
-
Hook for gating features behind credit requirements.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
**Import Path**: `@umituz/react-native-subscription`
|
|
8
|
-
|
|
9
|
-
**File**: `src/presentation/hooks/useCreditsGate.ts`
|
|
10
|
-
|
|
11
|
-
**Type**: Hook
|
|
12
|
-
|
|
13
|
-
## Strategy
|
|
14
|
-
|
|
15
|
-
### Credit Gating Flow
|
|
16
|
-
|
|
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
|
|
23
|
-
|
|
24
|
-
### Integration Points
|
|
25
|
-
|
|
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
|
|
30
|
-
|
|
31
|
-
## Restrictions
|
|
32
|
-
|
|
33
|
-
### REQUIRED
|
|
34
|
-
|
|
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
|
|
39
|
-
|
|
40
|
-
### PROHIBITED
|
|
41
|
-
|
|
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
|
|
46
|
-
|
|
47
|
-
### CRITICAL SAFETY
|
|
48
|
-
|
|
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
|
|
53
|
-
|
|
54
|
-
## AI Agent Guidelines
|
|
55
|
-
|
|
56
|
-
### When Implementing Credit Gates
|
|
57
|
-
|
|
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
|
|
63
|
-
|
|
64
|
-
### Integration Checklist
|
|
65
|
-
|
|
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
|
|
77
|
-
|
|
78
|
-
### Common Patterns
|
|
79
|
-
|
|
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
|
|
85
|
-
|
|
86
|
-
## Related Documentation
|
|
87
|
-
|
|
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`
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useCreditsGate Hook
|
|
3
|
-
*
|
|
4
|
-
* Single responsibility: Credits gating
|
|
5
|
-
* Uses ref pattern to avoid stale closure issues.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { useCallback, useRef, useEffect } from "react";
|
|
9
|
-
|
|
10
|
-
declare const __DEV__: boolean;
|
|
11
|
-
|
|
12
|
-
export interface UseCreditsGateParams {
|
|
13
|
-
readonly creditBalance: number;
|
|
14
|
-
readonly requiredCredits?: number;
|
|
15
|
-
readonly onCreditsRequired: (requiredCredits?: number) => void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface UseCreditsGateResult {
|
|
19
|
-
readonly hasCredits: boolean;
|
|
20
|
-
readonly creditBalance: number;
|
|
21
|
-
readonly requireCredits: () => boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function useCreditsGate(
|
|
25
|
-
params: UseCreditsGateParams
|
|
26
|
-
): UseCreditsGateResult {
|
|
27
|
-
const { creditBalance, requiredCredits = 1, onCreditsRequired } = params;
|
|
28
|
-
|
|
29
|
-
const creditBalanceRef = useRef(creditBalance);
|
|
30
|
-
const onCreditsRequiredRef = useRef(onCreditsRequired);
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
creditBalanceRef.current = creditBalance;
|
|
34
|
-
}, [creditBalance]);
|
|
35
|
-
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
onCreditsRequiredRef.current = onCreditsRequired;
|
|
38
|
-
}, [onCreditsRequired]);
|
|
39
|
-
|
|
40
|
-
const hasCredits = creditBalance >= requiredCredits;
|
|
41
|
-
|
|
42
|
-
const requireCredits = useCallback((): boolean => {
|
|
43
|
-
const currentBalance = creditBalanceRef.current;
|
|
44
|
-
const canAfford = currentBalance >= requiredCredits;
|
|
45
|
-
|
|
46
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
47
|
-
console.log("[useCreditsGate] requireCredits", {
|
|
48
|
-
currentBalance,
|
|
49
|
-
requiredCredits,
|
|
50
|
-
canAfford,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (!canAfford) {
|
|
55
|
-
onCreditsRequiredRef.current(requiredCredits);
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return true;
|
|
60
|
-
}, [requiredCredits]);
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
hasCredits,
|
|
64
|
-
creditBalance,
|
|
65
|
-
requireCredits,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# useDevTestCallbacks Hook
|
|
2
|
-
|
|
3
|
-
**Development-only** hook for testing subscription renewal and credit operations.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
**Import Path**: `@umituz/react-native-subscription`
|
|
8
|
-
|
|
9
|
-
**File**: `src/presentation/hooks/useDevTestCallbacks.ts`
|
|
10
|
-
|
|
11
|
-
**Type**: Hook
|
|
12
|
-
|
|
13
|
-
## Strategy
|
|
14
|
-
|
|
15
|
-
### Development Testing Utilities
|
|
16
|
-
|
|
17
|
-
1. **Renewal Simulation**: Simulate subscription renewal with credit allocation
|
|
18
|
-
2. **Credits Inspection**: Display current credit balance and purchase date
|
|
19
|
-
3. **Duplicate Protection Testing**: Test that duplicate renewals are prevented
|
|
20
|
-
4. **Development Mode Guard**: Only available in `__DEV__` mode
|
|
21
|
-
5. **Production Safety**: Returns `undefined` in production builds
|
|
22
|
-
6. **Alert-Based Feedback**: Show test results in alert dialogs
|
|
23
|
-
|
|
24
|
-
### Integration Points
|
|
25
|
-
|
|
26
|
-
- **useInitializeCredits**: For credit initialization testing
|
|
27
|
-
- **Credits Repository**: `src/domains/wallet/infrastructure/repositories/CreditsRepository.ts`
|
|
28
|
-
- **Development Tools**: For testing and debugging
|
|
29
|
-
- **Alert API**: For displaying test results
|
|
30
|
-
|
|
31
|
-
## Restrictions
|
|
32
|
-
|
|
33
|
-
### REQUIRED
|
|
34
|
-
|
|
35
|
-
- **Development Only**: MUST only use in `__DEV__` mode
|
|
36
|
-
- **Guard Checks**: MUST check if hook returns undefined
|
|
37
|
-
- **Visual Distinction**: SHOULD make dev tools visually distinct
|
|
38
|
-
- **Documentation**: MUST document behavior for other developers
|
|
39
|
-
|
|
40
|
-
### PROHIBITED
|
|
41
|
-
|
|
42
|
-
- **NEVER** use in production code paths
|
|
43
|
-
- **NEVER** ship dev UI to production
|
|
44
|
-
- **DO NOT** rely on dev tools for production features
|
|
45
|
-
- **DO NOT** expose dev functionality to end users
|
|
46
|
-
|
|
47
|
-
### CRITICAL SAFETY
|
|
48
|
-
|
|
49
|
-
- **ALWAYS** guard with `__DEV__` checks
|
|
50
|
-
- **NEVER** call hook functions in production
|
|
51
|
-
- **MUST** remove or disable before release
|
|
52
|
-
- **ALWAYS** test that dev tools don't affect production
|
|
53
|
-
|
|
54
|
-
## AI Agent Guidelines
|
|
55
|
-
|
|
56
|
-
### When Implementing Development Testing
|
|
57
|
-
|
|
58
|
-
1. **Always** guard with `__DEV__` checks
|
|
59
|
-
2. **Always** check if hook returns undefined
|
|
60
|
-
3. **Always** make dev tools visually distinct
|
|
61
|
-
4. **Never** expose dev tools to production users
|
|
62
|
-
5. **Always** document development-only behavior
|
|
63
|
-
|
|
64
|
-
### Integration Checklist
|
|
65
|
-
|
|
66
|
-
- [ ] Import from correct path: `@umituz/react-native-subscription`
|
|
67
|
-
- [ ] Guard with `__DEV__` check
|
|
68
|
-
- [ ] Check if hook returns undefined
|
|
69
|
-
- [ ] Make dev UI visually distinct
|
|
70
|
-
- [ ] Test renewal simulation
|
|
71
|
-
- [ ] Test credits inspection
|
|
72
|
-
- [ ] Test duplicate protection
|
|
73
|
-
- [ ] Verify undefined returned in production
|
|
74
|
-
- [ ] Remove or disable before release
|
|
75
|
-
|
|
76
|
-
### Common Patterns
|
|
77
|
-
|
|
78
|
-
1. **Dev Test Panel**: Dedicated screen for testing
|
|
79
|
-
2. **Settings Integration**: Add dev tools to settings screen
|
|
80
|
-
3. **Debug Menu**: Hidden menu for testing
|
|
81
|
-
4. **Flow Testing**: Test complete renewal flows
|
|
82
|
-
5. **Edge Case Testing**: Test duplicate handling and errors
|
|
83
|
-
|
|
84
|
-
## Related Documentation
|
|
85
|
-
|
|
86
|
-
- **useCredits**: For accessing credits balance
|
|
87
|
-
- **useInitializeCredits**: For credit initialization
|
|
88
|
-
- **usePremiumWithCredits**: For premium + credits integration
|
|
89
|
-
- **Credits README**: `src/domains/wallet/README.md`
|
|
90
|
-
- **Renewal Testing Guide**: `src/docs/RENEWAL_TESTING.md`
|
|
91
|
-
- **Development Tools**: `src/docs/DEV_TOOLS.md`
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dev Test Callbacks Hook
|
|
3
|
-
* Provides test functions for subscription renewal testing
|
|
4
|
-
* Only used in __DEV__ mode
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { useCallback } from "react";
|
|
8
|
-
import { Alert } from "react-native";
|
|
9
|
-
import { useAuth } from "@umituz/react-native-auth";
|
|
10
|
-
import { getCreditsRepository } from "../../infrastructure/repositories/CreditsRepositoryProvider";
|
|
11
|
-
import { useCredits } from "./useCredits";
|
|
12
|
-
import type { DevTestActions } from "../screens/components/DevTestSection";
|
|
13
|
-
|
|
14
|
-
export const useDevTestCallbacks = (): DevTestActions | undefined => {
|
|
15
|
-
const { user } = useAuth();
|
|
16
|
-
const { credits, refetch } = useCredits({ userId: user?.uid });
|
|
17
|
-
|
|
18
|
-
const onTestRenewal = useCallback(async () => {
|
|
19
|
-
if (!user?.uid) {
|
|
20
|
-
Alert.alert("Error", "No user logged in");
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
const repository = getCreditsRepository();
|
|
26
|
-
const renewalId = `dev_renewal_${Date.now()}`;
|
|
27
|
-
const productId = "test_yearly_subscription";
|
|
28
|
-
|
|
29
|
-
if (__DEV__) {
|
|
30
|
-
console.log("๐งช [Dev Test] Simulating auto-renewal...", {
|
|
31
|
-
userId: user.uid,
|
|
32
|
-
renewalId,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const result = await repository.initializeCredits(
|
|
37
|
-
user.uid,
|
|
38
|
-
renewalId,
|
|
39
|
-
productId,
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
if (__DEV__) {
|
|
43
|
-
console.log("โ
[Dev Test] Renewal completed:", {
|
|
44
|
-
success: result.success,
|
|
45
|
-
credits: result.data?.credits,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
await refetch();
|
|
50
|
-
|
|
51
|
-
Alert.alert(
|
|
52
|
-
"โ
Test Renewal Success",
|
|
53
|
-
`Credits Updated!\n\nNew Balance: ${result.data?.credits || 0}\n\n(ACCUMULATE mode - credits added to existing)`,
|
|
54
|
-
[{ text: "OK" }],
|
|
55
|
-
);
|
|
56
|
-
} catch (error) {
|
|
57
|
-
if (__DEV__) {
|
|
58
|
-
console.error("โ [Dev Test] Renewal failed:", error);
|
|
59
|
-
}
|
|
60
|
-
Alert.alert(
|
|
61
|
-
"Test Failed",
|
|
62
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
}, [user?.uid, refetch]);
|
|
66
|
-
|
|
67
|
-
const onCheckCredits = useCallback(() => {
|
|
68
|
-
if (!credits) {
|
|
69
|
-
Alert.alert("Credits", "No credits data available");
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
Alert.alert(
|
|
74
|
-
"๐ Current Credits",
|
|
75
|
-
`Credits: ${credits.credits}\n\nPurchased: ${credits.purchasedAt?.toLocaleDateString() || "N/A"}`,
|
|
76
|
-
[{ text: "OK" }],
|
|
77
|
-
);
|
|
78
|
-
}, [credits]);
|
|
79
|
-
|
|
80
|
-
const onTestDuplicate = useCallback(async () => {
|
|
81
|
-
if (!user?.uid) {
|
|
82
|
-
Alert.alert("Error", "No user logged in");
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
const repository = getCreditsRepository();
|
|
88
|
-
const sameRenewalId = "dev_duplicate_test_12345";
|
|
89
|
-
|
|
90
|
-
if (__DEV__) {
|
|
91
|
-
console.log("๐งช [Dev Test] Testing duplicate protection...");
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const result1 = await repository.initializeCredits(
|
|
95
|
-
user.uid,
|
|
96
|
-
sameRenewalId,
|
|
97
|
-
"test_product",
|
|
98
|
-
);
|
|
99
|
-
if (__DEV__) {
|
|
100
|
-
console.log("First call:", result1.data);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const result2 = await repository.initializeCredits(
|
|
104
|
-
user.uid,
|
|
105
|
-
sameRenewalId,
|
|
106
|
-
"test_product",
|
|
107
|
-
);
|
|
108
|
-
if (__DEV__) {
|
|
109
|
-
console.log("Second call:", result2.data);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
await refetch();
|
|
113
|
-
|
|
114
|
-
const duplicateProtectionWorks =
|
|
115
|
-
result2.data?.credits === result1.data?.credits;
|
|
116
|
-
|
|
117
|
-
Alert.alert(
|
|
118
|
-
"Duplicate Test",
|
|
119
|
-
`First call: ${result1.success ? "โ
Added credits" : "โ Failed"}\n\nSecond call: ${duplicateProtectionWorks ? "โ
Skipped (protection works!)" : "โ Added again (protection failed!)"}`,
|
|
120
|
-
[{ text: "OK" }],
|
|
121
|
-
);
|
|
122
|
-
} catch (error) {
|
|
123
|
-
if (__DEV__) {
|
|
124
|
-
console.error("โ [Dev Test] Duplicate test failed:", error);
|
|
125
|
-
}
|
|
126
|
-
Alert.alert(
|
|
127
|
-
"Test Failed",
|
|
128
|
-
error instanceof Error ? error.message : "Unknown error",
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
}, [user?.uid, refetch]);
|
|
132
|
-
|
|
133
|
-
if (!__DEV__) {
|
|
134
|
-
return undefined;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
onTestRenewal,
|
|
139
|
-
onCheckCredits,
|
|
140
|
-
onTestDuplicate,
|
|
141
|
-
};
|
|
142
|
-
};
|