@umituz/react-native-subscription 2.2.29 → 2.2.30
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.30",
|
|
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
|
@@ -94,10 +94,15 @@ export {
|
|
|
94
94
|
export {
|
|
95
95
|
SubscriptionModal,
|
|
96
96
|
type SubscriptionModalProps,
|
|
97
|
+
type SubscriptionModalStyles,
|
|
97
98
|
} from "./presentation/components/paywall/SubscriptionModal";
|
|
98
99
|
|
|
99
100
|
export { SubscriptionModalHeader } from "./presentation/components/paywall/SubscriptionModalHeader";
|
|
100
|
-
export {
|
|
101
|
+
export {
|
|
102
|
+
SubscriptionModalOverlay,
|
|
103
|
+
type SubscriptionModalVariant,
|
|
104
|
+
type ModalLayoutConfig,
|
|
105
|
+
} from "./presentation/components/paywall/SubscriptionModalOverlay";
|
|
101
106
|
|
|
102
107
|
export { SubscriptionPlanCard } from "./presentation/components/paywall/SubscriptionPlanCard";
|
|
103
108
|
export { PaywallFeaturesList } from "./presentation/components/paywall/PaywallFeaturesList";
|
|
@@ -9,12 +9,22 @@ import { useAppDesignTokens } from "@umituz/react-native-design-system-theme";
|
|
|
9
9
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
10
10
|
|
|
11
11
|
import { SubscriptionModalHeader } from "./SubscriptionModalHeader";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
SubscriptionModalOverlay,
|
|
14
|
+
SubscriptionModalVariant,
|
|
15
|
+
ModalLayoutConfig,
|
|
16
|
+
} from "./SubscriptionModalOverlay";
|
|
13
17
|
import { PaywallFeaturesList } from "./PaywallFeaturesList";
|
|
14
18
|
import { SubscriptionPackageList } from "./SubscriptionPackageList";
|
|
15
19
|
import { SubscriptionFooter } from "./SubscriptionFooter";
|
|
16
20
|
import { useSubscriptionModal } from "../../hooks/useSubscriptionModal";
|
|
17
21
|
|
|
22
|
+
export interface SubscriptionModalStyles {
|
|
23
|
+
headerTopPadding?: number;
|
|
24
|
+
contentHorizontalPadding?: number;
|
|
25
|
+
contentBottomPadding?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
export interface SubscriptionModalProps {
|
|
19
29
|
visible: boolean;
|
|
20
30
|
onClose: () => void;
|
|
@@ -36,9 +46,16 @@ export interface SubscriptionModalProps {
|
|
|
36
46
|
termsOfServiceText?: string;
|
|
37
47
|
showRestoreButton?: boolean;
|
|
38
48
|
variant?: SubscriptionModalVariant;
|
|
39
|
-
|
|
49
|
+
layoutConfig?: ModalLayoutConfig;
|
|
50
|
+
styleConfig?: SubscriptionModalStyles;
|
|
40
51
|
}
|
|
41
52
|
|
|
53
|
+
const DEFAULT_STYLES: SubscriptionModalStyles = {
|
|
54
|
+
headerTopPadding: 48,
|
|
55
|
+
contentHorizontalPadding: 24,
|
|
56
|
+
contentBottomPadding: 32,
|
|
57
|
+
};
|
|
58
|
+
|
|
42
59
|
export const SubscriptionModal: React.FC<SubscriptionModalProps> = React.memo((props) => {
|
|
43
60
|
const {
|
|
44
61
|
visible,
|
|
@@ -61,9 +78,13 @@ export const SubscriptionModal: React.FC<SubscriptionModalProps> = React.memo((p
|
|
|
61
78
|
termsOfServiceText,
|
|
62
79
|
showRestoreButton = true,
|
|
63
80
|
variant = "bottom-sheet",
|
|
81
|
+
layoutConfig,
|
|
82
|
+
styleConfig,
|
|
64
83
|
} = props;
|
|
65
84
|
|
|
66
85
|
const tokens = useAppDesignTokens();
|
|
86
|
+
const styles_ = { ...DEFAULT_STYLES, ...styleConfig };
|
|
87
|
+
|
|
67
88
|
const {
|
|
68
89
|
selectedPkg,
|
|
69
90
|
setSelectedPkg,
|
|
@@ -76,19 +97,47 @@ export const SubscriptionModal: React.FC<SubscriptionModalProps> = React.memo((p
|
|
|
76
97
|
onClose,
|
|
77
98
|
});
|
|
78
99
|
|
|
100
|
+
if (__DEV__) {
|
|
101
|
+
console.log("[SubscriptionModal] Rendering", {
|
|
102
|
+
visible,
|
|
103
|
+
variant,
|
|
104
|
+
packagesCount: packages.length,
|
|
105
|
+
featuresCount: features.length,
|
|
106
|
+
isLoading,
|
|
107
|
+
layoutConfig,
|
|
108
|
+
styleConfig: styles_,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
79
112
|
if (!visible) return null;
|
|
80
113
|
|
|
81
|
-
const
|
|
82
|
-
const
|
|
114
|
+
const isFullscreen = variant === "fullscreen";
|
|
115
|
+
const containerPaddingTop = isFullscreen ? styles_.headerTopPadding : 0;
|
|
83
116
|
|
|
84
117
|
return (
|
|
85
|
-
<SubscriptionModalOverlay
|
|
86
|
-
|
|
87
|
-
|
|
118
|
+
<SubscriptionModalOverlay
|
|
119
|
+
visible={visible}
|
|
120
|
+
onClose={onClose}
|
|
121
|
+
variant={variant}
|
|
122
|
+
layoutConfig={layoutConfig}
|
|
123
|
+
>
|
|
124
|
+
<View style={[styles.container, { paddingTop: containerPaddingTop }]}>
|
|
125
|
+
<SubscriptionModalHeader
|
|
126
|
+
title={title}
|
|
127
|
+
subtitle={subtitle}
|
|
128
|
+
onClose={onClose}
|
|
129
|
+
variant={variant}
|
|
130
|
+
/>
|
|
88
131
|
|
|
89
132
|
<ScrollView
|
|
90
133
|
style={styles.scrollView}
|
|
91
|
-
contentContainerStyle={
|
|
134
|
+
contentContainerStyle={[
|
|
135
|
+
styles.scrollContent,
|
|
136
|
+
{
|
|
137
|
+
paddingHorizontal: styles_.contentHorizontalPadding,
|
|
138
|
+
paddingBottom: styles_.contentBottomPadding,
|
|
139
|
+
}
|
|
140
|
+
]}
|
|
92
141
|
showsVerticalScrollIndicator={false}
|
|
93
142
|
bounces={false}
|
|
94
143
|
>
|
|
@@ -124,7 +173,7 @@ export const SubscriptionModal: React.FC<SubscriptionModalProps> = React.memo((p
|
|
|
124
173
|
onPurchase={handlePurchase}
|
|
125
174
|
onRestore={handleRestore}
|
|
126
175
|
/>
|
|
127
|
-
</
|
|
176
|
+
</View>
|
|
128
177
|
</SubscriptionModalOverlay>
|
|
129
178
|
);
|
|
130
179
|
});
|
|
@@ -136,19 +185,11 @@ const styles = StyleSheet.create({
|
|
|
136
185
|
flex: 1,
|
|
137
186
|
width: "100%",
|
|
138
187
|
},
|
|
139
|
-
fullscreenContainer: {
|
|
140
|
-
flex: 1,
|
|
141
|
-
width: "100%",
|
|
142
|
-
paddingTop: 20,
|
|
143
|
-
paddingBottom: 20,
|
|
144
|
-
},
|
|
145
188
|
scrollView: {
|
|
146
189
|
flex: 1,
|
|
147
190
|
width: "100%",
|
|
148
191
|
},
|
|
149
192
|
scrollContent: {
|
|
150
|
-
paddingHorizontal: 24,
|
|
151
|
-
paddingBottom: 32,
|
|
152
193
|
flexGrow: 1,
|
|
153
194
|
},
|
|
154
195
|
featuresSection: {
|
|
@@ -23,13 +23,11 @@ export const SubscriptionModalHeader: React.FC<SubscriptionModalHeaderProps> = (
|
|
|
23
23
|
const tokens = useAppDesignTokens();
|
|
24
24
|
|
|
25
25
|
if (__DEV__) {
|
|
26
|
-
console.log("[SubscriptionModalHeader] Rendering title
|
|
26
|
+
console.log("[SubscriptionModalHeader] Rendering", { title, variant, hasSubtitle: !!subtitle });
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const headerStyle = variant === "fullscreen" ? styles.headerFullscreen : styles.header;
|
|
30
|
-
|
|
31
29
|
return (
|
|
32
|
-
<View style={
|
|
30
|
+
<View style={styles.header}>
|
|
33
31
|
<TouchableOpacity
|
|
34
32
|
style={styles.closeButton}
|
|
35
33
|
onPress={onClose}
|
|
@@ -61,13 +59,7 @@ const styles = StyleSheet.create({
|
|
|
61
59
|
header: {
|
|
62
60
|
alignItems: "center",
|
|
63
61
|
paddingHorizontal: 24,
|
|
64
|
-
paddingTop:
|
|
65
|
-
paddingBottom: 16,
|
|
66
|
-
},
|
|
67
|
-
headerFullscreen: {
|
|
68
|
-
alignItems: "center",
|
|
69
|
-
paddingHorizontal: 24,
|
|
70
|
-
paddingTop: 48,
|
|
62
|
+
paddingTop: 16,
|
|
71
63
|
paddingBottom: 16,
|
|
72
64
|
},
|
|
73
65
|
closeButton: {
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
StyleSheet,
|
|
11
11
|
TouchableOpacity,
|
|
12
12
|
Dimensions,
|
|
13
|
-
Platform
|
|
13
|
+
Platform,
|
|
14
|
+
ViewStyle,
|
|
14
15
|
} from "react-native";
|
|
15
16
|
import { useAppDesignTokens } from "@umituz/react-native-design-system-theme";
|
|
16
17
|
|
|
@@ -18,11 +19,30 @@ const { height: SCREEN_HEIGHT, width: SCREEN_WIDTH } = Dimensions.get("window");
|
|
|
18
19
|
|
|
19
20
|
export type SubscriptionModalVariant = "bottom-sheet" | "fullscreen" | "dialog";
|
|
20
21
|
|
|
22
|
+
export interface ModalLayoutConfig {
|
|
23
|
+
maxWidth?: number;
|
|
24
|
+
maxHeightPercent?: number;
|
|
25
|
+
widthPercent?: number;
|
|
26
|
+
borderRadius?: number;
|
|
27
|
+
backdropOpacity?: number;
|
|
28
|
+
horizontalPadding?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const DEFAULT_LAYOUT: ModalLayoutConfig = {
|
|
32
|
+
maxWidth: 480,
|
|
33
|
+
maxHeightPercent: 0.88,
|
|
34
|
+
widthPercent: 0.92,
|
|
35
|
+
borderRadius: 32,
|
|
36
|
+
backdropOpacity: 0.85,
|
|
37
|
+
horizontalPadding: 20,
|
|
38
|
+
};
|
|
39
|
+
|
|
21
40
|
interface SubscriptionModalOverlayProps {
|
|
22
41
|
visible: boolean;
|
|
23
42
|
onClose: () => void;
|
|
24
43
|
children: React.ReactNode;
|
|
25
44
|
variant: SubscriptionModalVariant;
|
|
45
|
+
layoutConfig?: ModalLayoutConfig;
|
|
26
46
|
}
|
|
27
47
|
|
|
28
48
|
export const SubscriptionModalOverlay: React.FC<SubscriptionModalOverlayProps> = ({
|
|
@@ -30,15 +50,42 @@ export const SubscriptionModalOverlay: React.FC<SubscriptionModalOverlayProps> =
|
|
|
30
50
|
onClose,
|
|
31
51
|
children,
|
|
32
52
|
variant,
|
|
53
|
+
layoutConfig,
|
|
33
54
|
}) => {
|
|
34
55
|
const tokens = useAppDesignTokens();
|
|
56
|
+
const config = { ...DEFAULT_LAYOUT, ...layoutConfig };
|
|
35
57
|
|
|
36
58
|
if (__DEV__) {
|
|
37
|
-
console.log("[SubscriptionModalOverlay] Rendering
|
|
59
|
+
console.log("[SubscriptionModalOverlay] Rendering", {
|
|
60
|
+
variant,
|
|
61
|
+
visible,
|
|
62
|
+
layoutConfig: config,
|
|
63
|
+
});
|
|
38
64
|
}
|
|
39
65
|
|
|
40
66
|
const isFullScreen = variant === "fullscreen";
|
|
41
67
|
|
|
68
|
+
const getFullscreenContentStyle = (): ViewStyle => ({
|
|
69
|
+
width: Math.min(SCREEN_WIDTH * (config.widthPercent ?? 0.92), config.maxWidth ?? 480),
|
|
70
|
+
maxHeight: SCREEN_HEIGHT * (config.maxHeightPercent ?? 0.88),
|
|
71
|
+
borderRadius: config.borderRadius ?? 32,
|
|
72
|
+
overflow: "hidden",
|
|
73
|
+
borderWidth: 1,
|
|
74
|
+
borderColor: "rgba(255, 255, 255, 0.08)",
|
|
75
|
+
backgroundColor: tokens.colors.surface,
|
|
76
|
+
...Platform.select({
|
|
77
|
+
ios: {
|
|
78
|
+
shadowColor: "#000",
|
|
79
|
+
shadowOffset: { width: 0, height: 16 },
|
|
80
|
+
shadowOpacity: 0.5,
|
|
81
|
+
shadowRadius: 32,
|
|
82
|
+
},
|
|
83
|
+
android: {
|
|
84
|
+
elevation: 16,
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
|
|
42
89
|
if (isFullScreen) {
|
|
43
90
|
return (
|
|
44
91
|
<Modal
|
|
@@ -47,13 +94,16 @@ export const SubscriptionModalOverlay: React.FC<SubscriptionModalOverlayProps> =
|
|
|
47
94
|
animationType="fade"
|
|
48
95
|
onRequestClose={onClose}
|
|
49
96
|
>
|
|
50
|
-
<View style={styles.fullscreenOverlay}>
|
|
97
|
+
<View style={[styles.fullscreenOverlay, { paddingHorizontal: config.horizontalPadding }]}>
|
|
51
98
|
<TouchableOpacity
|
|
52
|
-
style={
|
|
99
|
+
style={[
|
|
100
|
+
styles.fullscreenBackdrop,
|
|
101
|
+
{ backgroundColor: `rgba(0, 0, 0, ${config.backdropOpacity ?? 0.85})` }
|
|
102
|
+
]}
|
|
53
103
|
activeOpacity={1}
|
|
54
104
|
onPress={onClose}
|
|
55
105
|
/>
|
|
56
|
-
<View style={
|
|
106
|
+
<View style={getFullscreenContentStyle()}>
|
|
57
107
|
{children}
|
|
58
108
|
</View>
|
|
59
109
|
</View>
|
|
@@ -104,30 +154,9 @@ const styles = StyleSheet.create({
|
|
|
104
154
|
flex: 1,
|
|
105
155
|
justifyContent: "center",
|
|
106
156
|
alignItems: "center",
|
|
107
|
-
paddingHorizontal: 20,
|
|
108
157
|
},
|
|
109
158
|
fullscreenBackdrop: {
|
|
110
159
|
...StyleSheet.absoluteFillObject,
|
|
111
|
-
backgroundColor: "rgba(0, 0, 0, 0.85)",
|
|
112
|
-
},
|
|
113
|
-
fullscreenContent: {
|
|
114
|
-
width: Math.min(SCREEN_WIDTH * 0.92, 480),
|
|
115
|
-
maxHeight: SCREEN_HEIGHT * 0.88,
|
|
116
|
-
borderRadius: 32,
|
|
117
|
-
overflow: "hidden",
|
|
118
|
-
borderWidth: 1,
|
|
119
|
-
borderColor: "rgba(255, 255, 255, 0.08)",
|
|
120
|
-
...Platform.select({
|
|
121
|
-
ios: {
|
|
122
|
-
shadowColor: "#000",
|
|
123
|
-
shadowOffset: { width: 0, height: 16 },
|
|
124
|
-
shadowOpacity: 0.5,
|
|
125
|
-
shadowRadius: 32,
|
|
126
|
-
},
|
|
127
|
-
android: {
|
|
128
|
-
elevation: 16,
|
|
129
|
-
},
|
|
130
|
-
}),
|
|
131
160
|
},
|
|
132
161
|
bottomSheet: {
|
|
133
162
|
borderTopLeftRadius: 32,
|