@umituz/react-native-subscription 2.24.13 → 2.24.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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.24.
|
|
3
|
+
"version": "2.24.15",
|
|
4
4
|
"description": "Complete subscription management with RevenueCat, paywall UI, and credits system for React Native apps",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
TextInput,
|
|
13
13
|
KeyboardAvoidingView,
|
|
14
14
|
} from "react-native";
|
|
15
|
-
import { AtomicText } from "@umituz/react-native-design-system";
|
|
15
|
+
import { AtomicText, BaseModal } from "@umituz/react-native-design-system";
|
|
16
16
|
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
17
17
|
import { useLocalization } from "@umituz/react-native-localization";
|
|
18
18
|
import { usePaywallFeedback } from "../../hooks/feedback/usePaywallFeedback";
|
|
@@ -54,7 +54,7 @@ export const PaywallFeedbackModal: React.FC<PaywallFeedbackModalProps> = React.m
|
|
|
54
54
|
setOtherText,
|
|
55
55
|
selectReason,
|
|
56
56
|
handleSubmit,
|
|
57
|
-
handleSkip,
|
|
57
|
+
handleSkip, // BaseModal's onClose will handle skipping
|
|
58
58
|
canSubmit,
|
|
59
59
|
} = usePaywallFeedback({ onSubmit, onClose });
|
|
60
60
|
|
|
@@ -68,101 +68,107 @@ export const PaywallFeedbackModal: React.FC<PaywallFeedbackModalProps> = React.m
|
|
|
68
68
|
const displaySubmitText = submitText || t("paywall.feedback.submit");
|
|
69
69
|
const displayOtherPlaceholder = otherPlaceholder || t("paywall.feedback.otherPlaceholder");
|
|
70
70
|
|
|
71
|
+
// BaseModal from design system handles animations, safe areas, keyboard avoiding, and overlay backdrop
|
|
71
72
|
return (
|
|
72
|
-
<
|
|
73
|
+
<BaseModal
|
|
73
74
|
visible={visible}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
onClose={handleSkip}
|
|
76
|
+
title={displayTitle}
|
|
77
|
+
subtitle={displaySubtitle}
|
|
77
78
|
>
|
|
78
|
-
<
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
<View style={styles.optionsContainer}>
|
|
95
|
-
{FEEDBACK_OPTION_IDS.map((optionId, index) => {
|
|
96
|
-
const isSelected = selectedReason === optionId;
|
|
97
|
-
const isLast = index === FEEDBACK_OPTION_IDS.length - 1;
|
|
98
|
-
const displayText = t(`paywall.feedback.reasons.${optionId}`);
|
|
99
|
-
|
|
100
|
-
return (
|
|
101
|
-
<View key={optionId}>
|
|
102
|
-
<TouchableOpacity
|
|
103
|
-
style={[
|
|
104
|
-
styles.optionRow,
|
|
105
|
-
isLast && styles.optionRowLast,
|
|
106
|
-
]}
|
|
107
|
-
onPress={() => selectReason(optionId)}
|
|
108
|
-
activeOpacity={0.7}
|
|
109
|
-
>
|
|
110
|
-
<AtomicText
|
|
111
|
-
type="bodyMedium"
|
|
112
|
-
style={[
|
|
113
|
-
styles.optionText,
|
|
114
|
-
isSelected && styles.optionTextSelected,
|
|
115
|
-
]}
|
|
116
|
-
>
|
|
117
|
-
{displayText}
|
|
118
|
-
</AtomicText>
|
|
119
|
-
|
|
120
|
-
<View
|
|
121
|
-
style={[
|
|
122
|
-
styles.radioButton,
|
|
123
|
-
isSelected && styles.radioButtonSelected,
|
|
124
|
-
]}
|
|
125
|
-
>
|
|
126
|
-
{isSelected && (
|
|
127
|
-
<View style={styles.radioButtonInner} />
|
|
128
|
-
)}
|
|
129
|
-
</View>
|
|
130
|
-
</TouchableOpacity>
|
|
131
|
-
|
|
132
|
-
{isSelected && optionId === "other" && (
|
|
133
|
-
<View style={styles.inputContainer}>
|
|
134
|
-
<TextInput
|
|
135
|
-
style={styles.textInput}
|
|
136
|
-
placeholder={displayOtherPlaceholder}
|
|
137
|
-
placeholderTextColor={tokens.colors.textTertiary}
|
|
138
|
-
multiline
|
|
139
|
-
maxLength={200}
|
|
140
|
-
value={otherText}
|
|
141
|
-
onChangeText={setOtherText}
|
|
142
|
-
autoFocus
|
|
143
|
-
/>
|
|
144
|
-
</View>
|
|
145
|
-
)}
|
|
146
|
-
</View>
|
|
147
|
-
);
|
|
148
|
-
})}
|
|
149
|
-
</View>
|
|
79
|
+
<View style={{ paddingHorizontal: tokens.spacing.md, paddingBottom: tokens.spacing.lg }}>
|
|
80
|
+
<View style={[styles.optionsContainer, { backgroundColor: 'transparent', padding: 0 }]}>
|
|
81
|
+
{FEEDBACK_OPTION_IDS.map((optionId, index) => {
|
|
82
|
+
const isSelected = selectedReason === optionId;
|
|
83
|
+
const isOther = optionId === "other";
|
|
84
|
+
const showInput = isSelected && isOther;
|
|
85
|
+
const displayText = t(`paywall.feedback.reasons.${optionId}`);
|
|
86
|
+
|
|
87
|
+
// Dynamic styles for the container
|
|
88
|
+
const containerStyle = {
|
|
89
|
+
marginBottom: tokens.spacing.sm,
|
|
90
|
+
backgroundColor: tokens.colors.surfaceVariant,
|
|
91
|
+
borderRadius: tokens.borderRadius.md,
|
|
92
|
+
overflow: 'hidden' as const, // Ensure children don't bleed out
|
|
93
|
+
};
|
|
150
94
|
|
|
95
|
+
return (
|
|
96
|
+
<View key={optionId} style={containerStyle}>
|
|
151
97
|
<TouchableOpacity
|
|
152
|
-
style={
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
98
|
+
style={{
|
|
99
|
+
borderBottomWidth: showInput ? 1 : 0,
|
|
100
|
+
borderBottomColor: tokens.colors.surface, // Subtle separator
|
|
101
|
+
paddingVertical: tokens.spacing.md,
|
|
102
|
+
paddingHorizontal: tokens.spacing.md,
|
|
103
|
+
flexDirection: 'row',
|
|
104
|
+
alignItems: 'center',
|
|
105
|
+
justifyContent: 'space-between',
|
|
106
|
+
}}
|
|
107
|
+
onPress={() => selectReason(optionId)}
|
|
108
|
+
activeOpacity={0.7}
|
|
156
109
|
>
|
|
157
|
-
<AtomicText
|
|
158
|
-
|
|
110
|
+
<AtomicText
|
|
111
|
+
type="bodyMedium"
|
|
112
|
+
style={[
|
|
113
|
+
styles.optionText,
|
|
114
|
+
isSelected && { color: tokens.colors.primary, fontWeight: '600' },
|
|
115
|
+
]}
|
|
116
|
+
>
|
|
117
|
+
{displayText}
|
|
159
118
|
</AtomicText>
|
|
119
|
+
|
|
120
|
+
<View
|
|
121
|
+
style={[
|
|
122
|
+
styles.radioButton,
|
|
123
|
+
isSelected && styles.radioButtonSelected,
|
|
124
|
+
]}
|
|
125
|
+
>
|
|
126
|
+
{isSelected && (
|
|
127
|
+
<View style={styles.radioButtonInner} />
|
|
128
|
+
)}
|
|
129
|
+
</View>
|
|
160
130
|
</TouchableOpacity>
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
131
|
+
|
|
132
|
+
{showInput && (
|
|
133
|
+
<View style={[styles.inputContainer, { backgroundColor: 'transparent', marginTop: 0, padding: tokens.spacing.sm }]}>
|
|
134
|
+
<TextInput
|
|
135
|
+
style={[
|
|
136
|
+
styles.textInput,
|
|
137
|
+
{
|
|
138
|
+
minHeight: 80,
|
|
139
|
+
textAlignVertical: 'top',
|
|
140
|
+
backgroundColor: tokens.colors.surface, // Slightly different background for input
|
|
141
|
+
borderRadius: tokens.borderRadius.sm,
|
|
142
|
+
padding: tokens.spacing.sm,
|
|
143
|
+
}
|
|
144
|
+
]}
|
|
145
|
+
placeholder={displayOtherPlaceholder}
|
|
146
|
+
placeholderTextColor={tokens.colors.textTertiary}
|
|
147
|
+
multiline
|
|
148
|
+
maxLength={200}
|
|
149
|
+
value={otherText}
|
|
150
|
+
onChangeText={setOtherText}
|
|
151
|
+
autoFocus
|
|
152
|
+
/>
|
|
153
|
+
</View>
|
|
154
|
+
)}
|
|
155
|
+
</View>
|
|
156
|
+
);
|
|
157
|
+
})}
|
|
158
|
+
</View>
|
|
159
|
+
|
|
160
|
+
<TouchableOpacity
|
|
161
|
+
style={[styles.submitButton, { marginTop: tokens.spacing.lg }]}
|
|
162
|
+
onPress={handleSubmit}
|
|
163
|
+
disabled={!canSubmit}
|
|
164
|
+
activeOpacity={0.8}
|
|
165
|
+
>
|
|
166
|
+
<AtomicText type="labelLarge" style={styles.submitText}>
|
|
167
|
+
{displaySubmitText}
|
|
168
|
+
</AtomicText>
|
|
169
|
+
</TouchableOpacity>
|
|
170
|
+
</View>
|
|
171
|
+
</BaseModal>
|
|
166
172
|
);
|
|
167
173
|
});
|
|
168
174
|
|