@umituz/react-native-subscription 2.14.16 → 2.14.17
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.14.
|
|
3
|
+
"version": "2.14.17",
|
|
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",
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Package-driven: all logic handled internally
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { useMemo
|
|
8
|
-
import { Linking } from "react-native";
|
|
7
|
+
import { useMemo } from "react";
|
|
9
8
|
import { useCredits } from "./useCredits";
|
|
9
|
+
import { useSubscriptionStatus } from "./useSubscriptionStatus";
|
|
10
10
|
import { useCustomerInfo } from "../../revenuecat/presentation/hooks/useCustomerInfo";
|
|
11
11
|
import { usePaywallVisibility } from "./usePaywallVisibility";
|
|
12
12
|
import {
|
|
@@ -45,11 +45,15 @@ export const useSubscriptionSettingsConfig = (
|
|
|
45
45
|
|
|
46
46
|
// Internal hooks
|
|
47
47
|
const { credits } = useCredits({ userId, enabled: !!userId });
|
|
48
|
+
const { isPremium: subscriptionActive } = useSubscriptionStatus({
|
|
49
|
+
userId,
|
|
50
|
+
enabled: !!userId,
|
|
51
|
+
});
|
|
48
52
|
const { customerInfo } = useCustomerInfo();
|
|
49
53
|
const { openPaywall } = usePaywallVisibility();
|
|
50
54
|
|
|
51
|
-
// Premium status from
|
|
52
|
-
const isPremium =
|
|
55
|
+
// Premium status from actual RevenueCat subscription
|
|
56
|
+
const isPremium = subscriptionActive;
|
|
53
57
|
|
|
54
58
|
// RevenueCat entitlement info
|
|
55
59
|
const premiumEntitlement = customerInfo?.entitlements.active["premium"];
|
|
@@ -74,14 +78,8 @@ export const useSubscriptionSettingsConfig = (
|
|
|
74
78
|
[expiresAtIso]
|
|
75
79
|
);
|
|
76
80
|
|
|
77
|
-
// Subscription press handler
|
|
78
|
-
const handleSubscriptionPress =
|
|
79
|
-
if (isPremium) {
|
|
80
|
-
Linking.openURL("https://apps.apple.com/account/subscriptions");
|
|
81
|
-
} else {
|
|
82
|
-
openPaywall();
|
|
83
|
-
}
|
|
84
|
-
}, [isPremium, openPaywall]);
|
|
81
|
+
// Subscription press handler - always opens paywall for upgrade
|
|
82
|
+
const handleSubscriptionPress = openPaywall;
|
|
85
83
|
|
|
86
84
|
// Status type
|
|
87
85
|
const statusType: SubscriptionStatusType = isPremium ? "active" : "none";
|
|
@@ -140,7 +138,6 @@ export const useSubscriptionSettingsConfig = (
|
|
|
140
138
|
manageButton: translations.manageButton,
|
|
141
139
|
upgradeButton: translations.upgradeButton,
|
|
142
140
|
},
|
|
143
|
-
onManageSubscription: handleSubscriptionPress,
|
|
144
141
|
onUpgrade: openPaywall,
|
|
145
142
|
},
|
|
146
143
|
}),
|
|
@@ -154,7 +151,6 @@ export const useSubscriptionSettingsConfig = (
|
|
|
154
151
|
daysRemaining,
|
|
155
152
|
willRenew,
|
|
156
153
|
creditsArray,
|
|
157
|
-
handleSubscriptionPress,
|
|
158
154
|
openPaywall,
|
|
159
155
|
]
|
|
160
156
|
);
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* No business logic - pure presentation
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React from "react";
|
|
8
|
-
import { StyleSheet } from "react-native";
|
|
7
|
+
import React, { useMemo } from "react";
|
|
8
|
+
import { StyleSheet, View } from "react-native";
|
|
9
9
|
import { useAppDesignTokens, ScreenLayout } from "@umituz/react-native-design-system";
|
|
10
10
|
import { SubscriptionHeader } from "./components/SubscriptionHeader";
|
|
11
11
|
import { CreditsList } from "./components/CreditsList";
|
|
@@ -59,6 +59,26 @@ export const SubscriptionDetailScreen: React.FC<
|
|
|
59
59
|
> = ({ config }) => {
|
|
60
60
|
const tokens = useAppDesignTokens();
|
|
61
61
|
const showCredits = config.credits && config.credits.length > 0;
|
|
62
|
+
const showUpgradeButton = !config.isPremium && config.onUpgrade;
|
|
63
|
+
|
|
64
|
+
const styles = useMemo(
|
|
65
|
+
() =>
|
|
66
|
+
StyleSheet.create({
|
|
67
|
+
content: {
|
|
68
|
+
flexGrow: 1,
|
|
69
|
+
padding: tokens.spacing.lg,
|
|
70
|
+
gap: tokens.spacing.lg,
|
|
71
|
+
},
|
|
72
|
+
cardsContainer: {
|
|
73
|
+
gap: tokens.spacing.lg,
|
|
74
|
+
},
|
|
75
|
+
spacer: {
|
|
76
|
+
flex: 1,
|
|
77
|
+
minHeight: tokens.spacing.xl,
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
80
|
+
[tokens]
|
|
81
|
+
);
|
|
62
82
|
|
|
63
83
|
return (
|
|
64
84
|
<ScreenLayout
|
|
@@ -75,41 +95,38 @@ export const SubscriptionDetailScreen: React.FC<
|
|
|
75
95
|
) : undefined
|
|
76
96
|
}
|
|
77
97
|
>
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
98
|
+
<View style={styles.cardsContainer}>
|
|
99
|
+
<SubscriptionHeader
|
|
100
|
+
statusType={config.statusType}
|
|
101
|
+
isPremium={config.isPremium}
|
|
102
|
+
isLifetime={config.isLifetime}
|
|
103
|
+
expirationDate={config.expirationDate}
|
|
104
|
+
purchaseDate={config.purchaseDate}
|
|
105
|
+
daysRemaining={config.daysRemaining}
|
|
106
|
+
translations={config.translations}
|
|
107
|
+
/>
|
|
108
|
+
|
|
109
|
+
{showCredits && (
|
|
110
|
+
<CreditsList
|
|
111
|
+
credits={config.credits!}
|
|
112
|
+
title={
|
|
113
|
+
config.translations.usageTitle || config.translations.creditsTitle
|
|
114
|
+
}
|
|
115
|
+
description={config.translations.creditsResetInfo}
|
|
116
|
+
remainingLabel={config.translations.remainingLabel}
|
|
117
|
+
/>
|
|
118
|
+
)}
|
|
119
|
+
</View>
|
|
120
|
+
|
|
121
|
+
<View style={styles.spacer} />
|
|
87
122
|
|
|
88
|
-
{
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
description={config.translations.creditsResetInfo}
|
|
95
|
-
remainingLabel={config.translations.remainingLabel}
|
|
123
|
+
{showUpgradeButton && (
|
|
124
|
+
<SubscriptionActions
|
|
125
|
+
isPremium={config.isPremium}
|
|
126
|
+
upgradeButtonLabel={config.translations.upgradeButton}
|
|
127
|
+
onUpgrade={config.onUpgrade}
|
|
96
128
|
/>
|
|
97
129
|
)}
|
|
98
|
-
|
|
99
|
-
<SubscriptionActions
|
|
100
|
-
isPremium={config.isPremium}
|
|
101
|
-
manageButtonLabel={config.translations.manageButton}
|
|
102
|
-
upgradeButtonLabel={config.translations.upgradeButton}
|
|
103
|
-
onManage={config.onManageSubscription}
|
|
104
|
-
onUpgrade={config.onUpgrade}
|
|
105
|
-
/>
|
|
106
130
|
</ScreenLayout>
|
|
107
131
|
);
|
|
108
132
|
};
|
|
109
|
-
|
|
110
|
-
const styles = StyleSheet.create({
|
|
111
|
-
content: {
|
|
112
|
-
padding: 16,
|
|
113
|
-
gap: 16,
|
|
114
|
-
},
|
|
115
|
-
});
|
|
@@ -1,77 +1,56 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Subscription Actions Component
|
|
3
|
-
* Displays
|
|
3
|
+
* Displays upgrade button for non-premium users
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import React from "react";
|
|
6
|
+
import React, { useMemo } from "react";
|
|
7
7
|
import { View, StyleSheet, TouchableOpacity } from "react-native";
|
|
8
8
|
import { useAppDesignTokens, AtomicText } from "@umituz/react-native-design-system";
|
|
9
9
|
|
|
10
10
|
interface SubscriptionActionsProps {
|
|
11
11
|
isPremium: boolean;
|
|
12
|
-
manageButtonLabel?: string;
|
|
13
12
|
upgradeButtonLabel?: string;
|
|
14
|
-
onManage?: () => void;
|
|
15
13
|
onUpgrade?: () => void;
|
|
16
14
|
}
|
|
17
15
|
|
|
18
16
|
export const SubscriptionActions: React.FC<SubscriptionActionsProps> = ({
|
|
19
17
|
isPremium,
|
|
20
|
-
manageButtonLabel,
|
|
21
18
|
upgradeButtonLabel,
|
|
22
|
-
onManage,
|
|
23
19
|
onUpgrade,
|
|
24
20
|
}) => {
|
|
25
21
|
const tokens = useAppDesignTokens();
|
|
26
22
|
|
|
23
|
+
const styles = useMemo(
|
|
24
|
+
() =>
|
|
25
|
+
StyleSheet.create({
|
|
26
|
+
container: {
|
|
27
|
+
paddingBottom: tokens.spacing.xl,
|
|
28
|
+
},
|
|
29
|
+
primaryButton: {
|
|
30
|
+
paddingVertical: tokens.spacing.md,
|
|
31
|
+
borderRadius: tokens.borderRadius.lg,
|
|
32
|
+
alignItems: "center",
|
|
33
|
+
backgroundColor: tokens.colors.primary,
|
|
34
|
+
},
|
|
35
|
+
buttonText: {
|
|
36
|
+
color: tokens.colors.onPrimary,
|
|
37
|
+
fontWeight: "700",
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
[tokens]
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (isPremium || !onUpgrade || !upgradeButtonLabel) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
27
47
|
return (
|
|
28
48
|
<View style={styles.container}>
|
|
29
|
-
{
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
]}
|
|
35
|
-
onPress={onManage}
|
|
36
|
-
>
|
|
37
|
-
<AtomicText
|
|
38
|
-
type="titleMedium"
|
|
39
|
-
style={{ color: tokens.colors.textPrimary, fontWeight: "600" }}
|
|
40
|
-
>
|
|
41
|
-
{manageButtonLabel}
|
|
42
|
-
</AtomicText>
|
|
43
|
-
</TouchableOpacity>
|
|
44
|
-
)}
|
|
45
|
-
{!isPremium && onUpgrade && upgradeButtonLabel && (
|
|
46
|
-
<TouchableOpacity
|
|
47
|
-
style={[styles.primaryButton, { backgroundColor: tokens.colors.primary }]}
|
|
48
|
-
onPress={onUpgrade}
|
|
49
|
-
>
|
|
50
|
-
<AtomicText
|
|
51
|
-
type="titleMedium"
|
|
52
|
-
style={{ color: tokens.colors.onPrimary, fontWeight: "700" }}
|
|
53
|
-
>
|
|
54
|
-
{upgradeButtonLabel}
|
|
55
|
-
</AtomicText>
|
|
56
|
-
</TouchableOpacity>
|
|
57
|
-
)}
|
|
49
|
+
<TouchableOpacity style={styles.primaryButton} onPress={onUpgrade}>
|
|
50
|
+
<AtomicText type="titleMedium" style={styles.buttonText}>
|
|
51
|
+
{upgradeButtonLabel}
|
|
52
|
+
</AtomicText>
|
|
53
|
+
</TouchableOpacity>
|
|
58
54
|
</View>
|
|
59
55
|
);
|
|
60
56
|
};
|
|
61
|
-
|
|
62
|
-
const styles = StyleSheet.create({
|
|
63
|
-
container: {
|
|
64
|
-
gap: 12,
|
|
65
|
-
paddingBottom: 32,
|
|
66
|
-
},
|
|
67
|
-
primaryButton: {
|
|
68
|
-
paddingVertical: 16,
|
|
69
|
-
borderRadius: 12,
|
|
70
|
-
alignItems: "center",
|
|
71
|
-
},
|
|
72
|
-
secondaryButton: {
|
|
73
|
-
paddingVertical: 16,
|
|
74
|
-
borderRadius: 12,
|
|
75
|
-
alignItems: "center",
|
|
76
|
-
},
|
|
77
|
-
});
|