@umituz/react-native-subscription 2.2.13 → 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.13",
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",
@@ -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", labelKey: "paywall.feedback.reasons.tooExpensive" },
25
- { id: "no_need", labelKey: "paywall.feedback.reasons.noNeed" },
26
- { id: "trying_out", labelKey: "paywall.feedback.reasons.tryingOut" },
27
- { id: "technical_issues", labelKey: "paywall.feedback.reasons.technicalIssues" },
28
- { id: "other", labelKey: "paywall.feedback.reasons.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 behavior="padding" style={styles.keyboardView}>
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
- {t("paywall.feedback.title", { defaultValue: "Help us improve" })}
92
+ <AtomicText type="headlineMedium" style={styles.title}>
93
+ {displayTitle}
75
94
  </AtomicText>
76
- <AtomicText style={styles.subtitle}>
77
- {t("paywall.feedback.subtitle", { defaultValue: "We'd love to know why you decided not to join Premium today." })}
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 ? styles.optionRowLast : undefined,
113
+ isLast && styles.optionRowLast,
92
114
  ]}
93
115
  onPress={() => selectReason(option.id)}
94
- activeOpacity={0.6}
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
- {t(option.labelKey, { defaultValue: option.id })}
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={t("paywall.feedback.otherPlaceholder", { defaultValue: "Tell us more..." })}
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
- <View style={styles.footer}>
141
- <TouchableOpacity
142
- style={styles.submitButton}
143
- onPress={handleSubmit}
144
- disabled={!canSubmit}
145
- activeOpacity={0.8}
146
- >
147
- <AtomicText style={styles.submitText}>
148
- {t("paywall.feedback.submit", { defaultValue: "Submit" })}
149
- </AtomicText>
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.5)",
16
+ backgroundColor: "rgba(0, 0, 0, 0.6)",
17
17
  justifyContent: "center",
18
18
  alignItems: "center",
19
- padding: 24,
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: 340,
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: 24,
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: 20,
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
- padding: 16,
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: 16,
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: 20,
80
- height: 20,
81
- borderRadius: 10,
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: 10,
92
- height: 10,
93
- borderRadius: 5,
93
+ width: 12,
94
+ height: 12,
95
+ borderRadius: 6,
94
96
  backgroundColor: tokens.colors.primary,
95
97
  },
96
98
  inputContainer: {
97
- padding: 16,
98
- paddingTop: 0,
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: 14,
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: 12,
115
- paddingVertical: 14,
115
+ borderRadius: 14,
116
+ paddingVertical: 16,
116
117
  alignItems: "center",
117
- opacity: canSubmit ? 1 : 0.7,
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
  });