@umituz/react-native-subscription 3.1.9 → 3.1.11

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.
Files changed (45) hide show
  1. package/package.json +1 -1
  2. package/src/domains/credits/presentation/useCreditsRealTime.ts +31 -73
  3. package/src/domains/credits/utils/creditValidation.ts +5 -26
  4. package/src/domains/paywall/hooks/usePaywallActions.ts +21 -133
  5. package/src/domains/paywall/hooks/usePaywallActions.types.ts +16 -0
  6. package/src/domains/paywall/hooks/usePaywallPurchase.ts +78 -0
  7. package/src/domains/paywall/hooks/usePaywallRestore.ts +66 -0
  8. package/src/domains/revenuecat/infrastructure/services/userSwitchCore.ts +116 -0
  9. package/src/domains/revenuecat/infrastructure/services/userSwitchHandler.ts +19 -237
  10. package/src/domains/revenuecat/infrastructure/services/userSwitchHelpers.ts +55 -0
  11. package/src/domains/revenuecat/infrastructure/services/userSwitchInitializer.ts +143 -0
  12. package/src/domains/subscription/infrastructure/managers/SubscriptionManager.ts +6 -3
  13. package/src/domains/subscription/infrastructure/managers/initializationHandler.ts +2 -2
  14. package/src/domains/subscription/infrastructure/managers/packageHandlerFactory.ts +2 -2
  15. package/src/domains/subscription/infrastructure/managers/subscriptionManagerUtils.ts +2 -2
  16. package/src/domains/subscription/presentation/components/ManagedSubscriptionFlow.logic.ts +52 -0
  17. package/src/domains/subscription/presentation/components/ManagedSubscriptionFlow.tsx +15 -89
  18. package/src/domains/subscription/presentation/components/ManagedSubscriptionFlow.types.ts +59 -0
  19. package/src/domains/subscription/presentation/components/details/CreditRow.tsx +9 -0
  20. package/src/domains/subscription/presentation/components/details/PremiumDetailsCard.tsx +23 -0
  21. package/src/domains/subscription/presentation/components/states/FeedbackState.tsx +36 -0
  22. package/src/domains/subscription/presentation/components/states/InitializingState.tsx +47 -0
  23. package/src/domains/subscription/presentation/components/states/OnboardingState.tsx +27 -0
  24. package/src/domains/subscription/presentation/components/states/PaywallState.tsx +66 -0
  25. package/src/domains/subscription/presentation/components/states/ReadyState.tsx +51 -0
  26. package/src/domains/subscription/presentation/flowInitialState.ts +22 -0
  27. package/src/domains/subscription/presentation/flowTypes.ts +106 -0
  28. package/src/domains/subscription/presentation/screens/components/SubscriptionHeaderContent.tsx +119 -103
  29. package/src/domains/subscription/presentation/usePremiumActions.ts +5 -6
  30. package/src/domains/subscription/presentation/useSubscriptionFlow.ts +25 -92
  31. package/src/domains/wallet/presentation/components/BalanceCard.tsx +7 -0
  32. package/src/domains/wallet/presentation/components/TransactionItem.tsx +11 -0
  33. package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +34 -60
  34. package/src/index.components.ts +1 -1
  35. package/src/shared/infrastructure/SubscriptionEventBus.ts +4 -2
  36. package/src/shared/presentation/hooks/useFirestoreRealTime.ts +230 -0
  37. package/src/shared/presentation/types/hookState.types.ts +97 -0
  38. package/src/shared/utils/errors/errorAssertions.ts +35 -0
  39. package/src/shared/utils/errors/errorConversion.ts +73 -0
  40. package/src/shared/utils/errors/errorTypeGuards.ts +27 -0
  41. package/src/shared/utils/errors/errorWrappers.ts +54 -0
  42. package/src/shared/utils/errors/index.ts +19 -0
  43. package/src/shared/utils/errors/serviceErrors.ts +36 -0
  44. package/src/shared/utils/logger.ts +140 -0
  45. package/src/domains/subscription/presentation/components/ManagedSubscriptionFlow.states.tsx +0 -187
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Centralized logging utilities for development-only logging.
3
+ *
4
+ * Benefits:
5
+ * - Removes 8+ duplicated __DEV__ check patterns
6
+ * - Single source for logging configuration
7
+ * - Easier to add log aggregation later
8
+ * - Consistent formatting across all logs
9
+ */
10
+
11
+ /**
12
+ * Log level for categorizing log messages.
13
+ */
14
+ export enum LogLevel {
15
+ DEBUG = "DEBUG",
16
+ INFO = "INFO",
17
+ WARN = "WARN",
18
+ ERROR = "ERROR",
19
+ }
20
+
21
+ /**
22
+ * Structured log context for better debugging.
23
+ */
24
+ export interface LogContext {
25
+ /** Additional key-value pairs to include in the log */
26
+ [key: string]: unknown;
27
+ }
28
+
29
+ /**
30
+ * Internal logging function that only logs in __DEV__ mode.
31
+ */
32
+ function log(
33
+ level: LogLevel,
34
+ tag: string,
35
+ message: string,
36
+ context?: LogContext
37
+ ): void {
38
+ if (typeof __DEV__ === "undefined" || !__DEV__) {
39
+ return;
40
+ }
41
+
42
+ const timestamp = new Date().toISOString();
43
+ const logData = {
44
+ timestamp,
45
+ level,
46
+ tag,
47
+ message,
48
+ ...context,
49
+ };
50
+
51
+ switch (level) {
52
+ case LogLevel.DEBUG:
53
+ case LogLevel.INFO:
54
+ console.log(`[${tag}]`, message, context ? logData : "");
55
+ break;
56
+ case LogLevel.WARN:
57
+ console.warn(`[${tag}]`, message, context ? logData : "");
58
+ break;
59
+ case LogLevel.ERROR:
60
+ console.error(`[${tag}]`, message, context ? logData : "");
61
+ break;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Log a debug message. Only shown in __DEV__ mode.
67
+ *
68
+ * @param tag - Component or feature name for filtering
69
+ * @param message - Log message
70
+ * @param context - Optional additional context data
71
+ */
72
+ export function logDebug(tag: string, message: string, context?: LogContext): void {
73
+ log(LogLevel.DEBUG, tag, message, context);
74
+ }
75
+
76
+ /**
77
+ * Log an info message. Only shown in __DEV__ mode.
78
+ *
79
+ * @param tag - Component or feature name for filtering
80
+ * @param message - Log message
81
+ * @param context - Optional additional context data
82
+ */
83
+ export function logInfo(tag: string, message: string, context?: LogContext): void {
84
+ log(LogLevel.INFO, tag, message, context);
85
+ }
86
+
87
+ /**
88
+ * Log a warning message. Only shown in __DEV__ mode.
89
+ *
90
+ * @param tag - Component or feature name for filtering
91
+ * @param message - Warning message
92
+ * @param context - Optional additional context data
93
+ */
94
+ export function logWarn(tag: string, message: string, context?: LogContext): void {
95
+ log(LogLevel.WARN, tag, message, context);
96
+ }
97
+
98
+ /**
99
+ * Log an error message. Only shown in __DEV__ mode.
100
+ *
101
+ * @param tag - Component or feature name for filtering
102
+ * @param message - Error message
103
+ * @param error - Error object (will be serialized)
104
+ * @param context - Optional additional context data
105
+ */
106
+ export function logError(
107
+ tag: string,
108
+ message: string,
109
+ error?: Error | unknown,
110
+ context?: LogContext
111
+ ): void {
112
+ const errorContext = {
113
+ ...context,
114
+ error: error instanceof Error ? {
115
+ name: error.name,
116
+ message: error.message,
117
+ stack: error.stack,
118
+ } : error,
119
+ };
120
+ log(LogLevel.ERROR, tag, message, errorContext);
121
+ }
122
+
123
+ /**
124
+ * Create a tagged logger for a specific component or feature.
125
+ * Returns functions that automatically include the tag.
126
+ *
127
+ * @example
128
+ * const logger = createLogger("useCredits");
129
+ * logger.info("Credits loaded", { credits: 100 });
130
+ * logger.error("Failed to load", error);
131
+ */
132
+ export function createLogger(tag: string) {
133
+ return {
134
+ debug: (message: string, context?: LogContext) => logDebug(tag, message, context),
135
+ info: (message: string, context?: LogContext) => logInfo(tag, message, context),
136
+ warn: (message: string, context?: LogContext) => logWarn(tag, message, context),
137
+ error: (message: string, error?: Error | unknown, context?: LogContext) =>
138
+ logError(tag, message, error, context),
139
+ };
140
+ }
@@ -1,187 +0,0 @@
1
- /**
2
- * State Components for ManagedSubscriptionFlow
3
- * Separated for better maintainability
4
- */
5
-
6
- import React from "react";
7
- import type { PurchasesPackage } from "react-native-purchases";
8
- import type { UserCredits } from "../../../credits/core/Credits";
9
- import { SplashScreen } from "@umituz/react-native-design-system/molecules";
10
- import { OnboardingScreen } from "@umituz/react-native-design-system/onboarding";
11
- import type { ManagedSubscriptionFlowProps } from "./ManagedSubscriptionFlow";
12
- import { PaywallScreen } from "../../../paywall/components/PaywallScreen";
13
- import { PaywallFeedbackScreen } from "./feedback/PaywallFeedbackScreen";
14
- import { usePaywallFeedbackSubmit } from "../../../../presentation/hooks/feedback/useFeedbackSubmit";
15
-
16
- // ============================================================================
17
- // INITIALIZING STATE
18
- // ============================================================================
19
-
20
- interface InitializingStateProps {
21
- tokens: any;
22
- splash?: ManagedSubscriptionFlowProps["splash"];
23
- }
24
-
25
- export const InitializingState: React.FC<InitializingStateProps> = ({ tokens, splash }) => (
26
- <SplashScreen
27
- appName={splash?.appName || "Loading..."}
28
- tagline={splash?.tagline || "Please wait while we set things up"}
29
- colors={tokens.colors}
30
- />
31
- );
32
-
33
- // ============================================================================
34
- // ONBOARDING STATE
35
- // ============================================================================
36
-
37
- interface OnboardingStateProps {
38
- config: ManagedSubscriptionFlowProps["onboarding"];
39
- onComplete: () => void;
40
- }
41
-
42
- export const OnboardingState: React.FC<OnboardingStateProps> = ({ config, onComplete }) => (
43
- <OnboardingScreen
44
- slides={config.slides}
45
- onComplete={onComplete}
46
- showSkipButton={config.showSkipButton ?? true}
47
- showBackButton={config.showBackButton ?? true}
48
- showProgressBar={config.showProgressBar ?? true}
49
- themeColors={config.themeColors}
50
- translations={config.translations}
51
- />
52
- );
53
-
54
- // ============================================================================
55
- // PAYWALL STATE
56
- // ============================================================================
57
-
58
- interface PaywallStateProps {
59
- config: ManagedSubscriptionFlowProps["paywall"];
60
- packages: PurchasesPackage[];
61
- isPremium: boolean;
62
- credits: UserCredits | null;
63
- isSyncing: boolean;
64
- onPurchase: (pkg: PurchasesPackage) => Promise<boolean>;
65
- onRestore: () => Promise<boolean>;
66
- onClose: (purchased: boolean) => void;
67
- }
68
-
69
- export const PaywallState: React.FC<PaywallStateProps> = ({
70
- config,
71
- packages,
72
- isPremium,
73
- credits,
74
- isSyncing,
75
- onPurchase,
76
- onRestore,
77
- onClose,
78
- }) => {
79
- const [purchaseSuccessful, setPurchaseSuccessful] = React.useState(false);
80
-
81
- const handlePurchase = async (pkg: PurchasesPackage) => {
82
- const result = await onPurchase(pkg);
83
- if (result) {
84
- setPurchaseSuccessful(true);
85
- }
86
- return result;
87
- };
88
-
89
- const handleClose = () => {
90
- onClose(purchaseSuccessful);
91
- };
92
-
93
- return (
94
- <PaywallScreen
95
- translations={config.translations}
96
- legalUrls={config.legalUrls}
97
- features={config.features}
98
- bestValueIdentifier={config.bestValueIdentifier}
99
- creditsLabel={config.creditsLabel}
100
- heroImage={config.heroImage}
101
- source="onboarding"
102
- packages={packages}
103
- isPremium={isPremium}
104
- credits={credits}
105
- isSyncing={isSyncing}
106
- onPurchase={handlePurchase}
107
- onRestore={onRestore}
108
- onClose={handleClose}
109
- />
110
- );
111
- };
112
-
113
- // ============================================================================
114
- // FEEDBACK STATE
115
- // ============================================================================
116
-
117
- interface FeedbackStateProps {
118
- config: ManagedSubscriptionFlowProps["feedback"];
119
- onClose: () => void;
120
- }
121
-
122
- export const FeedbackState: React.FC<FeedbackStateProps> = ({ config, onClose }) => {
123
- const { submit: internalSubmit } = usePaywallFeedbackSubmit();
124
-
125
- const handleSubmit = async (data: { reason: string; otherText?: string }) => {
126
- if (config.onSubmit) {
127
- await config.onSubmit(data);
128
- } else {
129
- const description = data.otherText ? `${data.reason}: ${data.otherText}` : data.reason;
130
- await internalSubmit(description);
131
- }
132
- };
133
-
134
- return (
135
- <PaywallFeedbackScreen
136
- onClose={onClose}
137
- onSubmit={handleSubmit}
138
- translations={config.translations}
139
- />
140
- );
141
- };
142
-
143
- // ============================================================================
144
- // READY STATE (APP CONTENT)
145
- // ============================================================================
146
-
147
- interface ReadyStateProps {
148
- children: React.ReactNode;
149
- offline?: ManagedSubscriptionFlowProps["offline"];
150
- feedbackConfig: ManagedSubscriptionFlowProps["feedback"];
151
- showFeedback: boolean;
152
- tokens: any;
153
- onFeedbackClose: () => void;
154
- }
155
-
156
- export const ReadyState: React.FC<ReadyStateProps> = ({
157
- children,
158
- offline,
159
- feedbackConfig,
160
- showFeedback,
161
- tokens,
162
- onFeedbackClose,
163
- }) => {
164
- const { OfflineBanner } = require("@umituz/react-native-design-system/offline");
165
-
166
- return (
167
- <>
168
- {children}
169
-
170
- {offline && (
171
- <OfflineBanner
172
- visible={offline.isOffline}
173
- message={offline.message}
174
- backgroundColor={offline.backgroundColor || tokens.colors.error}
175
- position={offline.position || "top"}
176
- />
177
- )}
178
-
179
- {showFeedback && (
180
- <FeedbackState
181
- config={feedbackConfig}
182
- onClose={onFeedbackClose}
183
- />
184
- )}
185
- </>
186
- );
187
- };