@umituz/react-native-subscription 2.26.13 → 2.26.15
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 -15
- package/src/presentation/hooks/useFeatureGate.ts +41 -116
- 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/useAuthAwarePurchase.ts +0 -138
- 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 -81
- 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/useSubscriptionStatus.ts +0 -64
- 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,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
|
-
};
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# useInitializeCredits Hook
|
|
2
|
-
|
|
3
|
-
TanStack Query mutation hook for initializing credits after purchase.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
**Import Path**: `@umituz/react-native-subscription`
|
|
8
|
-
|
|
9
|
-
**File**: `src/presentation/hooks/useInitializeCredits.ts`
|
|
10
|
-
|
|
11
|
-
**Type**: Hook
|
|
12
|
-
|
|
13
|
-
## Strategy
|
|
14
|
-
|
|
15
|
-
### Credit Initialization Flow
|
|
16
|
-
|
|
17
|
-
1. **User Validation**: Verify user is authenticated before initialization
|
|
18
|
-
2. **Repository Call**: Call credits repository to initialize credits
|
|
19
|
-
3. **Duplicate Protection**: Repository prevents duplicate initialization with same purchase ID
|
|
20
|
-
4. **Loading State**: Track initialization progress with isInitializing flag
|
|
21
|
-
5. **Error Handling**: Handle and report initialization failures
|
|
22
|
-
6. **Success Tracking**: Return success boolean for caller to handle
|
|
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 mutation and optimistic updates
|
|
29
|
-
- **Purchase Flow**: Called after successful subscription purchase
|
|
30
|
-
|
|
31
|
-
## Restrictions
|
|
32
|
-
|
|
33
|
-
### REQUIRED
|
|
34
|
-
|
|
35
|
-
- **User ID**: MUST provide valid userId parameter
|
|
36
|
-
- **Authentication**: User MUST be authenticated
|
|
37
|
-
- **Error Handling**: MUST handle initialization failures
|
|
38
|
-
- **Loading State**: MUST show loading indicator during initialization
|
|
39
|
-
|
|
40
|
-
### PROHIBITED
|
|
41
|
-
|
|
42
|
-
- **NEVER** initialize credits without valid userId
|
|
43
|
-
- **NEVER** call for unauthenticated users
|
|
44
|
-
- **DO NOT** assume successful initialization (check return value)
|
|
45
|
-
- **DO NOT** call excessively (repository handles duplicates)
|
|
46
|
-
|
|
47
|
-
### CRITICAL SAFETY
|
|
48
|
-
|
|
49
|
-
- **ALWAYS** validate userId before initialization
|
|
50
|
-
- **MUST** handle errors gracefully
|
|
51
|
-
- **ALWAYS** check return value
|
|
52
|
-
- **NEVER** rely on side effects without checking success
|
|
53
|
-
|
|
54
|
-
## AI Agent Guidelines
|
|
55
|
-
|
|
56
|
-
### When Implementing Credit Initialization
|
|
57
|
-
|
|
58
|
-
1. **Always** validate userId before calling initializeCredits
|
|
59
|
-
2. **Always** handle loading state
|
|
60
|
-
3. **Always** check return value
|
|
61
|
-
4. **Always** provide purchaseId and productId when available
|
|
62
|
-
5. **Never** initialize credits for unauthenticated users
|
|
63
|
-
|
|
64
|
-
### Integration Checklist
|
|
65
|
-
|
|
66
|
-
- [ ] Import from correct path: `@umituz/react-native-subscription`
|
|
67
|
-
- [ ] Validate userId is not undefined
|
|
68
|
-
- [ ] Handle isInitializing state
|
|
69
|
-
- [ ] Check return value from initializeCredits
|
|
70
|
-
- [ ] Provide purchaseId when available
|
|
71
|
-
- [ ] Provide productId when available
|
|
72
|
-
- [ ] Test with premium user (no existing credits)
|
|
73
|
-
- [ ] Test with premium user (existing credits)
|
|
74
|
-
- [ ] Test duplicate protection
|
|
75
|
-
- [ ] Test error scenarios
|
|
76
|
-
|
|
77
|
-
### Common Patterns
|
|
78
|
-
|
|
79
|
-
1. **Post-Purchase Init**: Initialize after successful purchase
|
|
80
|
-
2. **Auto-Init for Premium**: Automatically initialize for premium users without credits
|
|
81
|
-
3. **Product-Specific Allocation**: Different products provide different credit amounts
|
|
82
|
-
4. **Retry Logic**: Implement retry mechanism on failure
|
|
83
|
-
5. **Admin Init**: Manual initialization for admin users
|
|
84
|
-
|
|
85
|
-
## Related Documentation
|
|
86
|
-
|
|
87
|
-
- **useCredits**: For accessing credits balance
|
|
88
|
-
- **useDeductCredit**: For deducting credits
|
|
89
|
-
- **usePremiumWithCredits**: For premium + credits integration
|
|
90
|
-
- **useDevTestCallbacks**: For testing credit initialization
|
|
91
|
-
- **Credits Repository**: `src/domains/wallet/infrastructure/repositories/README.md`
|
|
92
|
-
- **Wallet Domain**: `src/domains/wallet/README.md`
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useInitializeCredits Hook
|
|
3
|
-
* TanStack Query mutation hook for initializing credits after purchase.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { useCallback } from "react";
|
|
7
|
-
import { useMutation, useQueryClient } from "@umituz/react-native-design-system";
|
|
8
|
-
import { getCreditsRepository } from "../../infrastructure/repositories/CreditsRepositoryProvider";
|
|
9
|
-
import { creditsQueryKeys } from "./useCredits";
|
|
10
|
-
|
|
11
|
-
declare const __DEV__: boolean;
|
|
12
|
-
|
|
13
|
-
export interface UseInitializeCreditsParams {
|
|
14
|
-
userId: string | undefined;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface InitializeCreditsOptions {
|
|
18
|
-
purchaseId?: string;
|
|
19
|
-
productId?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface UseInitializeCreditsResult {
|
|
23
|
-
initializeCredits: (options?: InitializeCreditsOptions) => Promise<boolean>;
|
|
24
|
-
isInitializing: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const useInitializeCredits = ({
|
|
28
|
-
userId,
|
|
29
|
-
}: UseInitializeCreditsParams): UseInitializeCreditsResult => {
|
|
30
|
-
const repository = getCreditsRepository();
|
|
31
|
-
const queryClient = useQueryClient();
|
|
32
|
-
|
|
33
|
-
const mutation = useMutation({
|
|
34
|
-
mutationFn: async (options?: InitializeCreditsOptions) => {
|
|
35
|
-
if (!userId) throw new Error("User not authenticated");
|
|
36
|
-
if (__DEV__) console.log("[useInitializeCredits] Initializing:", { userId, ...options });
|
|
37
|
-
return repository.initializeCredits(userId, options?.purchaseId, options?.productId);
|
|
38
|
-
},
|
|
39
|
-
onSuccess: (result) => {
|
|
40
|
-
if (userId && result.success && result.data) {
|
|
41
|
-
if (__DEV__) console.log("[useInitializeCredits] Success:", result.data);
|
|
42
|
-
queryClient.setQueryData(creditsQueryKeys.user(userId), result.data);
|
|
43
|
-
queryClient.invalidateQueries({ queryKey: creditsQueryKeys.user(userId) });
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
onError: (error) => { if (__DEV__) console.error("[useInitializeCredits] Error:", error); },
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const initializeCredits = useCallback(async (opts?: InitializeCreditsOptions): Promise<boolean> => {
|
|
50
|
-
try {
|
|
51
|
-
const res = await mutation.mutateAsync(opts);
|
|
52
|
-
return res.success;
|
|
53
|
-
} catch { return false; }
|
|
54
|
-
}, [mutation]);
|
|
55
|
-
|
|
56
|
-
return { initializeCredits, isInitializing: mutation.isPending };
|
|
57
|
-
};
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# usePremiumGate Hook
|
|
2
|
-
|
|
3
|
-
Feature gating hook for premium-only features with optional authentication.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
**Import Path**: `@umituz/react-native-subscription`
|
|
8
|
-
|
|
9
|
-
**File**: `src/presentation/hooks/usePremiumGate.ts`
|
|
10
|
-
|
|
11
|
-
**Type**: Hook
|
|
12
|
-
|
|
13
|
-
## Strategy
|
|
14
|
-
|
|
15
|
-
### Premium Gating Flow
|
|
16
|
-
|
|
17
|
-
1. **Premium Check**: Verify if user has premium access
|
|
18
|
-
2. **Auth Check**: Optionally verify authentication status
|
|
19
|
-
3. **Gate Functions**: Provide requirePremium, requireAuth, requirePremiumWithAuth
|
|
20
|
-
4. **Access Control**: Simple booleans for conditional rendering (canAccess, canAccessWithAuth)
|
|
21
|
-
5. **Callback Triggers**: Execute appropriate callback when requirements not met
|
|
22
|
-
|
|
23
|
-
### Integration Points
|
|
24
|
-
|
|
25
|
-
- **usePremium**: For premium status check
|
|
26
|
-
- **useAuth**: For authentication status
|
|
27
|
-
- **Paywall Domain**: For premium upgrade flow
|
|
28
|
-
- **Auth UI**: For authentication flow
|
|
29
|
-
|
|
30
|
-
## Restrictions
|
|
31
|
-
|
|
32
|
-
### REQUIRED
|
|
33
|
-
|
|
34
|
-
- **Premium Status**: MUST provide isPremium parameter
|
|
35
|
-
- **Callback**: MUST implement onPremiumRequired callback
|
|
36
|
-
- **Access Check**: MUST verify canAccess before showing premium content
|
|
37
|
-
|
|
38
|
-
### PROHIBITED
|
|
39
|
-
|
|
40
|
-
- **NEVER** show premium content without checking isPremium
|
|
41
|
-
- **NEVER** use for security decisions without server validation
|
|
42
|
-
- **DO NOT** assume premium status (always verify)
|
|
43
|
-
|
|
44
|
-
### CRITICAL SAFETY
|
|
45
|
-
|
|
46
|
-
- **ALWAYS** verify canAccess before showing premium features
|
|
47
|
-
- **NEVER** trust client-side state for security
|
|
48
|
-
- **MUST** implement proper upgrade flow
|
|
49
|
-
- **ALWAYS** handle authentication when required
|
|
50
|
-
|
|
51
|
-
## AI Agent Guidelines
|
|
52
|
-
|
|
53
|
-
### When Implementing Premium Gates
|
|
54
|
-
|
|
55
|
-
1. **Always** check canAccess before showing premium content
|
|
56
|
-
2. **Always** provide clear upgrade path in callback
|
|
57
|
-
3. **Always** use requirePremium for action gating
|
|
58
|
-
4. **Always** handle authentication when using requirePremiumWithAuth
|
|
59
|
-
5. **Never** bypass premium checks
|
|
60
|
-
|
|
61
|
-
### Integration Checklist
|
|
62
|
-
|
|
63
|
-
- [ ] Import from correct path: `@umituz/react-native-subscription`
|
|
64
|
-
- [ ] Provide isPremium from usePremium
|
|
65
|
-
- [ ] Implement onPremiumRequired callback
|
|
66
|
-
- [ ] Optionally provide auth status and callback
|
|
67
|
-
- [ ] Use requirePremium for action gating
|
|
68
|
-
- [ ] Check canAccess for conditional rendering
|
|
69
|
-
- [ ] Test with premium user
|
|
70
|
-
- [ ] Test with non-premium user
|
|
71
|
-
- [ ] Test with authenticated user
|
|
72
|
-
- [ ] Test with unauthenticated user
|
|
73
|
-
|
|
74
|
-
### Common Patterns
|
|
75
|
-
|
|
76
|
-
1. **Premium Only**: Gate features behind premium only
|
|
77
|
-
2. **Auth + Premium**: Require both authentication and premium
|
|
78
|
-
3. **Conditional Rendering**: Check canAccess for UI
|
|
79
|
-
4. **Button States**: Disable buttons when not premium
|
|
80
|
-
5. **Upgrade Prompts**: Show in callback when not premium
|
|
81
|
-
|
|
82
|
-
## Related Documentation
|
|
83
|
-
|
|
84
|
-
- **usePremium**: Premium status check
|
|
85
|
-
- **useAuthGate**: Auth + subscription gating
|
|
86
|
-
- **useSubscriptionGate**: Subscription-only gating
|
|
87
|
-
- **useFeatureGate**: Unified feature gating
|
|
88
|
-
- **Paywall Domain**: `src/domains/paywall/README.md`
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* usePremiumGate Hook
|
|
3
|
-
*
|
|
4
|
-
* Feature gating hook for premium-only features
|
|
5
|
-
* Provides a simple way to gate features behind premium subscription
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* const { requirePremium, isPremium } = usePremiumGate({
|
|
10
|
-
* isPremium: subscriptionStore.isPremium,
|
|
11
|
-
* onPremiumRequired: () => navigation.navigate('Paywall'),
|
|
12
|
-
* });
|
|
13
|
-
*
|
|
14
|
-
* const handleGenerate = () => {
|
|
15
|
-
* requirePremium(() => {
|
|
16
|
-
* // This only runs if user is premium
|
|
17
|
-
* generateContent();
|
|
18
|
-
* });
|
|
19
|
-
* };
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import { useCallback, useMemo } from "react";
|
|
24
|
-
|
|
25
|
-
export interface UsePremiumGateParams {
|
|
26
|
-
/** Whether user has premium access */
|
|
27
|
-
isPremium: boolean;
|
|
28
|
-
/** Callback when premium is required but user is not premium */
|
|
29
|
-
onPremiumRequired: () => void;
|
|
30
|
-
/** Optional: Whether user is authenticated */
|
|
31
|
-
isAuthenticated?: boolean;
|
|
32
|
-
/** Optional: Callback when auth is required but user is not authenticated */
|
|
33
|
-
onAuthRequired?: () => void;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface UsePremiumGateResult {
|
|
37
|
-
/** Whether user has premium access */
|
|
38
|
-
isPremium: boolean;
|
|
39
|
-
/** Whether user is authenticated */
|
|
40
|
-
isAuthenticated: boolean;
|
|
41
|
-
/** Gate a feature behind premium - executes action if premium, else calls onPremiumRequired */
|
|
42
|
-
requirePremium: (action: () => void) => void;
|
|
43
|
-
/** Gate a feature behind auth - executes action if authenticated, else calls onAuthRequired */
|
|
44
|
-
requireAuth: (action: () => void) => void;
|
|
45
|
-
/** Gate a feature behind both auth and premium */
|
|
46
|
-
requirePremiumWithAuth: (action: () => void) => void;
|
|
47
|
-
/** Check if feature is accessible (premium check only) */
|
|
48
|
-
canAccess: boolean;
|
|
49
|
-
/** Check if feature is accessible (auth + premium) */
|
|
50
|
-
canAccessWithAuth: boolean;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function usePremiumGate(
|
|
54
|
-
params: UsePremiumGateParams
|
|
55
|
-
): UsePremiumGateResult {
|
|
56
|
-
const {
|
|
57
|
-
isPremium,
|
|
58
|
-
onPremiumRequired,
|
|
59
|
-
isAuthenticated = true,
|
|
60
|
-
onAuthRequired,
|
|
61
|
-
} = params;
|
|
62
|
-
|
|
63
|
-
const requirePremium = useCallback(
|
|
64
|
-
(action: () => void) => {
|
|
65
|
-
if (isPremium) {
|
|
66
|
-
action();
|
|
67
|
-
} else {
|
|
68
|
-
onPremiumRequired();
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
[isPremium, onPremiumRequired]
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
const requireAuth = useCallback(
|
|
75
|
-
(action: () => void) => {
|
|
76
|
-
if (isAuthenticated) {
|
|
77
|
-
action();
|
|
78
|
-
} else {
|
|
79
|
-
onAuthRequired?.();
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
[isAuthenticated, onAuthRequired]
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
const requirePremiumWithAuth = useCallback(
|
|
86
|
-
(action: () => void) => {
|
|
87
|
-
if (!isAuthenticated) {
|
|
88
|
-
onAuthRequired?.();
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (!isPremium) {
|
|
92
|
-
onPremiumRequired();
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
action();
|
|
96
|
-
},
|
|
97
|
-
[isAuthenticated, isPremium, onAuthRequired, onPremiumRequired]
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
const canAccess = useMemo(() => isPremium, [isPremium]);
|
|
101
|
-
|
|
102
|
-
const canAccessWithAuth = useMemo(
|
|
103
|
-
() => isAuthenticated && isPremium,
|
|
104
|
-
[isAuthenticated, isPremium]
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
isPremium,
|
|
109
|
-
isAuthenticated,
|
|
110
|
-
requirePremium,
|
|
111
|
-
requireAuth,
|
|
112
|
-
requirePremiumWithAuth,
|
|
113
|
-
canAccess,
|
|
114
|
-
canAccessWithAuth,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# usePremiumWithCredits Hook
|
|
2
|
-
|
|
3
|
-
Combined hook for premium subscription with credits system integration.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
**Import Path**: `@umituz/react-native-subscription`
|
|
8
|
-
|
|
9
|
-
**File**: `src/presentation/hooks/usePremiumWithCredits.ts`
|
|
10
|
-
|
|
11
|
-
**Type**: Hook
|
|
12
|
-
|
|
13
|
-
## Strategy
|
|
14
|
-
|
|
15
|
-
### Premium + Credits Integration
|
|
16
|
-
|
|
17
|
-
1. **Credits Access**: Provide all credits data from useCredits hook
|
|
18
|
-
2. **Auto-Initialization**: Automatically initialize credits when user becomes premium
|
|
19
|
-
3. **Premium Check**: Monitor isPremium status to trigger initialization
|
|
20
|
-
4. **Duplicate Prevention**: Skip initialization if credits already exist
|
|
21
|
-
5. **Loading Management**: Handle loading state during initialization
|
|
22
|
-
6. **Error Handling**: Handle initialization failures gracefully
|
|
23
|
-
|
|
24
|
-
### Integration Points
|
|
25
|
-
|
|
26
|
-
- **useCredits**: For credits balance and transactions
|
|
27
|
-
- **usePremium**: For premium status check
|
|
28
|
-
- **useInitializeCredits**: For credit initialization
|
|
29
|
-
- **Credits Repository**: `src/domains/wallet/infrastructure/repositories/CreditsRepository.ts`
|
|
30
|
-
|
|
31
|
-
## Restrictions
|
|
32
|
-
|
|
33
|
-
### REQUIRED
|
|
34
|
-
|
|
35
|
-
- **User ID**: MUST provide valid userId parameter
|
|
36
|
-
- **Premium Status**: MUST provide isPremium parameter
|
|
37
|
-
- **Loading State**: MUST handle loading state
|
|
38
|
-
- **Error Handling**: MUST handle initialization errors
|
|
39
|
-
|
|
40
|
-
### PROHIBITED
|
|
41
|
-
|
|
42
|
-
- **NEVER** call without valid userId
|
|
43
|
-
- **NEVER** call without isPremium parameter
|
|
44
|
-
- **DO NOT** manually manage credits state (use hook values)
|
|
45
|
-
- **DO NOT** call ensureCreditsInitialized excessively
|
|
46
|
-
|
|
47
|
-
### CRITICAL SAFETY
|
|
48
|
-
|
|
49
|
-
- **ALWAYS** validate userId before use
|
|
50
|
-
- **MUST** handle loading state during initialization
|
|
51
|
-
- **ALWAYS** check isPremium before showing premium features
|
|
52
|
-
- **NEVER** trust client-side state for security
|
|
53
|
-
|
|
54
|
-
## AI Agent Guidelines
|
|
55
|
-
|
|
56
|
-
### When Implementing Premium + Credits
|
|
57
|
-
|
|
58
|
-
1. **Always** provide valid userId
|
|
59
|
-
2. **Always** provide isPremium status
|
|
60
|
-
3. **Always** handle loading state
|
|
61
|
-
4. **Always** call ensureCreditsInitialized for premium users
|
|
62
|
-
5. **Never** manually initialize credits without checking isPremium
|
|
63
|
-
|
|
64
|
-
### Integration Checklist
|
|
65
|
-
|
|
66
|
-
- [ ] Import from correct path: `@umituz/react-native-subscription`
|
|
67
|
-
- [ ] Provide valid userId
|
|
68
|
-
- [ ] Provide isPremium from usePremium
|
|
69
|
-
- [ ] Handle loading state
|
|
70
|
-
- [ ] Call ensureCreditsInitialized when isPremium is true
|
|
71
|
-
- [ ] Test with premium user (no credits)
|
|
72
|
-
- [ ] Test with premium user (has credits)
|
|
73
|
-
- [ ] Test with free user
|
|
74
|
-
- [ ] Test subscription upgrade flow
|
|
75
|
-
- [ ] Test error scenarios
|
|
76
|
-
|
|
77
|
-
### Common Patterns
|
|
78
|
-
|
|
79
|
-
1. **Auto-Initialization**: Automatically initialize credits for premium users
|
|
80
|
-
2. **Subscription Change Detection**: Detect when user subscribes
|
|
81
|
-
3. **Premium Benefits Display**: Show credits along with premium status
|
|
82
|
-
4. **Subscription Monitor**: Refresh status periodically
|
|
83
|
-
5. **Manual Init**: Provide button for manual initialization
|
|
84
|
-
|
|
85
|
-
## Related Documentation
|
|
86
|
-
|
|
87
|
-
- **useCredits**: Credits management
|
|
88
|
-
- **useInitializeCredits**: Manual credit initialization
|
|
89
|
-
- **usePremium**: Premium status
|
|
90
|
-
- **useDeductCredit**: Credit deduction
|
|
91
|
-
- **Credits System**: `src/domains/wallet/README.md`
|
|
92
|
-
- **Premium Integration**: `src/docs/PREMIUM_INTEGRATION.md`
|