@umituz/react-native-subscription 2.2.12 → 2.2.14
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.2.
|
|
3
|
+
"version": "2.2.14",
|
|
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",
|
|
@@ -58,4 +58,4 @@
|
|
|
58
58
|
"README.md",
|
|
59
59
|
"LICENSE"
|
|
60
60
|
]
|
|
61
|
-
}
|
|
61
|
+
}
|
|
@@ -11,33 +11,40 @@ import {
|
|
|
11
11
|
TouchableWithoutFeedback,
|
|
12
12
|
TextInput,
|
|
13
13
|
KeyboardAvoidingView,
|
|
14
|
+
Platform,
|
|
14
15
|
} from "react-native";
|
|
15
|
-
import {
|
|
16
|
-
AtomicText,
|
|
17
|
-
} from "@umituz/react-native-design-system-atoms";
|
|
16
|
+
import { AtomicText } from "@umituz/react-native-design-system-atoms";
|
|
18
17
|
import { useAppDesignTokens } from "@umituz/react-native-design-system-theme";
|
|
19
18
|
import { useLocalization } from "@umituz/react-native-localization";
|
|
20
19
|
import { usePaywallFeedback } from "../../hooks/feedback/usePaywallFeedback";
|
|
21
20
|
import { createPaywallFeedbackStyles } from "./paywallFeedbackStyles";
|
|
22
21
|
|
|
23
22
|
const FEEDBACK_OPTIONS = [
|
|
24
|
-
{ id: "too_expensive",
|
|
25
|
-
{ id: "no_need",
|
|
26
|
-
{ id: "trying_out",
|
|
27
|
-
{ id: "technical_issues",
|
|
28
|
-
{ id: "other",
|
|
23
|
+
{ id: "too_expensive", defaultText: "Too expensive" },
|
|
24
|
+
{ id: "no_need", defaultText: "I don't need premium features" },
|
|
25
|
+
{ id: "trying_out", defaultText: "Just trying it out" },
|
|
26
|
+
{ id: "technical_issues", defaultText: "Technical issues" },
|
|
27
|
+
{ id: "other", defaultText: "Other" },
|
|
29
28
|
];
|
|
30
29
|
|
|
31
30
|
export interface PaywallFeedbackModalProps {
|
|
32
31
|
visible: boolean;
|
|
33
32
|
onClose: () => void;
|
|
34
33
|
onSubmit: (reason: string) => void;
|
|
34
|
+
title?: string;
|
|
35
|
+
subtitle?: string;
|
|
36
|
+
submitText?: string;
|
|
37
|
+
otherPlaceholder?: string;
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
export const PaywallFeedbackModal: React.FC<PaywallFeedbackModalProps> = React.memo(({
|
|
38
41
|
visible,
|
|
39
42
|
onClose,
|
|
40
43
|
onSubmit,
|
|
44
|
+
title,
|
|
45
|
+
subtitle,
|
|
46
|
+
submitText,
|
|
47
|
+
otherPlaceholder,
|
|
41
48
|
}) => {
|
|
42
49
|
const { t } = useLocalization();
|
|
43
50
|
const tokens = useAppDesignTokens();
|
|
@@ -57,6 +64,15 @@ export const PaywallFeedbackModal: React.FC<PaywallFeedbackModalProps> = React.m
|
|
|
57
64
|
[tokens, canSubmit],
|
|
58
65
|
);
|
|
59
66
|
|
|
67
|
+
const displayTitle = title || t("paywall.feedback.title", { defaultValue: "Help us improve" });
|
|
68
|
+
const displaySubtitle = subtitle || t("paywall.feedback.subtitle", {
|
|
69
|
+
defaultValue: "We'd love to know why you decided not to join Premium today."
|
|
70
|
+
});
|
|
71
|
+
const displaySubmitText = submitText || t("paywall.feedback.submit", { defaultValue: "Submit" });
|
|
72
|
+
const displayOtherPlaceholder = otherPlaceholder || t("paywall.feedback.otherPlaceholder", {
|
|
73
|
+
defaultValue: "Tell us more..."
|
|
74
|
+
});
|
|
75
|
+
|
|
60
76
|
return (
|
|
61
77
|
<Modal
|
|
62
78
|
visible={visible}
|
|
@@ -66,15 +82,18 @@ export const PaywallFeedbackModal: React.FC<PaywallFeedbackModalProps> = React.m
|
|
|
66
82
|
>
|
|
67
83
|
<TouchableWithoutFeedback onPress={handleSkip}>
|
|
68
84
|
<View style={styles.overlay}>
|
|
69
|
-
<KeyboardAvoidingView
|
|
85
|
+
<KeyboardAvoidingView
|
|
86
|
+
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
87
|
+
style={styles.keyboardView}
|
|
88
|
+
>
|
|
70
89
|
<TouchableWithoutFeedback>
|
|
71
90
|
<View style={styles.container}>
|
|
72
91
|
<View style={styles.header}>
|
|
73
|
-
<AtomicText style={styles.title}>
|
|
74
|
-
{
|
|
92
|
+
<AtomicText type="headlineMedium" style={styles.title}>
|
|
93
|
+
{displayTitle}
|
|
75
94
|
</AtomicText>
|
|
76
|
-
<AtomicText style={styles.subtitle}>
|
|
77
|
-
{
|
|
95
|
+
<AtomicText type="bodyMedium" style={styles.subtitle}>
|
|
96
|
+
{displaySubtitle}
|
|
78
97
|
</AtomicText>
|
|
79
98
|
</View>
|
|
80
99
|
|
|
@@ -82,34 +101,34 @@ export const PaywallFeedbackModal: React.FC<PaywallFeedbackModalProps> = React.m
|
|
|
82
101
|
{FEEDBACK_OPTIONS.map((option, index) => {
|
|
83
102
|
const isSelected = selectedReason === option.id;
|
|
84
103
|
const isLast = index === FEEDBACK_OPTIONS.length - 1;
|
|
104
|
+
const displayText = t(`paywall.feedback.reasons.${option.id}`, {
|
|
105
|
+
defaultValue: option.defaultText
|
|
106
|
+
});
|
|
85
107
|
|
|
86
108
|
return (
|
|
87
109
|
<View key={option.id}>
|
|
88
110
|
<TouchableOpacity
|
|
89
111
|
style={[
|
|
90
112
|
styles.optionRow,
|
|
91
|
-
isLast
|
|
113
|
+
isLast && styles.optionRowLast,
|
|
92
114
|
]}
|
|
93
115
|
onPress={() => selectReason(option.id)}
|
|
94
|
-
activeOpacity={0.
|
|
116
|
+
activeOpacity={0.7}
|
|
95
117
|
>
|
|
96
118
|
<AtomicText
|
|
119
|
+
type="bodyMedium"
|
|
97
120
|
style={[
|
|
98
121
|
styles.optionText,
|
|
99
|
-
isSelected
|
|
100
|
-
? styles.optionTextSelected
|
|
101
|
-
: undefined,
|
|
122
|
+
isSelected && styles.optionTextSelected,
|
|
102
123
|
]}
|
|
103
124
|
>
|
|
104
|
-
{
|
|
125
|
+
{displayText}
|
|
105
126
|
</AtomicText>
|
|
106
127
|
|
|
107
128
|
<View
|
|
108
129
|
style={[
|
|
109
130
|
styles.radioButton,
|
|
110
|
-
isSelected
|
|
111
|
-
? styles.radioButtonSelected
|
|
112
|
-
: undefined,
|
|
131
|
+
isSelected && styles.radioButtonSelected,
|
|
113
132
|
]}
|
|
114
133
|
>
|
|
115
134
|
{isSelected && (
|
|
@@ -122,7 +141,7 @@ export const PaywallFeedbackModal: React.FC<PaywallFeedbackModalProps> = React.m
|
|
|
122
141
|
<View style={styles.inputContainer}>
|
|
123
142
|
<TextInput
|
|
124
143
|
style={styles.textInput}
|
|
125
|
-
placeholder={
|
|
144
|
+
placeholder={displayOtherPlaceholder}
|
|
126
145
|
placeholderTextColor={tokens.colors.textTertiary}
|
|
127
146
|
multiline
|
|
128
147
|
maxLength={200}
|
|
@@ -137,18 +156,16 @@ export const PaywallFeedbackModal: React.FC<PaywallFeedbackModalProps> = React.m
|
|
|
137
156
|
})}
|
|
138
157
|
</View>
|
|
139
158
|
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
</TouchableOpacity>
|
|
151
|
-
</View>
|
|
159
|
+
<TouchableOpacity
|
|
160
|
+
style={styles.submitButton}
|
|
161
|
+
onPress={handleSubmit}
|
|
162
|
+
disabled={!canSubmit}
|
|
163
|
+
activeOpacity={0.8}
|
|
164
|
+
>
|
|
165
|
+
<AtomicText type="labelLarge" style={styles.submitText}>
|
|
166
|
+
{displaySubmitText}
|
|
167
|
+
</AtomicText>
|
|
168
|
+
</TouchableOpacity>
|
|
152
169
|
</View>
|
|
153
170
|
</TouchableWithoutFeedback>
|
|
154
171
|
</KeyboardAvoidingView>
|
|
@@ -13,10 +13,10 @@ export const createPaywallFeedbackStyles = (
|
|
|
13
13
|
StyleSheet.create({
|
|
14
14
|
overlay: {
|
|
15
15
|
flex: 1,
|
|
16
|
-
backgroundColor: "rgba(0, 0, 0, 0.
|
|
16
|
+
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
|
17
17
|
justifyContent: "center",
|
|
18
18
|
alignItems: "center",
|
|
19
|
-
padding:
|
|
19
|
+
padding: 20,
|
|
20
20
|
},
|
|
21
21
|
keyboardView: {
|
|
22
22
|
width: "100%",
|
|
@@ -24,41 +24,42 @@ export const createPaywallFeedbackStyles = (
|
|
|
24
24
|
},
|
|
25
25
|
container: {
|
|
26
26
|
width: "100%",
|
|
27
|
-
maxWidth:
|
|
27
|
+
maxWidth: 360,
|
|
28
28
|
backgroundColor: tokens.colors.surface,
|
|
29
29
|
borderRadius: 24,
|
|
30
|
-
overflow: "hidden",
|
|
31
30
|
padding: 24,
|
|
31
|
+
shadowColor: "#000",
|
|
32
|
+
shadowOffset: { width: 0, height: 8 },
|
|
33
|
+
shadowOpacity: 0.25,
|
|
34
|
+
shadowRadius: 16,
|
|
35
|
+
elevation: 8,
|
|
32
36
|
},
|
|
33
37
|
header: {
|
|
34
38
|
alignItems: "center",
|
|
35
|
-
marginBottom:
|
|
39
|
+
marginBottom: 20,
|
|
36
40
|
},
|
|
37
41
|
title: {
|
|
38
|
-
fontSize: 20,
|
|
39
|
-
fontWeight: "700",
|
|
40
42
|
color: tokens.colors.textPrimary,
|
|
41
43
|
marginBottom: 8,
|
|
42
44
|
textAlign: "center",
|
|
43
45
|
},
|
|
44
46
|
subtitle: {
|
|
45
|
-
fontSize: 14,
|
|
46
47
|
color: tokens.colors.textSecondary,
|
|
47
48
|
textAlign: "center",
|
|
48
|
-
lineHeight:
|
|
49
|
+
lineHeight: 22,
|
|
49
50
|
},
|
|
50
51
|
optionsContainer: {
|
|
51
|
-
gap: 0,
|
|
52
|
-
marginBottom: 24,
|
|
53
52
|
backgroundColor: tokens.colors.surfaceSecondary,
|
|
54
53
|
borderRadius: 16,
|
|
55
54
|
overflow: "hidden",
|
|
55
|
+
marginBottom: 20,
|
|
56
56
|
},
|
|
57
57
|
optionRow: {
|
|
58
58
|
flexDirection: "row",
|
|
59
59
|
alignItems: "center",
|
|
60
60
|
justifyContent: "space-between",
|
|
61
|
-
|
|
61
|
+
paddingVertical: 16,
|
|
62
|
+
paddingHorizontal: 16,
|
|
62
63
|
borderBottomWidth: 1,
|
|
63
64
|
borderBottomColor: tokens.colors.border,
|
|
64
65
|
},
|
|
@@ -66,59 +67,58 @@ export const createPaywallFeedbackStyles = (
|
|
|
66
67
|
borderBottomWidth: 0,
|
|
67
68
|
},
|
|
68
69
|
optionText: {
|
|
69
|
-
fontSize: 15,
|
|
70
70
|
color: tokens.colors.textSecondary,
|
|
71
71
|
flex: 1,
|
|
72
|
-
marginRight:
|
|
72
|
+
marginRight: 12,
|
|
73
73
|
},
|
|
74
74
|
optionTextSelected: {
|
|
75
75
|
color: tokens.colors.textPrimary,
|
|
76
76
|
fontWeight: "600",
|
|
77
77
|
},
|
|
78
78
|
radioButton: {
|
|
79
|
-
width:
|
|
80
|
-
height:
|
|
81
|
-
borderRadius:
|
|
79
|
+
width: 22,
|
|
80
|
+
height: 22,
|
|
81
|
+
borderRadius: 11,
|
|
82
82
|
borderWidth: 2,
|
|
83
83
|
borderColor: tokens.colors.border,
|
|
84
84
|
justifyContent: "center",
|
|
85
85
|
alignItems: "center",
|
|
86
|
+
backgroundColor: "transparent",
|
|
86
87
|
},
|
|
87
88
|
radioButtonSelected: {
|
|
88
89
|
borderColor: tokens.colors.primary,
|
|
90
|
+
borderWidth: 2,
|
|
89
91
|
},
|
|
90
92
|
radioButtonInner: {
|
|
91
|
-
width:
|
|
92
|
-
height:
|
|
93
|
-
borderRadius:
|
|
93
|
+
width: 12,
|
|
94
|
+
height: 12,
|
|
95
|
+
borderRadius: 6,
|
|
94
96
|
backgroundColor: tokens.colors.primary,
|
|
95
97
|
},
|
|
96
98
|
inputContainer: {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
paddingHorizontal: 16,
|
|
100
|
+
paddingBottom: 16,
|
|
99
101
|
},
|
|
100
102
|
textInput: {
|
|
101
103
|
backgroundColor: tokens.colors.surface,
|
|
102
104
|
borderRadius: 12,
|
|
105
|
+
borderWidth: 1,
|
|
106
|
+
borderColor: tokens.colors.border,
|
|
103
107
|
padding: 12,
|
|
104
|
-
fontSize:
|
|
108
|
+
fontSize: 15,
|
|
105
109
|
color: tokens.colors.textPrimary,
|
|
106
110
|
minHeight: 80,
|
|
107
111
|
textAlignVertical: "top",
|
|
108
112
|
},
|
|
109
|
-
footer: {
|
|
110
|
-
gap: 12,
|
|
111
|
-
},
|
|
112
113
|
submitButton: {
|
|
113
114
|
backgroundColor: canSubmit ? tokens.colors.primary : tokens.colors.surfaceSecondary,
|
|
114
|
-
borderRadius:
|
|
115
|
-
paddingVertical:
|
|
115
|
+
borderRadius: 14,
|
|
116
|
+
paddingVertical: 16,
|
|
116
117
|
alignItems: "center",
|
|
117
|
-
opacity: canSubmit ? 1 : 0.
|
|
118
|
+
opacity: canSubmit ? 1 : 0.6,
|
|
118
119
|
},
|
|
119
120
|
submitText: {
|
|
120
121
|
color: canSubmit ? tokens.colors.onPrimary : tokens.colors.textDisabled,
|
|
121
122
|
fontWeight: "600",
|
|
122
|
-
fontSize: 16,
|
|
123
123
|
},
|
|
124
124
|
});
|