@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
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# Feedback Components
|
|
2
|
+
|
|
3
|
+
Kullanıcı etkileşimi ve feedback için UI bileşenleri.
|
|
4
|
+
|
|
5
|
+
## Bileşenler
|
|
6
|
+
|
|
7
|
+
- [PaywallFeedbackModal](#paywallfeedbackmodal) - Paywall feedback modal'ı
|
|
8
|
+
|
|
9
|
+
## PaywallFeedbackModal
|
|
10
|
+
|
|
11
|
+
Kullanıcıların paywall deneyimi hakkında feedback vermeleri için modal bileşeni.
|
|
12
|
+
|
|
13
|
+
### Kullanım
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import React, { useState } from 'react';
|
|
17
|
+
import { Button } from 'react-native';
|
|
18
|
+
import { PaywallFeedbackModal } from '@umituz/react-native-subscription';
|
|
19
|
+
|
|
20
|
+
function PaywallScreen() {
|
|
21
|
+
const [showFeedback, setShowFeedback] = useState(false);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<Button
|
|
26
|
+
onPress={() => setShowFeedback(true)}
|
|
27
|
+
title="Give Feedback"
|
|
28
|
+
/>
|
|
29
|
+
|
|
30
|
+
<PaywallFeedbackModal
|
|
31
|
+
isVisible={showFeedback}
|
|
32
|
+
onClose={() => setShowFeedback(false)}
|
|
33
|
+
onSubmit={(feedback) => {
|
|
34
|
+
console.log('Feedback submitted:', feedback);
|
|
35
|
+
// Analytics tracking
|
|
36
|
+
analytics.track('paywall_feedback', {
|
|
37
|
+
feedback,
|
|
38
|
+
timestamp: new Date().toISOString(),
|
|
39
|
+
});
|
|
40
|
+
setShowFeedback(false);
|
|
41
|
+
}}
|
|
42
|
+
translations={{
|
|
43
|
+
title: 'Tell us why',
|
|
44
|
+
placeholder: 'Share your thoughts...',
|
|
45
|
+
submit: 'Submit',
|
|
46
|
+
cancel: 'Cancel',
|
|
47
|
+
}}
|
|
48
|
+
/>
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Props
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
interface PaywallFeedbackModalProps {
|
|
58
|
+
isVisible: boolean;
|
|
59
|
+
onClose: () => void;
|
|
60
|
+
onSubmit: (feedback: string) => void;
|
|
61
|
+
translations?: PaywallFeedbackTranslations;
|
|
62
|
+
placeholder?: string;
|
|
63
|
+
maxLength?: number;
|
|
64
|
+
showRating?: boolean;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Özellikler
|
|
69
|
+
|
|
70
|
+
- Kullanıcı feedback'i toplama
|
|
71
|
+
- Özelleştirilebilir çeviri desteği
|
|
72
|
+
- Karakter limiti
|
|
73
|
+
- Opsiyonel rating sistemi
|
|
74
|
+
- Smooth animasyonlar
|
|
75
|
+
|
|
76
|
+
### Detaylı Kullanım
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { PaywallFeedbackModal } from '@umituz/react-native-subscription';
|
|
80
|
+
|
|
81
|
+
function AdvancedFeedback() {
|
|
82
|
+
const [showFeedback, setShowFeedback] = useState(false);
|
|
83
|
+
const [feedbackData, setFeedbackData] = useState({
|
|
84
|
+
rating: 0,
|
|
85
|
+
feedback: '',
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const handleSubmit = (feedback: string) => {
|
|
89
|
+
// Feedback'i kaydet
|
|
90
|
+
saveFeedback({
|
|
91
|
+
...feedbackData,
|
|
92
|
+
feedback,
|
|
93
|
+
timestamp: new Date().toISOString(),
|
|
94
|
+
userId: currentUser.id,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Analytics tracking
|
|
98
|
+
analytics.track('paywall_feedback_submitted', {
|
|
99
|
+
rating: feedbackData.rating,
|
|
100
|
+
feedbackLength: feedback.length,
|
|
101
|
+
hasFeedback: feedback.length > 0,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
setShowFeedback(false);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<PaywallFeedbackModal
|
|
109
|
+
isVisible={showFeedback}
|
|
110
|
+
onClose={() => setShowFeedback(false)}
|
|
111
|
+
onSubmit={handleSubmit}
|
|
112
|
+
placeholder="Why didn't you subscribe? What can we improve?"
|
|
113
|
+
maxLength={500}
|
|
114
|
+
showRating={true}
|
|
115
|
+
onRatingChange={(rating) => {
|
|
116
|
+
setFeedbackData(prev => ({ ...prev, rating }));
|
|
117
|
+
}}
|
|
118
|
+
translations={{
|
|
119
|
+
title: 'Help us improve',
|
|
120
|
+
placeholder: 'Tell us what you think...',
|
|
121
|
+
submit: 'Submit Feedback',
|
|
122
|
+
cancel: 'Cancel',
|
|
123
|
+
ratingLabels: ['Poor', 'Fair', 'Good', 'Very Good', 'Excellent'],
|
|
124
|
+
}}
|
|
125
|
+
/>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Analytics Entegrasyonu
|
|
131
|
+
|
|
132
|
+
Feedback'i analytics ile takip edin:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { PaywallFeedbackModal } from '@umituz/react-native-subscription';
|
|
136
|
+
|
|
137
|
+
function PaywallWithTracking() {
|
|
138
|
+
const [showPaywall, setShowPaywall] = useState(true);
|
|
139
|
+
const [showFeedback, setShowFeedback] = useState(false);
|
|
140
|
+
const [paywallShownAt, setPaywallShownAt] = useState<Date | null>(null);
|
|
141
|
+
|
|
142
|
+
// Paywall gösterimini track et
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
if (showPaywall) {
|
|
145
|
+
setPaywallShownAt(new Date());
|
|
146
|
+
analytics.track('paywall_impression', {
|
|
147
|
+
timestamp: new Date().toISOString(),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}, [showPaywall]);
|
|
151
|
+
|
|
152
|
+
const handlePaywallClose = () => {
|
|
153
|
+
// Kullanıcı paywall'ı kapattı
|
|
154
|
+
const duration = paywallShownAt
|
|
155
|
+
? Date.now() - paywallShownAt.getTime()
|
|
156
|
+
: 0;
|
|
157
|
+
|
|
158
|
+
analytics.track('paywall_dismissed', {
|
|
159
|
+
duration,
|
|
160
|
+
timestamp: new Date().toISOString(),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Feedback göster (opsiyonel)
|
|
164
|
+
if (duration > 5000) {
|
|
165
|
+
// 5 saniyeden uzun bakmışsa
|
|
166
|
+
setShowFeedback(true);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
setShowPaywall(false);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const handleFeedbackSubmit = (feedback: string) => {
|
|
173
|
+
analytics.track('paywall_feedback', {
|
|
174
|
+
feedback,
|
|
175
|
+
feedbackLength: feedback.length,
|
|
176
|
+
hasFeedback: feedback.length > 0,
|
|
177
|
+
timestamp: new Date().toISOString(),
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
setShowFeedback(false);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<>
|
|
185
|
+
<PaywallModal
|
|
186
|
+
isVisible={showPaywall}
|
|
187
|
+
onClose={handlePaywallClose}
|
|
188
|
+
/>
|
|
189
|
+
|
|
190
|
+
<PaywallFeedbackModal
|
|
191
|
+
isVisible={showFeedback}
|
|
192
|
+
onClose={() => setShowFeedback(false)}
|
|
193
|
+
onSubmit={handleFeedbackSubmit}
|
|
194
|
+
translations={{
|
|
195
|
+
title: 'Tell us why',
|
|
196
|
+
placeholder: 'Why did you decide not to subscribe?',
|
|
197
|
+
submit: 'Submit',
|
|
198
|
+
cancel: 'Skip',
|
|
199
|
+
}}
|
|
200
|
+
/>
|
|
201
|
+
</>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Feedback Kategorileri
|
|
207
|
+
|
|
208
|
+
Farklı feedback senaryoları için:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import { PaywallFeedbackModal } from '@umituz/react-native-subscription';
|
|
212
|
+
|
|
213
|
+
type FeedbackReason =
|
|
214
|
+
| 'too_expensive'
|
|
215
|
+
| 'dont_need_features'
|
|
216
|
+
| 'technical_issues'
|
|
217
|
+
| 'prefer_free'
|
|
218
|
+
| 'other';
|
|
219
|
+
|
|
220
|
+
function CategorizedFeedback() {
|
|
221
|
+
const [selectedReason, setSelectedReason] = useState<FeedbackReason | null>(null);
|
|
222
|
+
|
|
223
|
+
const reasons = [
|
|
224
|
+
{ id: 'too_expensive', label: 'Too expensive', icon: '💰' },
|
|
225
|
+
{ id: 'dont_need_features', label: "Don't need features", icon: '🤷' },
|
|
226
|
+
{ id: 'technical_issues', label: 'Technical issues', icon: '🔧' },
|
|
227
|
+
{ id: 'prefer_free', label: 'Prefer free version', icon: '🆓' },
|
|
228
|
+
{ id: 'other', label: 'Other', icon: '💬' },
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<PaywallFeedbackModal
|
|
233
|
+
isVisible={showFeedback}
|
|
234
|
+
onClose={() => setShowFeedback(false)}
|
|
235
|
+
onSubmit={(feedback) => {
|
|
236
|
+
saveFeedback({
|
|
237
|
+
reason: selectedReason,
|
|
238
|
+
feedback,
|
|
239
|
+
timestamp: new Date().toISOString(),
|
|
240
|
+
});
|
|
241
|
+
}}
|
|
242
|
+
customContent={
|
|
243
|
+
<View>
|
|
244
|
+
<Text>Why didn't you subscribe?</Text>
|
|
245
|
+
{reasons.map((reason) => (
|
|
246
|
+
<TouchableOpacity
|
|
247
|
+
key={reason.id}
|
|
248
|
+
onPress={() => setSelectedReason(reason.id as FeedbackReason)}
|
|
249
|
+
style={[
|
|
250
|
+
styles.reasonButton,
|
|
251
|
+
selectedReason === reason.id && styles.selected,
|
|
252
|
+
]}
|
|
253
|
+
>
|
|
254
|
+
<Text>{reason.icon}</Text>
|
|
255
|
+
<Text>{reason.label}</Text>
|
|
256
|
+
</TouchableOpacity>
|
|
257
|
+
))}
|
|
258
|
+
</View>
|
|
259
|
+
}
|
|
260
|
+
/>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Styling
|
|
266
|
+
|
|
267
|
+
Özel stiller kullanma:
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
import { paywallFeedbackStyles } from '@umituz/react-native-subscription';
|
|
271
|
+
|
|
272
|
+
const customStyles = StyleSheet.create({
|
|
273
|
+
modal: {
|
|
274
|
+
margin: 20,
|
|
275
|
+
backgroundColor: '#fff',
|
|
276
|
+
borderRadius: 16,
|
|
277
|
+
padding: 24,
|
|
278
|
+
},
|
|
279
|
+
title: {
|
|
280
|
+
fontSize: 24,
|
|
281
|
+
fontWeight: 'bold',
|
|
282
|
+
color: '#FF6B6B',
|
|
283
|
+
marginBottom: 16,
|
|
284
|
+
},
|
|
285
|
+
textArea: {
|
|
286
|
+
borderWidth: 1,
|
|
287
|
+
borderColor: '#E0E0E0',
|
|
288
|
+
borderRadius: 8,
|
|
289
|
+
padding: 12,
|
|
290
|
+
minHeight: 120,
|
|
291
|
+
fontSize: 16,
|
|
292
|
+
},
|
|
293
|
+
buttonContainer: {
|
|
294
|
+
flexDirection: 'row',
|
|
295
|
+
justifyContent: 'space-between',
|
|
296
|
+
marginTop: 16,
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
<PaywallFeedbackModal
|
|
301
|
+
isVisible={showFeedback}
|
|
302
|
+
onClose={handleClose}
|
|
303
|
+
onSubmit={handleSubmit}
|
|
304
|
+
style={customStyles.modal}
|
|
305
|
+
titleStyle={customStyles.title}
|
|
306
|
+
textAreaStyle={customStyles.textArea}
|
|
307
|
+
buttonContainerStyle={customStyles.buttonContainer}
|
|
308
|
+
/>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Best Practices
|
|
312
|
+
|
|
313
|
+
1. **Timing**: Feedback'i doğru zamanda gösterin (paywall'dan hemen sonra)
|
|
314
|
+
2. **Optional**: Feedback'i zorunlu yapmayın
|
|
315
|
+
3. **Short**: Kullanıcıdan kısa feedback isteyin
|
|
316
|
+
4. **Actionable**: Feedback'i ürün geliştirmede kullanın
|
|
317
|
+
5. **Privacy**: Kullanıcıya feedback'in nasıl kullanılacağını bildirin
|
|
318
|
+
6. **Analytics**: Feedback verilerini analytics ile takip edin
|
|
319
|
+
7. **Follow-up**: Ciddi sorunlarda follow-up yapın
|
|
320
|
+
|
|
321
|
+
## Örnek: Complete Feedback Flow
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
import React, { useState, useEffect } from 'react';
|
|
325
|
+
import { View, Button } from 'react-native';
|
|
326
|
+
import { PaywallFeedbackModal } from '@umituz/react-native-subscription';
|
|
327
|
+
|
|
328
|
+
function PaywallWithFeedbackFlow() {
|
|
329
|
+
const [paywallVisible, setPaywallVisible] = useState(true);
|
|
330
|
+
const [feedbackVisible, setFeedbackVisible] = useState(false);
|
|
331
|
+
const [paywallStartTime, setPaywallStartTime] = useState<number>(0);
|
|
332
|
+
|
|
333
|
+
// Paywall gösterimini track et
|
|
334
|
+
useEffect(() => {
|
|
335
|
+
if (paywallVisible) {
|
|
336
|
+
setPaywallStartTime(Date.now());
|
|
337
|
+
analytics.track('paywall_shown', {
|
|
338
|
+
timestamp: new Date().toISOString(),
|
|
339
|
+
source: 'upgrade_button',
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}, [paywallVisible]);
|
|
343
|
+
|
|
344
|
+
const handlePaywallClose = (result: 'purchased' | 'dismissed') => {
|
|
345
|
+
const duration = Date.now() - paywallStartTime;
|
|
346
|
+
|
|
347
|
+
analytics.track('paywall_closed', {
|
|
348
|
+
result,
|
|
349
|
+
duration,
|
|
350
|
+
timestamp: new Date().toISOString(),
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
if (result === 'dismissed' && duration > 3000) {
|
|
354
|
+
// 3 saniyeden uzun baktıysa feedback iste
|
|
355
|
+
setFeedbackVisible(true);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
setPaywallVisible(false);
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
const handleFeedbackSubmit = (feedback: string) => {
|
|
362
|
+
analytics.track('paywall_feedback_submitted', {
|
|
363
|
+
feedback,
|
|
364
|
+
feedbackLength: feedback.length,
|
|
365
|
+
timestamp: new Date().toISOString(),
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// Optional: Firebase'e kaydet
|
|
369
|
+
if (feedback.trim()) {
|
|
370
|
+
firestore()
|
|
371
|
+
.collection('feedback')
|
|
372
|
+
.add({
|
|
373
|
+
type: 'paywall',
|
|
374
|
+
feedback,
|
|
375
|
+
userId: currentUser?.id,
|
|
376
|
+
timestamp: new Date().toISOString(),
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
setFeedbackVisible(false);
|
|
381
|
+
|
|
382
|
+
// Teşekkür mesajı göster
|
|
383
|
+
Alert.alert('Thank you!', 'Thanks for your feedback.');
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
return (
|
|
387
|
+
<View>
|
|
388
|
+
<Button
|
|
389
|
+
onPress={() => setPaywallVisible(true)}
|
|
390
|
+
title="Show Paywall"
|
|
391
|
+
/>
|
|
392
|
+
|
|
393
|
+
<PaywallModal
|
|
394
|
+
isVisible={paywallVisible}
|
|
395
|
+
onClose={() => handlePaywallClose('dismissed')}
|
|
396
|
+
onPurchase={() => handlePaywallClose('purchased')}
|
|
397
|
+
/>
|
|
398
|
+
|
|
399
|
+
<PaywallFeedbackModal
|
|
400
|
+
isVisible={feedbackVisible}
|
|
401
|
+
onClose={() => setFeedbackVisible(false)}
|
|
402
|
+
onSubmit={handleFeedbackSubmit}
|
|
403
|
+
placeholder="What would make this offer better for you?"
|
|
404
|
+
maxLength={300}
|
|
405
|
+
translations={{
|
|
406
|
+
title: 'Quick question',
|
|
407
|
+
placeholder: 'Your feedback helps us improve',
|
|
408
|
+
submit: 'Send Feedback',
|
|
409
|
+
cancel: 'No thanks',
|
|
410
|
+
}}
|
|
411
|
+
/>
|
|
412
|
+
</View>
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
## Translations
|
|
418
|
+
|
|
419
|
+
Farklı dillerde destek:
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
const translations = {
|
|
423
|
+
'en': {
|
|
424
|
+
title: 'Tell us why',
|
|
425
|
+
placeholder: 'Share your thoughts...',
|
|
426
|
+
submit: 'Submit',
|
|
427
|
+
cancel: 'Cancel',
|
|
428
|
+
},
|
|
429
|
+
'tr': {
|
|
430
|
+
title: 'Bize nedenlerini söyleyin',
|
|
431
|
+
placeholder: 'Düşüncelerinizi paylaşın...',
|
|
432
|
+
submit: 'Gönder',
|
|
433
|
+
cancel: 'İptal',
|
|
434
|
+
},
|
|
435
|
+
'de': {
|
|
436
|
+
title: 'Sagen Sie uns warum',
|
|
437
|
+
placeholder: 'Teilen Sie uns Ihre Gedanken mit...',
|
|
438
|
+
submit: 'Absenden',
|
|
439
|
+
cancel: 'Abbrechen',
|
|
440
|
+
},
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
<PaywallFeedbackModal
|
|
444
|
+
translations={translations[userLanguage]}
|
|
445
|
+
onSubmit={handleSubmit}
|
|
446
|
+
/>
|
|
447
|
+
```
|