@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.16",
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, useCallback } from "react";
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 credits
52
- const isPremium = credits !== null;
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 = useCallback(() => {
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
- <SubscriptionHeader
79
- statusType={config.statusType}
80
- isPremium={config.isPremium}
81
- isLifetime={config.isLifetime}
82
- expirationDate={config.expirationDate}
83
- purchaseDate={config.purchaseDate}
84
- daysRemaining={config.daysRemaining}
85
- translations={config.translations}
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
- {showCredits && (
89
- <CreditsList
90
- credits={config.credits!}
91
- title={
92
- config.translations.usageTitle || config.translations.creditsTitle
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 action buttons for subscription management
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
- {isPremium && onManage && manageButtonLabel && (
30
- <TouchableOpacity
31
- style={[
32
- styles.secondaryButton,
33
- { backgroundColor: tokens.colors.surfaceSecondary },
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
- });