@umituz/react-native-subscription 2.2.31 → 2.2.33
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.33",
|
|
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",
|
package/src/index.ts
CHANGED
|
@@ -108,6 +108,11 @@ export { SubscriptionPlanCard } from "./presentation/components/paywall/Subscrip
|
|
|
108
108
|
export { PaywallFeaturesList } from "./presentation/components/paywall/PaywallFeaturesList";
|
|
109
109
|
export { PaywallFeatureItem } from "./presentation/components/paywall/PaywallFeatureItem";
|
|
110
110
|
export { PaywallLegalFooter } from "./presentation/components/paywall/PaywallLegalFooter";
|
|
111
|
+
export {
|
|
112
|
+
PaywallModal,
|
|
113
|
+
type PaywallModalProps,
|
|
114
|
+
type PaywallModalStyles,
|
|
115
|
+
} from "./presentation/components/paywall/PaywallModal";
|
|
111
116
|
|
|
112
117
|
// =============================================================================
|
|
113
118
|
// PRESENTATION LAYER - Premium Details Components
|
|
@@ -30,11 +30,11 @@ export const PaywallLegalFooter: React.FC<PaywallLegalFooterProps> = React.memo(
|
|
|
30
30
|
const tokens = useAppDesignTokens();
|
|
31
31
|
|
|
32
32
|
if (__DEV__) {
|
|
33
|
-
console.log("[PaywallLegalFooter] Rendering
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
privacyText,
|
|
37
|
-
|
|
33
|
+
console.log("[PaywallLegalFooter] Rendering links:", {
|
|
34
|
+
privacy: !!privacyUrl,
|
|
35
|
+
terms: !!termsUrl,
|
|
36
|
+
pText: privacyText,
|
|
37
|
+
tText: termsOfServiceText
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -62,32 +62,42 @@ export const PaywallLegalFooter: React.FC<PaywallLegalFooterProps> = React.memo(
|
|
|
62
62
|
</AtomicText>
|
|
63
63
|
|
|
64
64
|
{hasLinks && (
|
|
65
|
-
<View style={styles.
|
|
66
|
-
{
|
|
67
|
-
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
<View style={styles.legalLinksWrapper}>
|
|
66
|
+
<View style={[styles.legalLinksContainer, { borderColor: tokens.colors.border }]}>
|
|
67
|
+
{privacyUrl && (
|
|
68
|
+
<TouchableOpacity
|
|
69
|
+
onPress={handlePrivacyPress}
|
|
70
|
+
activeOpacity={0.6}
|
|
71
|
+
style={styles.linkItem}
|
|
71
72
|
>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
73
|
+
<AtomicText
|
|
74
|
+
type="labelSmall"
|
|
75
|
+
style={[styles.linkText, { color: tokens.colors.textSecondary }]}
|
|
76
|
+
>
|
|
77
|
+
{privacyText}
|
|
78
|
+
</AtomicText>
|
|
79
|
+
</TouchableOpacity>
|
|
80
|
+
)}
|
|
81
|
+
|
|
82
|
+
{privacyUrl && termsUrl && (
|
|
83
|
+
<View style={[styles.dot, { backgroundColor: tokens.colors.border }]} />
|
|
84
|
+
)}
|
|
85
|
+
|
|
86
|
+
{termsUrl && (
|
|
87
|
+
<TouchableOpacity
|
|
88
|
+
onPress={handleTermsPress}
|
|
89
|
+
activeOpacity={0.6}
|
|
90
|
+
style={styles.linkItem}
|
|
86
91
|
>
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
92
|
+
<AtomicText
|
|
93
|
+
type="labelSmall"
|
|
94
|
+
style={[styles.linkText, { color: tokens.colors.textSecondary }]}
|
|
95
|
+
>
|
|
96
|
+
{termsOfServiceText}
|
|
97
|
+
</AtomicText>
|
|
98
|
+
</TouchableOpacity>
|
|
99
|
+
)}
|
|
100
|
+
</View>
|
|
91
101
|
</View>
|
|
92
102
|
)}
|
|
93
103
|
</View>
|
|
@@ -101,28 +111,45 @@ const styles = StyleSheet.create({
|
|
|
101
111
|
container: {
|
|
102
112
|
alignItems: "center",
|
|
103
113
|
paddingHorizontal: 24,
|
|
104
|
-
paddingBottom:
|
|
114
|
+
paddingBottom: 24,
|
|
105
115
|
paddingTop: 8,
|
|
106
116
|
width: "100%",
|
|
107
117
|
},
|
|
108
118
|
termsText: {
|
|
109
119
|
textAlign: "center",
|
|
110
|
-
fontSize:
|
|
111
|
-
lineHeight:
|
|
112
|
-
marginBottom:
|
|
120
|
+
fontSize: 10,
|
|
121
|
+
lineHeight: 14,
|
|
122
|
+
marginBottom: 16,
|
|
123
|
+
opacity: 0.7,
|
|
124
|
+
},
|
|
125
|
+
legalLinksWrapper: {
|
|
126
|
+
width: "100%",
|
|
127
|
+
alignItems: "center",
|
|
113
128
|
},
|
|
114
129
|
legalLinksContainer: {
|
|
115
130
|
flexDirection: "row",
|
|
116
131
|
alignItems: "center",
|
|
117
132
|
justifyContent: "center",
|
|
118
|
-
|
|
119
|
-
|
|
133
|
+
paddingVertical: 8,
|
|
134
|
+
paddingHorizontal: 16,
|
|
135
|
+
borderRadius: 20,
|
|
136
|
+
backgroundColor: "rgba(255, 255, 255, 0.03)",
|
|
137
|
+
borderWidth: 1,
|
|
138
|
+
borderColor: "rgba(255, 255, 255, 0.05)",
|
|
139
|
+
},
|
|
140
|
+
linkItem: {
|
|
141
|
+
paddingVertical: 2,
|
|
120
142
|
},
|
|
121
143
|
linkText: {
|
|
122
|
-
|
|
123
|
-
|
|
144
|
+
fontSize: 11,
|
|
145
|
+
fontWeight: "500",
|
|
146
|
+
letterSpacing: 0.3,
|
|
124
147
|
},
|
|
125
|
-
|
|
126
|
-
|
|
148
|
+
dot: {
|
|
149
|
+
width: 3,
|
|
150
|
+
height: 3,
|
|
151
|
+
borderRadius: 1.5,
|
|
152
|
+
marginHorizontal: 12,
|
|
153
|
+
opacity: 0.3,
|
|
127
154
|
},
|
|
128
155
|
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React, { useEffect } from "react";
|
|
7
|
-
import { View, Modal, StyleSheet, TouchableOpacity } from "react-native";
|
|
7
|
+
import { View, Modal, StyleSheet, TouchableOpacity, Dimensions } from "react-native";
|
|
8
8
|
import { useAppDesignTokens } from "@umituz/react-native-design-system-theme";
|
|
9
9
|
import { useLocalization } from "@umituz/react-native-localization";
|
|
10
10
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
@@ -13,10 +13,34 @@ import { PaywallHeader } from "./PaywallHeader";
|
|
|
13
13
|
import { PaywallTabBar } from "./PaywallTabBar";
|
|
14
14
|
import { CreditsTabContent } from "./CreditsTabContent";
|
|
15
15
|
import { SubscriptionTabContent } from "./SubscriptionTabContent";
|
|
16
|
+
import { ModalLayoutConfig } from "./SubscriptionModalOverlay";
|
|
16
17
|
import type { PaywallTabType } from "../../../domain/entities/paywall/PaywallTab";
|
|
17
18
|
import type { CreditsPackage } from "../../../domain/entities/paywall/CreditsPackage";
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
const { height: SCREEN_HEIGHT } = Dimensions.get("window");
|
|
21
|
+
|
|
22
|
+
export interface PaywallModalStyles {
|
|
23
|
+
headerTopPadding?: number;
|
|
24
|
+
contentHorizontalPadding?: number;
|
|
25
|
+
contentBottomPadding?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const DEFAULT_LAYOUT: ModalLayoutConfig = {
|
|
29
|
+
maxWidth: 480,
|
|
30
|
+
maxHeightPercent: 0.88,
|
|
31
|
+
widthPercent: 0.92,
|
|
32
|
+
borderRadius: 32,
|
|
33
|
+
backdropOpacity: 0.85,
|
|
34
|
+
horizontalPadding: 20,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const DEFAULT_STYLES: PaywallModalStyles = {
|
|
38
|
+
headerTopPadding: 48,
|
|
39
|
+
contentHorizontalPadding: 24,
|
|
40
|
+
contentBottomPadding: 32,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export interface PaywallModalProps {
|
|
20
44
|
visible: boolean;
|
|
21
45
|
onClose: () => void;
|
|
22
46
|
initialTab?: PaywallTabType;
|
|
@@ -36,32 +60,40 @@ interface PaywallModalProps {
|
|
|
36
60
|
privacyText?: string;
|
|
37
61
|
termsOfServiceText?: string;
|
|
38
62
|
restoreButtonText?: string;
|
|
63
|
+
layoutConfig?: ModalLayoutConfig;
|
|
64
|
+
styleConfig?: PaywallModalStyles;
|
|
39
65
|
}
|
|
40
66
|
|
|
41
67
|
export const PaywallModal: React.FC<PaywallModalProps> = React.memo(
|
|
42
|
-
({
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
68
|
+
(props) => {
|
|
69
|
+
const {
|
|
70
|
+
visible,
|
|
71
|
+
onClose,
|
|
72
|
+
initialTab = "credits",
|
|
73
|
+
creditsPackages,
|
|
74
|
+
subscriptionPackages,
|
|
75
|
+
currentCredits,
|
|
76
|
+
requiredCredits,
|
|
77
|
+
onCreditsPurchase,
|
|
78
|
+
onSubscriptionPurchase,
|
|
79
|
+
onRestore,
|
|
80
|
+
subscriptionFeatures = [],
|
|
81
|
+
isLoading = false,
|
|
82
|
+
title,
|
|
83
|
+
subtitle,
|
|
84
|
+
privacyUrl,
|
|
85
|
+
termsUrl,
|
|
86
|
+
privacyText,
|
|
87
|
+
termsOfServiceText,
|
|
88
|
+
restoreButtonText,
|
|
89
|
+
layoutConfig,
|
|
90
|
+
styleConfig,
|
|
91
|
+
} = props;
|
|
92
|
+
|
|
63
93
|
const tokens = useAppDesignTokens();
|
|
64
94
|
const { t } = useLocalization();
|
|
95
|
+
const config = { ...DEFAULT_LAYOUT, ...layoutConfig };
|
|
96
|
+
const styles_ = { ...DEFAULT_STYLES, ...styleConfig };
|
|
65
97
|
|
|
66
98
|
const {
|
|
67
99
|
activeTab,
|
|
@@ -96,16 +128,29 @@ export const PaywallModal: React.FC<PaywallModalProps> = React.memo(
|
|
|
96
128
|
animationType="fade"
|
|
97
129
|
onRequestClose={onClose}
|
|
98
130
|
>
|
|
99
|
-
<View style={styles.overlay}>
|
|
131
|
+
<View style={[styles.overlay, { paddingHorizontal: config.horizontalPadding }]}>
|
|
100
132
|
<TouchableOpacity
|
|
101
|
-
style={
|
|
133
|
+
style={[
|
|
134
|
+
styles.backdrop,
|
|
135
|
+
{ backgroundColor: `rgba(0, 0, 0, ${config.backdropOpacity ?? 0.85})` }
|
|
136
|
+
]}
|
|
102
137
|
activeOpacity={1}
|
|
103
138
|
onPress={onClose}
|
|
104
139
|
/>
|
|
105
140
|
<View
|
|
106
|
-
style={[
|
|
141
|
+
style={[
|
|
142
|
+
styles.content,
|
|
143
|
+
{
|
|
144
|
+
backgroundColor: tokens.colors.surface,
|
|
145
|
+
borderRadius: config.borderRadius ?? 32,
|
|
146
|
+
maxHeight: SCREEN_HEIGHT * (config.maxHeightPercent ?? 0.88),
|
|
147
|
+
height: SCREEN_HEIGHT * (config.maxHeightPercent ?? 0.88), // Explicit height to prevent collapse
|
|
148
|
+
width: `${(config.widthPercent ?? 0.92) * 100}%`,
|
|
149
|
+
maxWidth: config.maxWidth ?? 480,
|
|
150
|
+
}
|
|
151
|
+
]}
|
|
107
152
|
>
|
|
108
|
-
<View style={styles.contentInner}>
|
|
153
|
+
<View style={[styles.contentInner, { paddingTop: styles_.headerTopPadding }]}>
|
|
109
154
|
<PaywallHeader
|
|
110
155
|
title={displayTitle}
|
|
111
156
|
subtitle={displaySubtitle}
|
|
@@ -120,34 +165,36 @@ export const PaywallModal: React.FC<PaywallModalProps> = React.memo(
|
|
|
120
165
|
subscriptionLabel={t("paywall.tabs.subscription", { defaultValue: "Subscription" })}
|
|
121
166
|
/>
|
|
122
167
|
|
|
123
|
-
{
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
168
|
+
<View style={{ flex: 1 }}>
|
|
169
|
+
{activeTab === "credits" ? (
|
|
170
|
+
<CreditsTabContent
|
|
171
|
+
packages={creditsPackages}
|
|
172
|
+
selectedPackageId={selectedCreditsPackageId}
|
|
173
|
+
onSelectPackage={handleCreditsPackageSelect}
|
|
174
|
+
onPurchase={handleCreditsPurchase}
|
|
175
|
+
currentCredits={currentCredits}
|
|
176
|
+
requiredCredits={requiredCredits}
|
|
177
|
+
isLoading={isLoading}
|
|
178
|
+
purchaseButtonText={t("paywall.purchase", { defaultValue: "Purchase" })}
|
|
179
|
+
/>
|
|
180
|
+
) : (
|
|
181
|
+
<SubscriptionTabContent
|
|
182
|
+
packages={subscriptionPackages}
|
|
183
|
+
selectedPackage={selectedSubscriptionPkg}
|
|
184
|
+
onSelectPackage={handleSubscriptionPackageSelect}
|
|
185
|
+
onPurchase={handleSubscriptionPurchase}
|
|
186
|
+
features={subscriptionFeatures}
|
|
187
|
+
isLoading={isLoading}
|
|
188
|
+
purchaseButtonText={t("paywall.subscribe", { defaultValue: "Subscribe" })}
|
|
189
|
+
onRestore={onRestore}
|
|
190
|
+
privacyUrl={privacyUrl}
|
|
191
|
+
termsUrl={termsUrl}
|
|
192
|
+
privacyText={privacyText}
|
|
193
|
+
termsOfServiceText={termsOfServiceText}
|
|
194
|
+
restoreButtonText={restoreButtonText}
|
|
195
|
+
/>
|
|
196
|
+
)}
|
|
197
|
+
</View>
|
|
151
198
|
</View>
|
|
152
199
|
</View>
|
|
153
200
|
</View>
|
|
@@ -163,24 +210,17 @@ const styles = StyleSheet.create({
|
|
|
163
210
|
flex: 1,
|
|
164
211
|
justifyContent: "center",
|
|
165
212
|
alignItems: "center",
|
|
166
|
-
paddingHorizontal: 20,
|
|
167
213
|
},
|
|
168
214
|
backdrop: {
|
|
169
215
|
...StyleSheet.absoluteFillObject,
|
|
170
|
-
backgroundColor: "rgba(0, 0, 0, 0.85)",
|
|
171
216
|
},
|
|
172
217
|
content: {
|
|
173
|
-
borderRadius: 32,
|
|
174
|
-
maxHeight: "88%",
|
|
175
|
-
width: "92%",
|
|
176
|
-
maxWidth: 480,
|
|
177
218
|
overflow: "hidden",
|
|
178
219
|
borderWidth: 1,
|
|
179
220
|
borderColor: "rgba(255, 255, 255, 0.08)",
|
|
180
221
|
},
|
|
181
222
|
contentInner: {
|
|
182
223
|
flex: 1,
|
|
183
|
-
paddingTop: 20,
|
|
184
224
|
paddingBottom: 20,
|
|
185
225
|
},
|
|
186
226
|
});
|