@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.
Files changed (37) hide show
  1. package/package.json +1 -1
  2. package/src/domains/paywall/components/PaywallModal.tsx +36 -13
  3. package/src/domains/paywall/components/PlanCard.tsx +16 -3
  4. package/src/domains/paywall/entities/types.ts +4 -0
  5. package/src/domains/paywall/hooks/usePaywallTranslations.ts +8 -0
  6. package/src/presentation/hooks/index.ts +0 -13
  7. package/src/presentation/hooks/useFeatureGate.ts +12 -33
  8. package/src/revenuecat/domain/types/RevenueCatTypes.ts +32 -0
  9. package/src/revenuecat/index.ts +1 -0
  10. package/src/revenuecat/presentation/hooks/useRevenueCatTrialEligibility.ts +179 -0
  11. package/src/presentation/hooks/useAuthAwarePurchase.md +0 -92
  12. package/src/presentation/hooks/useAuthGate.md +0 -89
  13. package/src/presentation/hooks/useAuthGate.ts +0 -65
  14. package/src/presentation/hooks/useCreditChecker.md +0 -102
  15. package/src/presentation/hooks/useCreditChecker.ts +0 -41
  16. package/src/presentation/hooks/useCreditsGate.md +0 -94
  17. package/src/presentation/hooks/useCreditsGate.ts +0 -67
  18. package/src/presentation/hooks/useDevTestCallbacks.md +0 -91
  19. package/src/presentation/hooks/useDevTestCallbacks.ts +0 -142
  20. package/src/presentation/hooks/useInitializeCredits.md +0 -92
  21. package/src/presentation/hooks/useInitializeCredits.ts +0 -57
  22. package/src/presentation/hooks/usePremiumGate.md +0 -88
  23. package/src/presentation/hooks/usePremiumGate.ts +0 -116
  24. package/src/presentation/hooks/usePremiumWithCredits.md +0 -92
  25. package/src/presentation/hooks/usePremiumWithCredits.ts +0 -48
  26. package/src/presentation/hooks/useSubscription.md +0 -94
  27. package/src/presentation/hooks/useSubscription.ts +0 -119
  28. package/src/presentation/hooks/useSubscriptionDetails.md +0 -93
  29. package/src/presentation/hooks/useSubscriptionDetails.ts +0 -85
  30. package/src/presentation/hooks/useSubscriptionGate.md +0 -84
  31. package/src/presentation/hooks/useSubscriptionGate.ts +0 -67
  32. package/src/presentation/hooks/useSubscriptionStatus.md +0 -94
  33. package/src/presentation/hooks/useTrialEligibility.ts +0 -66
  34. package/src/presentation/hooks/useUserTier.md +0 -91
  35. package/src/presentation/hooks/useUserTier.ts +0 -78
  36. package/src/presentation/hooks/useUserTierWithRepository.md +0 -92
  37. 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
- };