@umituz/react-native-subscription 2.40.14 → 2.40.16

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.40.14",
3
+ "version": "2.40.16",
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",
@@ -1,15 +1,11 @@
1
1
  /**
2
- * Subscription Flow Hook
2
+ * Subscription Flow Store
3
3
  * Manages the high-level application flow: Splash -> Onboarding -> Paywall -> Main App.
4
- * Centralizing this in the library allows for minimal boilerplate in the main application's navigator.
4
+ * Uses @umituz/react-native-design-system's storage utility for standardized persistence.
5
5
  */
6
6
 
7
- import { useState, useEffect, useCallback } from "react";
8
7
  import { DeviceEventEmitter } from "react-native";
9
- import AsyncStorage from "@react-native-async-storage/async-storage";
10
-
11
- const PAYWALL_SHOWN_KEY = "post_onboarding_paywall_shown";
12
- const ONBOARDING_KEY = "onboarding_complete";
8
+ import { createStore } from "@umituz/react-native-design-system/storage";
13
9
 
14
10
  export interface SubscriptionFlowState {
15
11
  isInitialized: boolean;
@@ -20,8 +16,7 @@ export interface SubscriptionFlowState {
20
16
  isAuthModalOpen: boolean;
21
17
  }
22
18
 
23
- export interface UseSubscriptionFlowResult {
24
- state: SubscriptionFlowState;
19
+ export interface SubscriptionFlowActions {
25
20
  completeOnboarding: () => Promise<void>;
26
21
  closePostOnboardingPaywall: () => Promise<void>;
27
22
  closeFeedback: () => void;
@@ -29,128 +24,78 @@ export interface UseSubscriptionFlowResult {
29
24
  markPaywallShown: () => Promise<void>;
30
25
  setShowFeedback: (show: boolean) => void;
31
26
  resetFlow: () => Promise<void>;
27
+ setInitialized: (initialized: boolean) => void;
32
28
  }
33
29
 
34
- export function useSubscriptionFlow(userId?: string): UseSubscriptionFlowResult {
35
- const [state, setState] = useState<SubscriptionFlowState>({
36
- isInitialized: false,
37
- isOnboardingComplete: false,
38
- showPostOnboardingPaywall: false,
39
- showFeedback: false,
40
- paywallShown: false,
41
- isAuthModalOpen: false,
42
- });
43
-
44
- // Initialization: Load persisted state
45
- useEffect(() => {
46
- const init = async () => {
47
- try {
48
- const [onboardingValue, paywallValue] = await Promise.all([
49
- AsyncStorage.getItem(ONBOARDING_KEY),
50
- AsyncStorage.getItem(PAYWALL_SHOWN_KEY),
51
- ]);
52
-
53
- setState((prev) => ({
54
- ...prev,
55
- isInitialized: true,
56
- isOnboardingComplete: onboardingValue === "true",
57
- paywallShown: paywallValue === "true",
58
- }));
59
- } catch (error) {
60
- console.error("[useSubscriptionFlow] Initialization failed:", error);
61
- setState((prev) => ({ ...prev, isInitialized: true }));
62
- }
63
- };
64
-
65
- init();
66
-
67
- // Listen for global onboarding completion events (e.g. from standalone onboarding components)
68
- const subscription = DeviceEventEmitter.addListener(
69
- "onboarding-complete",
70
- () => {
71
- setState((prev) => ({ ...prev, isOnboardingComplete: true }));
72
- AsyncStorage.setItem(ONBOARDING_KEY, "true");
73
- }
74
- );
75
-
76
- return () => subscription.remove();
77
- }, []);
78
-
79
- const completeOnboarding = useCallback(async () => {
80
- try {
81
- await AsyncStorage.setItem(ONBOARDING_KEY, "true");
82
- setState((prev) => ({
83
- ...prev,
30
+ export type SubscriptionFlowStore = SubscriptionFlowState & SubscriptionFlowActions;
31
+
32
+ const initialState: SubscriptionFlowState = {
33
+ isInitialized: false,
34
+ isOnboardingComplete: false,
35
+ showPostOnboardingPaywall: false,
36
+ showFeedback: false,
37
+ paywallShown: false,
38
+ isAuthModalOpen: false,
39
+ };
40
+
41
+ export const useSubscriptionFlowStore = createStore<SubscriptionFlowState, SubscriptionFlowActions>({
42
+ name: "subscription-flow-storage",
43
+ initialState,
44
+ persist: true,
45
+ // Only persist onboarding and paywall status, other states are transient
46
+ partialize: (state) => ({
47
+ isOnboardingComplete: state.isOnboardingComplete,
48
+ paywallShown: state.paywallShown,
49
+ }),
50
+ onRehydrate: (state) => {
51
+ state.setInitialized(true);
52
+ },
53
+ actions: (set) => ({
54
+ completeOnboarding: async () => {
55
+ set({
84
56
  isOnboardingComplete: true,
85
57
  showPostOnboardingPaywall: true,
86
- }));
58
+ });
87
59
  DeviceEventEmitter.emit("onboarding-complete");
88
- } catch (e) {
89
- console.error("[useSubscriptionFlow] Failed to complete onboarding:", e);
90
- }
91
- }, []);
92
-
93
- const closePostOnboardingPaywall = useCallback(async () => {
94
- try {
95
- await AsyncStorage.setItem(PAYWALL_SHOWN_KEY, "true");
96
- setState((prev) => ({
97
- ...prev,
60
+ },
61
+ closePostOnboardingPaywall: async () => {
62
+ set({
98
63
  showPostOnboardingPaywall: false,
99
64
  paywallShown: true,
100
- }));
101
- } catch (e) {
102
- console.error("[useSubscriptionFlow] Failed to close paywall:", e);
103
- }
104
- }, []);
105
-
106
- const closeFeedback = useCallback(() => {
107
- setState((prev) => ({ ...prev, showFeedback: false }));
108
- }, []);
109
-
110
- const setAuthModalOpen = useCallback((open: boolean) => {
111
- setState((prev) => ({ ...prev, isAuthModalOpen: open }));
112
- }, []);
113
-
114
- const setShowFeedback = useCallback((show: boolean) => {
115
- setState((prev) => ({ ...prev, showFeedback: show }));
116
- }, []);
117
-
118
- const markPaywallShown = useCallback(async () => {
119
- try {
120
- await AsyncStorage.setItem(PAYWALL_SHOWN_KEY, "true");
121
- setState((prev) => ({ ...prev, paywallShown: true }));
122
- } catch (e) {
123
- console.error("[useSubscriptionFlow] Failed to mark paywall shown:", e);
124
- }
125
- }, []);
126
-
127
- const resetFlow = useCallback(async () => {
128
- try {
129
- await Promise.all([
130
- AsyncStorage.removeItem(ONBOARDING_KEY),
131
- AsyncStorage.removeItem(PAYWALL_SHOWN_KEY),
132
- ]);
133
- setState({
134
- isInitialized: true,
65
+ });
66
+ },
67
+ closeFeedback: () => set({ showFeedback: false }),
68
+ setAuthModalOpen: (open: boolean) => set({ isAuthModalOpen: open }),
69
+ setShowFeedback: (show: boolean) => set({ showFeedback: show }),
70
+ markPaywallShown: async () => set({ paywallShown: true }),
71
+ setInitialized: (initialized: boolean) => set({ isInitialized: initialized }),
72
+ resetFlow: async () => {
73
+ set({
135
74
  isOnboardingComplete: false,
136
75
  showPostOnboardingPaywall: false,
137
76
  showFeedback: false,
138
77
  paywallShown: false,
139
78
  isAuthModalOpen: false,
140
79
  });
141
- } catch (e) {
142
- console.error("[useSubscriptionFlow] Failed to reset flow:", e);
143
- }
144
- }, []);
80
+ },
81
+ }),
82
+ });
145
83
 
84
+ /**
85
+ * Hook for backward compatibility and easier consumption.
86
+ * Provides a unified object structure matching the previous implementation.
87
+ */
88
+ export function useSubscriptionFlow(_userId?: string) {
89
+ const store = useSubscriptionFlowStore();
90
+
146
91
  return {
147
- state,
148
- completeOnboarding,
149
- closePostOnboardingPaywall,
150
- closeFeedback,
151
- setAuthModalOpen,
152
- markPaywallShown,
153
- setShowFeedback,
154
- resetFlow,
92
+ state: store,
93
+ completeOnboarding: store.completeOnboarding,
94
+ closePostOnboardingPaywall: store.closePostOnboardingPaywall,
95
+ closeFeedback: store.closeFeedback,
96
+ setAuthModalOpen: store.setAuthModalOpen,
97
+ markPaywallShown: store.markPaywallShown,
98
+ setShowFeedback: store.setShowFeedback,
99
+ resetFlow: store.resetFlow,
155
100
  };
156
101
  }
package/src/index.ts CHANGED
@@ -45,8 +45,8 @@ export { useDeductCredit } from "./domains/credits/presentation/deduct-credit/us
45
45
  export { useFeatureGate } from "./domains/subscription/presentation/useFeatureGate";
46
46
  export { usePaywallVisibility, paywallControl } from "./domains/subscription/presentation/usePaywallVisibility";
47
47
  export { usePremium } from "./domains/subscription/presentation/usePremium";
48
- export { useSubscriptionFlow } from "./domains/subscription/presentation/useSubscriptionFlow";
49
- export type { SubscriptionFlowState, UseSubscriptionFlowResult } from "./domains/subscription/presentation/useSubscriptionFlow";
48
+ export { useSubscriptionFlow, useSubscriptionFlowStore } from "./domains/subscription/presentation/useSubscriptionFlow";
49
+ export type { SubscriptionFlowState, SubscriptionFlowActions, SubscriptionFlowStore } from "./domains/subscription/presentation/useSubscriptionFlow";
50
50
  export { useSubscriptionStatus } from "./domains/subscription/presentation/useSubscriptionStatus";
51
51
  export * from "./domains/subscription/presentation/useSubscriptionStatus.types";
52
52
  export * from "./presentation/hooks/feedback/usePaywallFeedback";