@umituz/react-native-subscription 3.0.1 → 3.1.1

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": "3.0.1",
3
+ "version": "3.1.1",
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",
@@ -75,7 +75,6 @@ export const PaywallScreen: React.FC<PaywallScreenProps> = React.memo((props) =>
75
75
  selectedPlanId,
76
76
  setSelectedPlanId,
77
77
  isProcessing,
78
- handlePurchase,
79
78
  handleRestore,
80
79
  resetState
81
80
  } = usePaywallActions({
@@ -228,14 +227,8 @@ export const PaywallScreen: React.FC<PaywallScreenProps> = React.memo((props) =>
228
227
  translations={translations}
229
228
  legalUrls={legalUrls}
230
229
  isProcessing={isProcessing}
231
- selectedPlanId={selectedPlanId}
232
- packages={packages}
233
- onPurchase={handlePurchase}
234
230
  onRestore={handleRestore}
235
- onLegalUrl={handleLegalUrl}
236
- insets={insets}
237
- tokens={tokens}
238
- styles={styles}
231
+ onLegalClick={handleLegalUrl}
239
232
  />
240
233
  </View>
241
234
  );
@@ -4,10 +4,10 @@
4
4
  */
5
5
 
6
6
  import React from "react";
7
- import type { NavigationProp } from "@react-navigation/native";
7
+ import type { PurchasesPackage } from "react-native-purchases";
8
+ import type { UserCredits } from "../../../credits/core/Credits";
8
9
  import { SplashScreen } from "@umituz/react-native-design-system/molecules";
9
10
  import { OnboardingScreen } from "@umituz/react-native-design-system/onboarding";
10
- import { useSubscriptionFlowStore } from "../useSubscriptionFlow";
11
11
  import type { ManagedSubscriptionFlowProps } from "./ManagedSubscriptionFlow";
12
12
  import { PaywallScreen } from "../../../paywall/components/PaywallScreen";
13
13
  import { PaywallFeedbackScreen } from "./feedback/PaywallFeedbackScreen";
@@ -57,12 +57,12 @@ export const OnboardingState: React.FC<OnboardingStateProps> = ({ config, onComp
57
57
 
58
58
  interface PaywallStateProps {
59
59
  config: ManagedSubscriptionFlowProps["paywall"];
60
- packages: any[];
60
+ packages: PurchasesPackage[];
61
61
  isPremium: boolean;
62
- credits: number | null;
62
+ credits: UserCredits | null;
63
63
  isSyncing: boolean;
64
- onPurchase: (pkgId: string) => Promise<any>;
65
- onRestore: () => Promise<any>;
64
+ onPurchase: (pkg: PurchasesPackage) => Promise<boolean>;
65
+ onRestore: () => Promise<boolean>;
66
66
  onClose: (purchased: boolean) => void;
67
67
  }
68
68
 
@@ -78,9 +78,9 @@ export const PaywallState: React.FC<PaywallStateProps> = ({
78
78
  }) => {
79
79
  const [purchaseSuccessful, setPurchaseSuccessful] = React.useState(false);
80
80
 
81
- const handlePurchase = async (pkgId: string) => {
82
- const result = await onPurchase(pkgId);
83
- if (result?.success) {
81
+ const handlePurchase = async (pkg: PurchasesPackage) => {
82
+ const result = await onPurchase(pkg);
83
+ if (result) {
84
84
  setPurchaseSuccessful(true);
85
85
  }
86
86
  return result;
@@ -91,7 +91,7 @@ const ManagedSubscriptionFlowInner: React.FC<ManagedSubscriptionFlowProps> = ({
91
91
  const status = useSubscriptionFlowStatus();
92
92
 
93
93
  // Premium hooks
94
- const { isPremium, isSyncing, credits, isLoading: isPremiumLoading } = usePremiumStatus();
94
+ const { isPremium, isSyncing, credits } = usePremiumStatus();
95
95
  const { packages } = usePremiumPackages();
96
96
  const { purchasePackage, restorePurchase } = usePremiumActions();
97
97
 
@@ -108,7 +108,7 @@ const ManagedSubscriptionFlowInner: React.FC<ManagedSubscriptionFlowProps> = ({
108
108
  // ========================================================================
109
109
 
110
110
  useEffect(() => {
111
- if (status === SubscriptionFlowStatus.CHECK_PREMIUM && !isPremiumLoading) {
111
+ if (status === SubscriptionFlowStatus.CHECK_PREMIUM && !isSyncing) {
112
112
  const paywallShown = useSubscriptionFlowStore.getState().paywallShown;
113
113
 
114
114
  if (isPremium) {
@@ -119,7 +119,7 @@ const ManagedSubscriptionFlowInner: React.FC<ManagedSubscriptionFlowProps> = ({
119
119
  completePaywall(false);
120
120
  }
121
121
  }
122
- }, [status, isPremium, isPremiumLoading, showPaywall, completePaywall]);
122
+ }, [status, isPremium, isSyncing, showPaywall, completePaywall]);
123
123
 
124
124
  useEffect(() => {
125
125
  if (status === SubscriptionFlowStatus.READY && showFeedback) {
@@ -4,9 +4,8 @@
4
4
  */
5
5
 
6
6
  import React from "react";
7
- import { View, TouchableOpacity, ScrollView } from "react-native";
7
+ import { View, TouchableOpacity } from "react-native";
8
8
  import { AtomicText, AtomicIcon } from "@umituz/react-native-design-system/atoms";
9
- import { useSafeAreaInsets } from "@umituz/react-native-design-system/safe-area";
10
9
  import { FeedbackOption } from "./FeedbackOption";
11
10
  import type { PaywallFeedbackTranslations } from "./PaywallFeedbackScreen.types";
12
11
 
@@ -38,7 +38,7 @@ export const PaywallFeedbackScreen: React.FC<PaywallFeedbackScreenProps> = React
38
38
  canSubmit,
39
39
  } = usePaywallFeedback({ onSubmit, onClose });
40
40
 
41
- const screenStyles = useMemo(() => createScreenStyles(insets), [insets]);
41
+ const screenStyles = useMemo(() => createScreenStyles(), []);
42
42
 
43
43
  return (
44
44
  <View style={[screenStyles.container, { backgroundColor: 'white', opacity: 1 }]}>
@@ -96,7 +96,7 @@ PaywallFeedbackScreen.displayName = "PaywallFeedbackScreen";
96
96
  // STYLES
97
97
  // ============================================================================
98
98
 
99
- const createScreenStyles = (insets: { top: number; bottom: number }) => ({
99
+ const createScreenStyles = () => ({
100
100
  container: {
101
101
  flex: 1,
102
102
  },
@@ -16,7 +16,6 @@ export const SubscriptionFlowProvider: React.FC<{ children: React.ReactNode }> =
16
16
  // Selectors for stable references and only what we need
17
17
  const isInitialized = useSubscriptionFlowStore((state) => state.isInitialized);
18
18
  const isOnboardingComplete = useSubscriptionFlowStore((state) => state.isOnboardingComplete);
19
- const showPostOnboardingPaywall = useSubscriptionFlowStore((state) => state.showPostOnboardingPaywall);
20
19
  const status = useSubscriptionFlowStore((state) => state.status);
21
20
  const setInitialized = useSubscriptionFlowStore((state) => state.setInitialized);
22
21
  const setStatus = useSubscriptionFlowStore((state) => state.setStatus);
@@ -49,7 +48,6 @@ export const SubscriptionFlowProvider: React.FC<{ children: React.ReactNode }> =
49
48
  console.log('[SubscriptionFlowProvider] 🧠 Calculating Status Transition', {
50
49
  isInitialized,
51
50
  isOnboardingComplete,
52
- showPostOnboardingPaywall,
53
51
  currentStatus: status
54
52
  });
55
53
  }
@@ -60,8 +58,9 @@ export const SubscriptionFlowProvider: React.FC<{ children: React.ReactNode }> =
60
58
  nextStatus = SubscriptionFlowStatus.INITIALIZING;
61
59
  } else if (!isOnboardingComplete) {
62
60
  nextStatus = SubscriptionFlowStatus.ONBOARDING;
63
- } else if (showPostOnboardingPaywall) {
64
- nextStatus = SubscriptionFlowStatus.POST_ONBOARDING_PAYWALL;
61
+ } else {
62
+ // Onboarding complete - let ManagedSubscriptionFlow handle CHECK_PREMIUM
63
+ nextStatus = SubscriptionFlowStatus.CHECK_PREMIUM;
65
64
  }
66
65
 
67
66
  if (nextStatus !== status) {
@@ -71,7 +70,6 @@ export const SubscriptionFlowProvider: React.FC<{ children: React.ReactNode }> =
71
70
  }, [
72
71
  isInitialized,
73
72
  isOnboardingComplete,
74
- showPostOnboardingPaywall,
75
73
  status,
76
74
  setStatus
77
75
  ]);
@@ -6,7 +6,7 @@
6
6
  export { useAuthAwarePurchase } from "./domains/subscription/presentation/useAuthAwarePurchase";
7
7
  export { useFeatureGate } from "./domains/subscription/presentation/useFeatureGate";
8
8
  export { usePaywallVisibility, paywallControl } from "./domains/subscription/presentation/usePaywallVisibility";
9
- export { usePremiumStatus } from "./domains/subscription/presentation/usePremiumStatus";
9
+ export { usePremiumStatus, usePremiumStatus as usePremium } from "./domains/subscription/presentation/usePremiumStatus";
10
10
  export { usePremiumPackages } from "./domains/subscription/presentation/usePremiumPackages";
11
11
  export { usePremiumActions } from "./domains/subscription/presentation/usePremiumActions";
12
12
  export { useSubscriptionFlowStore } from "./domains/subscription/presentation/useSubscriptionFlow";
@@ -35,7 +35,3 @@ export type {
35
35
  SettingsFeedbackData,
36
36
  UseSettingsFeedbackSubmitOptions,
37
37
  } from "./presentation/hooks/feedback/useFeedbackSubmit";
38
-
39
- // Paywall Hooks
40
- export { usePaywallOrchestrator } from "./domains/paywall/hooks/usePaywallOrchestrator";
41
- export type { PaywallOrchestratorOptions } from "./domains/paywall/hooks/usePaywallOrchestrator";
@@ -1,166 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- import type { NavigationProp } from "@react-navigation/native";
3
- import type { ImageSourcePropType } from "react-native";
4
- import { usePremiumStatus } from "../../subscription/presentation/usePremiumStatus";
5
- import { usePremiumPackages } from "../../subscription/presentation/usePremiumPackages";
6
- import { usePremiumActions } from "../../subscription/presentation/usePremiumActions";
7
- import { useSubscriptionFlowStore } from "../../subscription/presentation/useSubscriptionFlow";
8
- import { usePaywallVisibility } from "../../subscription/presentation/usePaywallVisibility";
9
- import { PaywallTranslations, PaywallLegalUrls, SubscriptionFeature } from "../entities/types";
10
-
11
- export interface PaywallOrchestratorOptions {
12
- navigation: NavigationProp<any>;
13
- translations: PaywallTranslations;
14
- features: SubscriptionFeature[];
15
- legalUrls: PaywallLegalUrls;
16
- heroImage: ImageSourcePropType;
17
- isNavReady?: boolean;
18
- isLocalizationReady?: boolean;
19
- bestValueIdentifier?: string;
20
- creditsLabel?: string;
21
- /** Disable manual navigation (used when paywall is rendered inline) */
22
- disableNavigation?: boolean;
23
- }
24
-
25
- export function usePaywallOrchestrator({
26
- navigation,
27
- translations,
28
- features,
29
- legalUrls,
30
- heroImage,
31
- isNavReady = true,
32
- isLocalizationReady = true,
33
- bestValueIdentifier = "yearly",
34
- creditsLabel,
35
- disableNavigation = false,
36
- }: PaywallOrchestratorOptions) {
37
- const { isPremium, isSyncing, credits } = usePremiumStatus();
38
- const { packages } = usePremiumPackages();
39
- const { purchasePackage, restorePurchase } = usePremiumActions();
40
-
41
- const isOnboardingComplete = useSubscriptionFlowStore((state) => state.isOnboardingComplete);
42
- const showPostOnboardingPaywall = useSubscriptionFlowStore((state) => state.showPostOnboardingPaywall);
43
- const paywallShown = useSubscriptionFlowStore((state) => state.paywallShown);
44
- const isAuthModalOpen = useSubscriptionFlowStore((state) => state.isAuthModalOpen);
45
- const showFeedback = useSubscriptionFlowStore((state) => state.showFeedback);
46
- const markPaywallShown = useSubscriptionFlowStore((state) => state.markPaywallShown);
47
- const closePostOnboardingPaywall = useSubscriptionFlowStore((state) => state.closePostOnboardingPaywall);
48
- const setShowFeedback = useSubscriptionFlowStore((state) => state.setShowFeedback);
49
-
50
- const { showPaywall, closePaywall } = usePaywallVisibility();
51
- const hasNavigatedRef = useRef(false);
52
-
53
- const handleClose = () => {
54
- closePaywall();
55
- };
56
-
57
- useEffect(() => {
58
- if (!isNavReady || !isLocalizationReady) return;
59
-
60
- const shouldShowPostOnboarding =
61
- isOnboardingComplete &&
62
- showPostOnboardingPaywall &&
63
- !paywallShown &&
64
- !isAuthModalOpen &&
65
- !isPremium;
66
-
67
- const shouldShowManual = showPaywall && !isPremium && !isAuthModalOpen;
68
-
69
- if (shouldShowPostOnboarding || shouldShowManual) {
70
- if (hasNavigatedRef.current) return;
71
- hasNavigatedRef.current = true;
72
-
73
- // Skip navigation if disabled (paywall rendered inline)
74
- if (disableNavigation) {
75
- if (__DEV__) {
76
- console.log('[usePaywallOrchestrator] ⏭️ Skipping navigation (disableNavigation=true)', {
77
- source: shouldShowPostOnboarding ? "onboarding" : "manual",
78
- });
79
- }
80
-
81
- if (shouldShowPostOnboarding) {
82
- markPaywallShown();
83
- }
84
-
85
- if (showPaywall) {
86
- closePaywall();
87
- }
88
-
89
- return;
90
- }
91
-
92
- if (__DEV__) console.log('[usePaywallOrchestrator] 🚀 Navigating to Paywall', {
93
- source: shouldShowPostOnboarding ? "onboarding" : "manual",
94
- packagesCount: packages.length
95
- });
96
-
97
- navigation.navigate("PaywallScreen", {
98
- translations,
99
- legalUrls,
100
- features,
101
- bestValueIdentifier,
102
- creditsLabel,
103
- heroImage,
104
- source: shouldShowPostOnboarding ? "onboarding" : "manual",
105
- packages,
106
- isPremium,
107
- credits,
108
- isSyncing,
109
- onPurchase: purchasePackage,
110
- onRestore: restorePurchase,
111
- onClose: handleClose,
112
- });
113
-
114
- if (shouldShowPostOnboarding) {
115
- markPaywallShown();
116
- }
117
-
118
- if (showPaywall) {
119
- closePaywall();
120
- }
121
- } else {
122
- hasNavigatedRef.current = false;
123
- }
124
- }, [
125
- isNavReady,
126
- isLocalizationReady,
127
- isOnboardingComplete,
128
- showPostOnboardingPaywall,
129
- paywallShown,
130
- isAuthModalOpen,
131
- isPremium,
132
- showPaywall,
133
- navigation,
134
- translations,
135
- legalUrls,
136
- features,
137
- heroImage,
138
- packages,
139
- markPaywallShown,
140
- closePaywall,
141
- bestValueIdentifier,
142
- creditsLabel,
143
- credits,
144
- isSyncing,
145
- purchasePackage,
146
- restorePurchase,
147
- handleClose,
148
- disableNavigation,
149
- ]);
150
-
151
- const completeOnboarding = useSubscriptionFlowStore((state) => state.completeOnboarding);
152
-
153
- return {
154
- flowState: {
155
- isOnboardingComplete,
156
- showPostOnboardingPaywall,
157
- paywallShown,
158
- isAuthModalOpen,
159
- showFeedback
160
- },
161
- markPaywallShown,
162
- closePostOnboardingPaywall,
163
- completeOnboarding,
164
- setShowFeedback
165
- };
166
- }