@umituz/react-native-subscription 2.14.97 → 2.14.98
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 +462 -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/config/README.md +390 -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 +160 -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/domain/README.md +147 -0
- package/src/revenuecat/domain/errors/README.md +197 -0
- package/src/revenuecat/infrastructure/config/README.md +40 -0
- package/src/revenuecat/infrastructure/managers/README.md +49 -0
- package/src/revenuecat/presentation/hooks/README.md +56 -0
- package/src/utils/README.md +529 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
# PaywallModal Component
|
|
2
|
+
|
|
3
|
+
Modal paywall component for subscription upgrade.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { PaywallModal } from '@umituz/react-native-subscription';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
interface PaywallModalProps {
|
|
15
|
+
isVisible: boolean;
|
|
16
|
+
onClose: () => void;
|
|
17
|
+
config?: PaywallConfig;
|
|
18
|
+
onPurchase?: (result: PurchaseResult) => void;
|
|
19
|
+
isLoading?: boolean;
|
|
20
|
+
translations?: PaywallTranslations;
|
|
21
|
+
theme?: 'light' | 'dark';
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Basic Usage
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
function PaywallExample() {
|
|
29
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
<Button onPress={() => setIsVisible(true)} title="Show Paywall" />
|
|
34
|
+
|
|
35
|
+
<PaywallModal
|
|
36
|
+
isVisible={isVisible}
|
|
37
|
+
onClose={() => setIsVisible(false)}
|
|
38
|
+
/>
|
|
39
|
+
</>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
### Basic Config
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
<PaywallModal
|
|
50
|
+
isVisible={isVisible}
|
|
51
|
+
onClose={handleClose}
|
|
52
|
+
config={{
|
|
53
|
+
title: 'Unlock Premium',
|
|
54
|
+
description: 'Get unlimited access to all features',
|
|
55
|
+
features: [
|
|
56
|
+
{ icon: '⭐', text: 'Unlimited Access' },
|
|
57
|
+
{ icon: '🚀', text: 'AI-Powered Tools' },
|
|
58
|
+
{ icon: '🛡️', text: 'Ad-Free Experience' },
|
|
59
|
+
],
|
|
60
|
+
}}
|
|
61
|
+
/>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Advanced Config
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const paywallConfig: PaywallConfig = {
|
|
68
|
+
title: 'Go Premium',
|
|
69
|
+
description: 'Join thousands of premium users',
|
|
70
|
+
features: [
|
|
71
|
+
{
|
|
72
|
+
icon: '💎',
|
|
73
|
+
text: 'Premium Content',
|
|
74
|
+
description: 'Access exclusive articles and videos',
|
|
75
|
+
highlight: true,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
icon: '⚡',
|
|
79
|
+
text: 'Faster Processing',
|
|
80
|
+
description: 'Get results in seconds, not minutes',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
icon: '💬',
|
|
84
|
+
text: 'Priority Support',
|
|
85
|
+
description: '24/7 dedicated support team',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
icon: '🎁',
|
|
89
|
+
text: 'Exclusive Features',
|
|
90
|
+
description: 'Early access to new features',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
theme: 'dark',
|
|
94
|
+
showCloseButton: true,
|
|
95
|
+
closeOnBackdropPress: false,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
<PaywallModal
|
|
99
|
+
isVisible={isVisible}
|
|
100
|
+
onClose={handleClose}
|
|
101
|
+
config={paywallConfig}
|
|
102
|
+
/>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Purchase Handling
|
|
106
|
+
|
|
107
|
+
### With Callback
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
<PaywallModal
|
|
111
|
+
isVisible={isVisible}
|
|
112
|
+
onClose={handleClose}
|
|
113
|
+
onPurchase={(result) => {
|
|
114
|
+
if (result.success) {
|
|
115
|
+
Alert.alert('Success', 'Welcome to Premium!');
|
|
116
|
+
setIsVisible(false);
|
|
117
|
+
} else {
|
|
118
|
+
Alert.alert('Error', result.error?.message || 'Purchase failed');
|
|
119
|
+
}
|
|
120
|
+
}}
|
|
121
|
+
/>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### With Custom Handler
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
function PaywallWithHandler() {
|
|
128
|
+
const { handlePurchase, isLoading } = usePaywallActions();
|
|
129
|
+
|
|
130
|
+
const onPurchase = async (pkg: Package) => {
|
|
131
|
+
const result = await handlePurchase(pkg);
|
|
132
|
+
|
|
133
|
+
if (result.success) {
|
|
134
|
+
// Analytics
|
|
135
|
+
analytics.track('purchase_completed', {
|
|
136
|
+
packageId: pkg.identifier,
|
|
137
|
+
revenue: pkg.product.price,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Navigation
|
|
141
|
+
navigation.goBack();
|
|
142
|
+
|
|
143
|
+
// Success message
|
|
144
|
+
Toast.show({
|
|
145
|
+
type: 'success',
|
|
146
|
+
text1: 'Purchase Successful!',
|
|
147
|
+
text2: 'You are now a Premium user',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return result;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<PaywallModal
|
|
156
|
+
isVisible={isVisible}
|
|
157
|
+
onClose={handleClose}
|
|
158
|
+
onPurchase={onPurchase}
|
|
159
|
+
isLoading={isLoading}
|
|
160
|
+
/>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Customization
|
|
166
|
+
|
|
167
|
+
### Custom Theme
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const customTheme = {
|
|
171
|
+
colors: {
|
|
172
|
+
primary: '#FF6B6B',
|
|
173
|
+
background: '#1a1a1a',
|
|
174
|
+
card: '#2d2d2d',
|
|
175
|
+
text: '#ffffff',
|
|
176
|
+
textSecondary: '#999999',
|
|
177
|
+
border: '#3d3d3d',
|
|
178
|
+
},
|
|
179
|
+
fonts: {
|
|
180
|
+
title: {
|
|
181
|
+
fontSize: 28,
|
|
182
|
+
fontWeight: 'bold',
|
|
183
|
+
},
|
|
184
|
+
body: {
|
|
185
|
+
fontSize: 16,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
borderRadius: 16,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
<PaywallModal
|
|
192
|
+
isVisible={isVisible}
|
|
193
|
+
onClose={handleClose}
|
|
194
|
+
theme={customTheme}
|
|
195
|
+
/>
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Custom Package Display
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
function CustomPaywall() {
|
|
202
|
+
const { packages } = useSubscriptionPackages();
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<PaywallModal
|
|
206
|
+
isVisible={isVisible}
|
|
207
|
+
onClose={handleClose}
|
|
208
|
+
config={{
|
|
209
|
+
title: 'Choose Your Plan',
|
|
210
|
+
packages: packages.map(pkg => ({
|
|
211
|
+
identifier: pkg.identifier,
|
|
212
|
+
title: pkg.product.title,
|
|
213
|
+
description: pkg.product.description,
|
|
214
|
+
price: pkg.product.priceString,
|
|
215
|
+
popular: pkg.identifier.includes('annual'),
|
|
216
|
+
savings: pkg.identifier.includes('annual')
|
|
217
|
+
? 'Save 33%'
|
|
218
|
+
: undefined,
|
|
219
|
+
})),
|
|
220
|
+
}}
|
|
221
|
+
/>
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## A/B Testing
|
|
227
|
+
|
|
228
|
+
### Variant A
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const variantAConfig: PaywallConfig = {
|
|
232
|
+
title: 'Unlock Premium',
|
|
233
|
+
description: 'Get unlimited access',
|
|
234
|
+
features: [
|
|
235
|
+
{ icon: '⭐', text: 'Unlimited Access' },
|
|
236
|
+
{ icon: '🚀', text: 'AI Tools' },
|
|
237
|
+
],
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
<PaywallModal
|
|
241
|
+
config={variantAConfig}
|
|
242
|
+
...
|
|
243
|
+
/>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Variant B
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
const variantBConfig: PaywallConfig = {
|
|
250
|
+
title: 'Join Premium Members',
|
|
251
|
+
description: 'Over 10,000 users',
|
|
252
|
+
features: [
|
|
253
|
+
{ icon: '💎', text: 'Premium Content' },
|
|
254
|
+
{ icon: '⚡', text: 'Priority Speed' },
|
|
255
|
+
{ icon: '💬', text: 'VIP Support' },
|
|
256
|
+
{ icon: '🎁', text: 'Exclusive Perks' },
|
|
257
|
+
],
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
<PaywallModal
|
|
261
|
+
config={variantBConfig}
|
|
262
|
+
...
|
|
263
|
+
/>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Translations
|
|
267
|
+
|
|
268
|
+
### Multi-Language Support
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
const translations = {
|
|
272
|
+
en: {
|
|
273
|
+
title: 'Unlock Premium',
|
|
274
|
+
subscribe: 'Subscribe Now',
|
|
275
|
+
features: 'Features',
|
|
276
|
+
restore: 'Restore Purchase',
|
|
277
|
+
close: 'Close',
|
|
278
|
+
},
|
|
279
|
+
tr: {
|
|
280
|
+
title: 'Premium\'e Geç',
|
|
281
|
+
subscribe: 'Şimdi Abone Ol',
|
|
282
|
+
features: 'Özellikler',
|
|
283
|
+
restore: 'Satın Almayı Geri Yükle',
|
|
284
|
+
close: 'Kapat',
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
<PaywallModal
|
|
289
|
+
translations={translations[userLanguage]}
|
|
290
|
+
...
|
|
291
|
+
/>
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Responsive Design
|
|
295
|
+
|
|
296
|
+
The modal is responsive and adapts to:
|
|
297
|
+
|
|
298
|
+
- **iPhone SE**: Compact layout
|
|
299
|
+
- **iPhone 14 Pro**: Standard layout
|
|
300
|
+
- **iPad**: Tablet-optimized layout
|
|
301
|
+
- **Landscape**: Adjusted spacing
|
|
302
|
+
|
|
303
|
+
## Performance
|
|
304
|
+
|
|
305
|
+
### Lazy Loading
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
function LazyPaywall() {
|
|
309
|
+
const [showPaywall, setShowPaywall] = useState(false);
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<>
|
|
313
|
+
<Button onPress={() => setShowPaywall(true)} />
|
|
314
|
+
|
|
315
|
+
{showPaywall && (
|
|
316
|
+
<PaywallModal
|
|
317
|
+
isVisible={showPaywall}
|
|
318
|
+
onClose={() => setShowPaywall(false)}
|
|
319
|
+
/>
|
|
320
|
+
)}
|
|
321
|
+
</>
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Preloading Packages
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
function PreloadedPaywall() {
|
|
330
|
+
const { packages, isLoading } = useSubscriptionPackages({
|
|
331
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// Preload packages before showing paywall
|
|
335
|
+
useEffect(() => {
|
|
336
|
+
if (!packages.length) {
|
|
337
|
+
// Trigger background fetch
|
|
338
|
+
refetch();
|
|
339
|
+
}
|
|
340
|
+
}, []);
|
|
341
|
+
|
|
342
|
+
return (
|
|
343
|
+
<PaywallModal
|
|
344
|
+
isVisible={isVisible}
|
|
345
|
+
config={{ packages }}
|
|
346
|
+
/>
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Best Practices
|
|
352
|
+
|
|
353
|
+
1. **Track impressions** - Log when paywall is shown
|
|
354
|
+
2. **Track dismissals** - Log when and why users close
|
|
355
|
+
3. **Test different copy** - A/B test titles and features
|
|
356
|
+
4. **Use social proof** - Show user count or ratings
|
|
357
|
+
5. **Highlight savings** - Show annual savings
|
|
358
|
+
6. **Make it actionable** - Clear CTA buttons
|
|
359
|
+
7. **Handle orientation** - Test in landscape and portrait
|
|
360
|
+
|
|
361
|
+
## Complete Example
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
function CompletePaywallFlow() {
|
|
365
|
+
const { isPremium } = usePremium();
|
|
366
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
367
|
+
const [paywallShown, setPaywallShown] = useState(false);
|
|
368
|
+
|
|
369
|
+
// Auto-show after 3 actions
|
|
370
|
+
const { actionCount } = useActionCounter();
|
|
371
|
+
useEffect(() => {
|
|
372
|
+
if (!isPremium && actionCount >= 3 && !paywallShown) {
|
|
373
|
+
setIsVisible(true);
|
|
374
|
+
setPaywallShown(true);
|
|
375
|
+
|
|
376
|
+
analytics.track('auto_paywall_shown', {
|
|
377
|
+
trigger: 'action_limit',
|
|
378
|
+
actions: actionCount,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}, [actionCount, isPremium, paywallShown]);
|
|
382
|
+
|
|
383
|
+
const handlePurchase = async (result: PurchaseResult) => {
|
|
384
|
+
if (result.success) {
|
|
385
|
+
analytics.track('purchase_completed', {
|
|
386
|
+
packageId: result.packageId,
|
|
387
|
+
revenue: result.revenue,
|
|
388
|
+
trigger: 'auto_paywall',
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
setIsVisible(false);
|
|
392
|
+
|
|
393
|
+
Alert.alert(
|
|
394
|
+
'Welcome to Premium!',
|
|
395
|
+
'Thank you for subscribing.'
|
|
396
|
+
);
|
|
397
|
+
} else {
|
|
398
|
+
analytics.track('purchase_failed', {
|
|
399
|
+
error: result.error?.message,
|
|
400
|
+
trigger: 'auto_paywall',
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const handleClose = () => {
|
|
406
|
+
const duration = Date.now() - paywallShownAt;
|
|
407
|
+
analytics.track('paywall_closed', {
|
|
408
|
+
duration,
|
|
409
|
+
trigger: 'auto_paywall',
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
setIsVisible(false);
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
return (
|
|
416
|
+
<PaywallModal
|
|
417
|
+
isVisible={isVisible}
|
|
418
|
+
onClose={handleClose}
|
|
419
|
+
onPurchase={handlePurchase}
|
|
420
|
+
config={{
|
|
421
|
+
title: 'You\'re Awesome! 🎉',
|
|
422
|
+
description: `${actionCount} actions completed. Upgrade for unlimited access!`,
|
|
423
|
+
features: [
|
|
424
|
+
{ icon: '∞', text: 'Unlimited Actions', highlight: true },
|
|
425
|
+
{ icon: '⚡', text: 'Lightning Fast' },
|
|
426
|
+
{ icon: '🛡️', text: 'Ad-Free Experience' },
|
|
427
|
+
],
|
|
428
|
+
}}
|
|
429
|
+
/>
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## Related Components
|
|
435
|
+
|
|
436
|
+
- **PaywallScreen** - Full-screen paywall
|
|
437
|
+
- **PremiumDetailsCard** - Premium status card
|
|
438
|
+
- **PaywallFeedbackModal** - Feedback collection
|
|
439
|
+
|
|
440
|
+
## See Also
|
|
441
|
+
|
|
442
|
+
- [Paywall Domain](../../../domains/paywall/README.md)
|
|
443
|
+
- [usePaywall Hooks](../../hooks/usePaywall.md)
|
|
444
|
+
- [Paywall README](../feedback/README.md)
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Paywall Components
|
|
2
|
+
|
|
3
|
+
UI components specifically designed for paywall and subscription upgrade screens.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This directory contains specialized components for displaying paywalls, package selection, and subscription upgrade prompts.
|
|
8
|
+
|
|
9
|
+
## Components
|
|
10
|
+
|
|
11
|
+
### PaywallModal
|
|
12
|
+
Modal overlay for paywall display.
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
interface PaywallModalProps {
|
|
16
|
+
visible: boolean;
|
|
17
|
+
onClose: () => void;
|
|
18
|
+
onPurchase: (pkg: Package) => void;
|
|
19
|
+
configuration: PaywallConfig;
|
|
20
|
+
restorePurchases?: () => void;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Features:**
|
|
25
|
+
- Modal overlay with backdrop dismissal
|
|
26
|
+
- Animated entry and exit
|
|
27
|
+
- Close button
|
|
28
|
+
- Responsive layout
|
|
29
|
+
- Loading states
|
|
30
|
+
|
|
31
|
+
### PackageCard
|
|
32
|
+
Individual subscription package display.
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
interface PackageCardProps {
|
|
36
|
+
package: Package;
|
|
37
|
+
selected?: boolean;
|
|
38
|
+
onSelect: () => void;
|
|
39
|
+
displayMode?: 'card' | 'list' | 'minimal';
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Display Modes:**
|
|
44
|
+
- **card**: Full featured card with all details
|
|
45
|
+
- **list**: Compact list item
|
|
46
|
+
- **minimal**: Minimal version for tight spaces
|
|
47
|
+
|
|
48
|
+
### FeatureComparison
|
|
49
|
+
Comparison table showing features across packages.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
interface FeatureComparisonProps {
|
|
53
|
+
packages: Package[];
|
|
54
|
+
features: string[];
|
|
55
|
+
highlightPackage?: string;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### SocialProofBar
|
|
60
|
+
Social proof element showing user count and ratings.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
interface SocialProofBarProps {
|
|
64
|
+
userCount?: number;
|
|
65
|
+
rating?: number;
|
|
66
|
+
style?: 'compact' | 'expanded';
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### CTAButton
|
|
71
|
+
Call-to-action button for purchase.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
interface CTAButtonProps {
|
|
75
|
+
package: Package;
|
|
76
|
+
onPress: () => void;
|
|
77
|
+
disabled?: boolean;
|
|
78
|
+
loading?: boolean;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Usage Examples
|
|
83
|
+
|
|
84
|
+
### Basic Paywall
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { PaywallModal } from './components/PaywallModal';
|
|
88
|
+
|
|
89
|
+
function PaywallFlow() {
|
|
90
|
+
const [visible, setVisible] = useState(false);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
<Button onPress={() => setVisible(true)}>Show Paywall</Button>
|
|
95
|
+
|
|
96
|
+
<PaywallModal
|
|
97
|
+
visible={visible}
|
|
98
|
+
onClose={() => setVisible(false)}
|
|
99
|
+
onPurchase={handlePurchase}
|
|
100
|
+
configuration={paywallConfig}
|
|
101
|
+
/>
|
|
102
|
+
</>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Package Selection
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { PackageCard } from './components/PackageCard';
|
|
111
|
+
|
|
112
|
+
function PackageSelection() {
|
|
113
|
+
const [selected, setSelected] = useState('premium_annual');
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<ScrollView horizontal>
|
|
117
|
+
{packages.map(pkg => (
|
|
118
|
+
<PackageCard
|
|
119
|
+
key={pkg.identifier}
|
|
120
|
+
package={pkg}
|
|
121
|
+
selected={selected === pkg.identifier}
|
|
122
|
+
onSelect={() => setSelected(pkg.identifier)}
|
|
123
|
+
/>
|
|
124
|
+
))}
|
|
125
|
+
</ScrollView>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Feature Comparison
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { FeatureComparison } from './components/FeatureComparison';
|
|
134
|
+
|
|
135
|
+
function PaywallComparison() {
|
|
136
|
+
const features = [
|
|
137
|
+
'Unlimited Access',
|
|
138
|
+
'Ad-Free',
|
|
139
|
+
'Priority Support',
|
|
140
|
+
'AI Features',
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<FeatureComparison
|
|
145
|
+
packages={packages}
|
|
146
|
+
features={features}
|
|
147
|
+
highlightPackage="premium_annual"
|
|
148
|
+
/>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Component 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 cardStyles = StyleSheet.create({
|
|
163
|
+
card: {
|
|
164
|
+
backgroundColor: tokens.colors.surface,
|
|
165
|
+
borderRadius: tokens.radius.xl,
|
|
166
|
+
padding: tokens.spacing.xl,
|
|
167
|
+
shadowColor: tokens.colors.shadow,
|
|
168
|
+
shadowOffset: { width: 0, height: 2 },
|
|
169
|
+
shadowOpacity: 0.1,
|
|
170
|
+
shadowRadius: 8,
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Best Practices
|
|
176
|
+
|
|
177
|
+
1. **Visual Hierarchy**: Highlight recommended packages clearly
|
|
178
|
+
2. **Clear Pricing**: Show price, period, and per-month equivalent
|
|
179
|
+
3. **Feature Clarity**: Make features easy to understand
|
|
180
|
+
4. **Social Proof**: Include ratings, reviews, user counts
|
|
181
|
+
5. **Trust Signals**: Show guarantees, badges, certifications
|
|
182
|
+
6. **Mobile First**: Optimize for mobile screens
|
|
183
|
+
7. **Performance**: Lazy load images, avoid expensive animations
|
|
184
|
+
8. **Accessibility**: Support screen readers, proper touch targets
|
|
185
|
+
|
|
186
|
+
## Related
|
|
187
|
+
|
|
188
|
+
- [Paywall README](../../../domains/paywall/README.md)
|
|
189
|
+
- [usePaywallVisibility](../../hooks/usePaywallVisibility.md)
|
|
190
|
+
- [PaywallOperations](../../hooks/usePaywallOperations.md)
|