@umituz/react-native-subscription 2.14.97 → 2.14.99
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/LICENSE +21 -0
- package/README.md +461 -0
- package/package.json +1 -3
- package/src/application/README.md +229 -0
- package/src/application/ports/README.md +103 -0
- package/src/domain/README.md +402 -0
- package/src/domain/constants/README.md +80 -0
- package/src/domain/entities/README.md +176 -0
- package/src/domain/errors/README.md +307 -0
- package/src/domain/value-objects/README.md +186 -0
- package/src/domains/README.md +240 -0
- package/src/domains/config/README.md +390 -0
- package/src/domains/config/domain/README.md +390 -0
- package/src/domains/config/domain/entities/README.md +350 -0
- package/src/domains/paywall/README.md +371 -0
- package/src/domains/paywall/components/PaywallHeader.tsx +8 -11
- package/src/domains/paywall/components/README.md +185 -0
- package/src/domains/paywall/entities/README.md +199 -0
- package/src/domains/paywall/hooks/README.md +129 -0
- package/src/domains/wallet/README.md +292 -0
- package/src/domains/wallet/domain/README.md +108 -0
- package/src/domains/wallet/domain/entities/README.md +122 -0
- package/src/domains/wallet/domain/errors/README.md +157 -0
- package/src/domains/wallet/infrastructure/README.md +96 -0
- package/src/domains/wallet/presentation/components/BalanceCard.tsx +6 -12
- package/src/domains/wallet/presentation/components/README.md +231 -0
- package/src/domains/wallet/presentation/hooks/README.md +255 -0
- package/src/infrastructure/README.md +514 -0
- package/src/infrastructure/mappers/README.md +34 -0
- package/src/infrastructure/models/README.md +26 -0
- package/src/infrastructure/repositories/README.md +385 -0
- package/src/infrastructure/services/README.md +374 -0
- package/src/presentation/README.md +410 -0
- package/src/presentation/components/README.md +183 -0
- package/src/presentation/components/details/CreditRow.md +337 -0
- package/src/presentation/components/details/DetailRow.md +283 -0
- package/src/presentation/components/details/PremiumDetailsCard.md +266 -0
- package/src/presentation/components/details/PremiumStatusBadge.md +266 -0
- package/src/presentation/components/details/README.md +449 -0
- package/src/presentation/components/feedback/PaywallFeedbackModal.md +314 -0
- package/src/presentation/components/feedback/README.md +447 -0
- package/src/presentation/components/paywall/PaywallModal.md +444 -0
- package/src/presentation/components/paywall/README.md +190 -0
- package/src/presentation/components/sections/README.md +468 -0
- package/src/presentation/components/sections/SubscriptionSection.md +246 -0
- package/src/presentation/hooks/README.md +743 -0
- package/src/presentation/hooks/useAuthAwarePurchase.md +359 -0
- package/src/presentation/hooks/useAuthGate.md +403 -0
- package/src/presentation/hooks/useAuthSubscriptionSync.md +398 -0
- package/src/presentation/hooks/useCreditChecker.md +407 -0
- package/src/presentation/hooks/useCredits.md +342 -0
- package/src/presentation/hooks/useCreditsGate.md +346 -0
- package/src/presentation/hooks/useDeductCredit.md +176 -0
- package/src/presentation/hooks/useDevTestCallbacks.md +422 -0
- package/src/presentation/hooks/useFeatureGate.md +157 -0
- package/src/presentation/hooks/useInitializeCredits.md +458 -0
- package/src/presentation/hooks/usePaywall.md +334 -0
- package/src/presentation/hooks/usePaywallOperations.md +486 -0
- package/src/presentation/hooks/usePaywallVisibility.md +344 -0
- package/src/presentation/hooks/usePremium.md +230 -0
- package/src/presentation/hooks/usePremiumGate.md +423 -0
- package/src/presentation/hooks/usePremiumWithCredits.md +429 -0
- package/src/presentation/hooks/useSubscription.md +450 -0
- package/src/presentation/hooks/useSubscriptionDetails.md +438 -0
- package/src/presentation/hooks/useSubscriptionGate.md +168 -0
- package/src/presentation/hooks/useSubscriptionSettingsConfig.md +374 -0
- package/src/presentation/hooks/useSubscriptionStatus.md +424 -0
- package/src/presentation/hooks/useUserTier.md +356 -0
- package/src/presentation/hooks/useUserTierWithRepository.md +452 -0
- package/src/presentation/screens/README.md +194 -0
- package/src/presentation/types/README.md +38 -0
- package/src/presentation/utils/README.md +52 -0
- package/src/revenuecat/README.md +523 -0
- package/src/revenuecat/application/README.md +158 -0
- package/src/revenuecat/application/ports/README.md +169 -0
- package/src/revenuecat/domain/README.md +147 -0
- package/src/revenuecat/domain/constants/README.md +183 -0
- package/src/revenuecat/domain/entities/README.md +382 -0
- package/src/revenuecat/domain/errors/README.md +197 -0
- package/src/revenuecat/domain/types/README.md +373 -0
- package/src/revenuecat/domain/value-objects/README.md +441 -0
- package/src/revenuecat/infrastructure/README.md +50 -0
- package/src/revenuecat/infrastructure/config/README.md +40 -0
- package/src/revenuecat/infrastructure/handlers/README.md +218 -0
- package/src/revenuecat/infrastructure/managers/README.md +49 -0
- package/src/revenuecat/infrastructure/services/README.md +325 -0
- package/src/revenuecat/infrastructure/utils/README.md +382 -0
- package/src/revenuecat/presentation/README.md +184 -0
- package/src/revenuecat/presentation/hooks/README.md +56 -0
- package/src/utils/README.md +529 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Paywall Header
|
|
3
|
-
* Header with
|
|
3
|
+
* Header with background, close button, title and subtitle
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, StyleSheet, TouchableOpacity } from "react-native";
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
import {
|
|
10
10
|
AtomicText,
|
|
11
11
|
AtomicIcon,
|
|
@@ -25,16 +25,13 @@ export const PaywallHeader: React.FC<PaywallHeaderProps> = React.memo(
|
|
|
25
25
|
const { themeMode } = useDesignSystemTheme();
|
|
26
26
|
const isDark = themeMode === "dark";
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
?
|
|
30
|
-
:
|
|
28
|
+
const backgroundColor = isDark
|
|
29
|
+
? tokens.colors.surface
|
|
30
|
+
: tokens.colors.primary;
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
start={{ x: 0, y: 0 }}
|
|
36
|
-
end={{ x: 1, y: 1 }}
|
|
37
|
-
style={styles.container}
|
|
33
|
+
<View
|
|
34
|
+
style={[styles.container, { backgroundColor }]}
|
|
38
35
|
>
|
|
39
36
|
<TouchableOpacity
|
|
40
37
|
onPress={onClose}
|
|
@@ -66,7 +63,7 @@ export const PaywallHeader: React.FC<PaywallHeaderProps> = React.memo(
|
|
|
66
63
|
</View>
|
|
67
64
|
|
|
68
65
|
<View style={[styles.wave, { backgroundColor: tokens.colors.background }]} />
|
|
69
|
-
</
|
|
66
|
+
</View>
|
|
70
67
|
);
|
|
71
68
|
}
|
|
72
69
|
);
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Paywall Components
|
|
2
|
+
|
|
3
|
+
UI components for displaying paywalls and upgrade prompts.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This directory contains React Native components for rendering paywall screens and upgrade prompts.
|
|
8
|
+
|
|
9
|
+
## Components
|
|
10
|
+
|
|
11
|
+
### PaywallScreen
|
|
12
|
+
Main paywall screen with package selection.
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
function PaywallScreen() {
|
|
16
|
+
const { packages, isLoading } = useSubscriptionPackages();
|
|
17
|
+
const { handlePurchase, handleRestore } = usePaywallOperations({
|
|
18
|
+
userId: user?.uid,
|
|
19
|
+
isAnonymous: !user,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (isLoading) return <LoadingScreen />;
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<ScrollView>
|
|
26
|
+
<PaywallHeader />
|
|
27
|
+
|
|
28
|
+
{packages.map((pkg) => (
|
|
29
|
+
<PackageCard
|
|
30
|
+
key={pkg.identifier}
|
|
31
|
+
package={pkg}
|
|
32
|
+
onPress={() => handlePurchase(pkg)}
|
|
33
|
+
/>
|
|
34
|
+
))}
|
|
35
|
+
|
|
36
|
+
<RestoreButton onPress={handleRestore} />
|
|
37
|
+
</ScrollView>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### PackageCard
|
|
43
|
+
Individual subscription package display card.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
interface PackageCardProps {
|
|
47
|
+
package: PaywallPackage;
|
|
48
|
+
selected?: boolean;
|
|
49
|
+
onPress: () => void;
|
|
50
|
+
popular?: boolean;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Features:**
|
|
55
|
+
- Highlight popular packages
|
|
56
|
+
- Show price and period
|
|
57
|
+
- Display features list
|
|
58
|
+
- Show savings (for annual)
|
|
59
|
+
- Visual selection indicator
|
|
60
|
+
|
|
61
|
+
### PaywallModal
|
|
62
|
+
Modal-style paywall overlay.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
interface PaywallModalProps {
|
|
66
|
+
visible: boolean;
|
|
67
|
+
onClose: () => void;
|
|
68
|
+
onPurchase: (pkg: Package) => void;
|
|
69
|
+
configuration: PaywallConfig;
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Usage:**
|
|
74
|
+
```typescript
|
|
75
|
+
<PaywallModal
|
|
76
|
+
visible={showPaywall}
|
|
77
|
+
onClose={() => setShowPaywall(false)}
|
|
78
|
+
onPurchase={handlePurchase}
|
|
79
|
+
configuration={{
|
|
80
|
+
title: 'Upgrade to Premium',
|
|
81
|
+
features: ['Unlimited access', 'Ad-free'],
|
|
82
|
+
packages: packages,
|
|
83
|
+
}}
|
|
84
|
+
/>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### PremiumFeatureLock
|
|
88
|
+
Locked feature indicator that prompts upgrade.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
interface PremiumFeatureLockProps {
|
|
92
|
+
feature: string;
|
|
93
|
+
onPress: () => void;
|
|
94
|
+
icon?: string;
|
|
95
|
+
message?: string;
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Usage:**
|
|
100
|
+
```typescript
|
|
101
|
+
<PremiumFeatureLock
|
|
102
|
+
feature="AI Generation"
|
|
103
|
+
onPress={() => showPaywall({ type: 'premium_feature', feature: 'ai_generation' })}
|
|
104
|
+
message="Upgrade to generate unlimited content"
|
|
105
|
+
icon="lock"
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Usage Patterns
|
|
110
|
+
|
|
111
|
+
### With Navigation
|
|
112
|
+
```typescript
|
|
113
|
+
function navigateToPaywall(trigger: PaywallTrigger) {
|
|
114
|
+
navigation.navigate('Paywall', { trigger });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// In paywall screen
|
|
118
|
+
const { trigger } = route.params;
|
|
119
|
+
const config = getPaywallConfig(trigger.type);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### With Inline Paywall
|
|
123
|
+
```typescript
|
|
124
|
+
function InlinePaywall({ onUpgrade, onDismiss }) {
|
|
125
|
+
return (
|
|
126
|
+
<Card>
|
|
127
|
+
<Image source={premiumIllustration} />
|
|
128
|
+
<Title>Unlock Premium Features</Title>
|
|
129
|
+
<FeaturesList features={premiumFeatures} />
|
|
130
|
+
<Button onPress={onUpgrade}>Upgrade Now</Button>
|
|
131
|
+
<Link onPress={onDismiss}>Maybe Later</Link>
|
|
132
|
+
</Card>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### With Context
|
|
138
|
+
```typescript
|
|
139
|
+
function ContextualPaywall({ feature, context }) {
|
|
140
|
+
const { packages } = useSubscriptionPackages();
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<PaywallScreen
|
|
144
|
+
title={`Unlock ${feature}`}
|
|
145
|
+
subtitle={`You need Premium to use ${feature}`}
|
|
146
|
+
highlightPackage={context.recommendedPackage}
|
|
147
|
+
packages={packages}
|
|
148
|
+
/>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Styling
|
|
154
|
+
|
|
155
|
+
Components use design tokens for consistent styling:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { useAppDesignTokens } from '@umituz/react-native-design-system';
|
|
159
|
+
|
|
160
|
+
const tokens = useAppDesignTokens();
|
|
161
|
+
|
|
162
|
+
const styles = StyleSheet.create({
|
|
163
|
+
card: {
|
|
164
|
+
backgroundColor: tokens.colors.surface,
|
|
165
|
+
borderRadius: tokens.radius.lg,
|
|
166
|
+
padding: tokens.spacing.lg,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Best Practices
|
|
172
|
+
|
|
173
|
+
1. **Clear Value**: Communicate premium benefits clearly
|
|
174
|
+
2. **Visual Hierarchy**: Highlight recommended package
|
|
175
|
+
3. **Social Proof**: Show user counts or testimonials
|
|
176
|
+
4. **Easy Dismissal**: Allow users to close when appropriate
|
|
177
|
+
5. **Smooth Purchase**: Make purchase flow simple
|
|
178
|
+
6. **Loading States**: Show appropriate loading indicators
|
|
179
|
+
7. **Error Handling**: Handle purchase failures gracefully
|
|
180
|
+
|
|
181
|
+
## Related
|
|
182
|
+
|
|
183
|
+
- [Paywall README](../README.md)
|
|
184
|
+
- [PaywallVisibility Hook](../../hooks/usePaywallVisibility.md)
|
|
185
|
+
- [Premium Components](../../components/details/README.md)
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Paywall Entities
|
|
2
|
+
|
|
3
|
+
Domain entities for paywall configuration and state management.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This directory contains entities representing paywall configuration, triggers, and display logic.
|
|
8
|
+
|
|
9
|
+
## Entities
|
|
10
|
+
|
|
11
|
+
### PaywallTrigger
|
|
12
|
+
Represents an event that triggers paywall display.
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
interface PaywallTrigger {
|
|
16
|
+
type: PaywallTriggerType;
|
|
17
|
+
feature?: string;
|
|
18
|
+
packageName?: string;
|
|
19
|
+
context?: Record<string, any>;
|
|
20
|
+
timestamp: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type PaywallTriggerType =
|
|
24
|
+
| 'premium_feature' // Premium feature access attempt
|
|
25
|
+
| 'credit_gate' // Credit gate failure
|
|
26
|
+
| 'manual' // User manually opened
|
|
27
|
+
| 'onboarding_complete' // Post-onboarding
|
|
28
|
+
| 'usage_limit' // Free tier limit reached
|
|
29
|
+
| 'subscription_expired'; // Subscription expired
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Usage:**
|
|
33
|
+
```typescript
|
|
34
|
+
const trigger: PaywallTrigger = {
|
|
35
|
+
type: 'premium_feature',
|
|
36
|
+
feature: 'ai_generation',
|
|
37
|
+
context: { cost: 5 },
|
|
38
|
+
timestamp: Date.now(),
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### PaywallConfig
|
|
43
|
+
Configuration for paywall display.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
interface PaywallConfig {
|
|
47
|
+
title: string;
|
|
48
|
+
subtitle: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
features: string[];
|
|
51
|
+
highlightBenefit?: string; // Main value proposition
|
|
52
|
+
packages: PaywallPackage[];
|
|
53
|
+
defaultPackage?: string; // Pre-selected package
|
|
54
|
+
dismissible: boolean;
|
|
55
|
+
showCloseButton: boolean;
|
|
56
|
+
onUpgrade: (pkg: PaywallPackage) => void;
|
|
57
|
+
onDismiss: () => void;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Usage:**
|
|
62
|
+
```typescript
|
|
63
|
+
const config: PaywallConfig = {
|
|
64
|
+
title: 'Upgrade to Premium',
|
|
65
|
+
subtitle: 'Unlock all features',
|
|
66
|
+
features: [
|
|
67
|
+
'Unlimited access',
|
|
68
|
+
'Priority support',
|
|
69
|
+
'Ad-free experience',
|
|
70
|
+
],
|
|
71
|
+
packages: availablePackages,
|
|
72
|
+
dismissible: true,
|
|
73
|
+
showCloseButton: true,
|
|
74
|
+
onUpgrade: (pkg) => purchasePackage(pkg),
|
|
75
|
+
onDismiss: () => navigation.goBack(),
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### PaywallPackage
|
|
80
|
+
Represents a subscription package displayed in paywall.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
interface PaywallPackage {
|
|
84
|
+
identifier: string; // Unique package ID
|
|
85
|
+
productIdentifier: string; // RevenueCat product ID
|
|
86
|
+
title: string; // Display title
|
|
87
|
+
description: string; // Package description
|
|
88
|
+
price: number; // Price in local currency
|
|
89
|
+
pricePerMonth?: number; // Monthly equivalent (for annual)
|
|
90
|
+
currencyCode: string; // Currency code
|
|
91
|
+
period: PackagePeriod; // Billing period
|
|
92
|
+
features: string[]; // Package features
|
|
93
|
+
popular?: boolean; // Highlight as popular
|
|
94
|
+
savings?: number; // Savings amount (for annual)
|
|
95
|
+
badge?: string; // Custom badge text
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
type PackagePeriod = 'monthly' | 'annual' | 'lifetime';
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Usage:**
|
|
102
|
+
```typescript
|
|
103
|
+
const premiumPackage: PaywallPackage = {
|
|
104
|
+
identifier: 'premium_annual',
|
|
105
|
+
productIdentifier: 'com.app.premium.annual',
|
|
106
|
+
title: 'Premium Annual',
|
|
107
|
+
description: 'Best value - Save 50%',
|
|
108
|
+
price: 99.99,
|
|
109
|
+
pricePerMonth: 8.33,
|
|
110
|
+
currencyCode: 'USD',
|
|
111
|
+
period: 'annual',
|
|
112
|
+
features: [
|
|
113
|
+
'Unlimited access',
|
|
114
|
+
'Priority support',
|
|
115
|
+
'Ad-free',
|
|
116
|
+
'Advanced features',
|
|
117
|
+
],
|
|
118
|
+
popular: true,
|
|
119
|
+
savings: 20.00,
|
|
120
|
+
badge: 'BEST VALUE',
|
|
121
|
+
};
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### PaywallState
|
|
125
|
+
Manages current paywall state and context.
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
interface PaywallState {
|
|
129
|
+
visible: boolean;
|
|
130
|
+
trigger?: PaywallTrigger;
|
|
131
|
+
selectedPackage?: string;
|
|
132
|
+
pendingAction?: () => void; // Execute after upgrade
|
|
133
|
+
metadata?: {
|
|
134
|
+
userId?: string;
|
|
135
|
+
screen?: string; // Screen where paywall shown
|
|
136
|
+
previousScreen?: string; // Screen before paywall
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Usage:**
|
|
142
|
+
```typescript
|
|
143
|
+
const state: PaywallState = {
|
|
144
|
+
visible: true,
|
|
145
|
+
trigger: {
|
|
146
|
+
type: 'premium_feature',
|
|
147
|
+
feature: 'ai_generation',
|
|
148
|
+
timestamp: Date.now(),
|
|
149
|
+
},
|
|
150
|
+
selectedPackage: 'premium_annual',
|
|
151
|
+
pendingAction: () => executeAIGeneration(),
|
|
152
|
+
metadata: {
|
|
153
|
+
userId: 'user-123',
|
|
154
|
+
screen: 'AIGeneration',
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Key Operations
|
|
160
|
+
|
|
161
|
+
### Create Trigger
|
|
162
|
+
```typescript
|
|
163
|
+
function createTrigger(
|
|
164
|
+
type: PaywallTriggerType,
|
|
165
|
+
context?: Record<string, any>
|
|
166
|
+
): PaywallTrigger {
|
|
167
|
+
return {
|
|
168
|
+
type,
|
|
169
|
+
context,
|
|
170
|
+
timestamp: Date.now(),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Validate Config
|
|
176
|
+
```typescript
|
|
177
|
+
function validatePaywallConfig(config: PaywallConfig): void {
|
|
178
|
+
if (!config.title) throw new Error('Title is required');
|
|
179
|
+
if (!config.packages || config.packages.length === 0) {
|
|
180
|
+
throw new Error('At least one package is required');
|
|
181
|
+
}
|
|
182
|
+
if (config.defaultPackage && !config.packages.find(p => p.identifier === config.defaultPackage)) {
|
|
183
|
+
throw new Error('Default package must be in packages list');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Best Practices
|
|
189
|
+
|
|
190
|
+
1. **Rich Context**: Include context in triggers for analytics
|
|
191
|
+
2. **Validation**: Validate configurations before use
|
|
192
|
+
3. **Immutability**: Treat entities as immutable values
|
|
193
|
+
4. **Type Safety**: Use strict TypeScript types
|
|
194
|
+
5. **Analytics**: Track all paywall events and triggers
|
|
195
|
+
|
|
196
|
+
## Related
|
|
197
|
+
|
|
198
|
+
- [Paywall README](../README.md)
|
|
199
|
+
- [PaywallVisibility Hook](../../presentation/hooks/usePaywallVisibility.md)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Paywall Hooks
|
|
2
|
+
|
|
3
|
+
React hooks for paywall management and subscription upgrades.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This directory contains React hooks specifically for paywall functionality.
|
|
8
|
+
|
|
9
|
+
## Hooks
|
|
10
|
+
|
|
11
|
+
### usePaywallVisibility
|
|
12
|
+
Manages paywall visibility state.
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
function usePaywallVisibility(): {
|
|
16
|
+
showPaywall: boolean;
|
|
17
|
+
setShowPaywall: (visible: boolean) => void;
|
|
18
|
+
openPaywall: () => void;
|
|
19
|
+
closePaywall: () => void;
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Usage:**
|
|
24
|
+
```typescript
|
|
25
|
+
function PaywallWrapper() {
|
|
26
|
+
const { showPaywall, closePaywall } = usePaywallVisibility();
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<>
|
|
30
|
+
<YourApp />
|
|
31
|
+
<Modal visible={showPaywall} onRequestClose={closePaywall}>
|
|
32
|
+
<PaywallScreen onClose={closePaywall} />
|
|
33
|
+
</Modal>
|
|
34
|
+
</>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### usePaywallOperations
|
|
40
|
+
Handles paywall purchase operations.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
function usePaywallOperations(config: {
|
|
44
|
+
userId: string | undefined;
|
|
45
|
+
isAnonymous: boolean;
|
|
46
|
+
onPaywallClose?: () => void;
|
|
47
|
+
onPurchaseSuccess?: () => void;
|
|
48
|
+
onAuthRequired?: () => void;
|
|
49
|
+
}): {
|
|
50
|
+
handlePurchase: (pkg: Package) => Promise<boolean>;
|
|
51
|
+
handleRestore: () => Promise<boolean>;
|
|
52
|
+
pendingPackage: Package | null;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Usage:**
|
|
57
|
+
```typescript
|
|
58
|
+
function Paywall() {
|
|
59
|
+
const { handlePurchase, handleRestore } = usePaywallOperations({
|
|
60
|
+
userId: user?.uid,
|
|
61
|
+
isAnonymous: !user,
|
|
62
|
+
onPurchaseSuccess: () => navigation.goBack(),
|
|
63
|
+
onAuthRequired: () => showAuthModal(),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<View>
|
|
68
|
+
<PackageList onSelectPackage={handlePurchase} />
|
|
69
|
+
<Button onPress={handleRestore}>Restore</Button>
|
|
70
|
+
</View>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Usage Patterns
|
|
76
|
+
|
|
77
|
+
### Feature Gating
|
|
78
|
+
```typescript
|
|
79
|
+
function useFeatureGate(feature: string) {
|
|
80
|
+
const { openPaywall } = usePaywallVisibility();
|
|
81
|
+
const { isPremium } = usePremium();
|
|
82
|
+
|
|
83
|
+
const gateFeature = useCallback(() => {
|
|
84
|
+
if (!isPremium) {
|
|
85
|
+
analytics.track('paywall_triggered', { feature });
|
|
86
|
+
openPaywall();
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}, [isPremium, openPaywall]);
|
|
91
|
+
|
|
92
|
+
return gateFeature;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Trigger-Based Paywall
|
|
97
|
+
```typescript
|
|
98
|
+
function useTriggeredPaywall() {
|
|
99
|
+
const { openPaywall } = usePaywallVisibility();
|
|
100
|
+
|
|
101
|
+
const showPaywallForFeature = (feature: string, context?: any) => {
|
|
102
|
+
openPaywall();
|
|
103
|
+
// Store trigger context for analytics
|
|
104
|
+
PaywallTracker.record({
|
|
105
|
+
type: 'premium_feature',
|
|
106
|
+
feature,
|
|
107
|
+
context,
|
|
108
|
+
timestamp: Date.now(),
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return { showPaywallForFeature };
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Best Practices
|
|
117
|
+
|
|
118
|
+
1. **Centralized State**: Use global paywall visibility
|
|
119
|
+
2. **Auth Integration**: Handle authentication before purchase
|
|
120
|
+
3. **Pending Actions**: Store pending actions for post-purchase
|
|
121
|
+
4. **Analytics**: Track all paywall interactions
|
|
122
|
+
5. **Error Handling**: Handle purchase failures gracefully
|
|
123
|
+
6. **User Context**: Show relevant paywall based on context
|
|
124
|
+
|
|
125
|
+
## Related
|
|
126
|
+
|
|
127
|
+
- [usePaywallVisibility](../../presentation/hooks/usePaywallVisibility.md)
|
|
128
|
+
- [usePaywallOperations](../../presentation/hooks/usePaywallOperations.md)
|
|
129
|
+
- [PremiumGate Hook](../../presentation/hooks/usePremiumGate.md)
|