@umituz/react-native-auth 1.6.8 → 1.7.0

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.
@@ -1,23 +1,16 @@
1
1
  /**
2
2
  * Register Form Component
3
- * Form fields and actions for registration
3
+ * Single Responsibility: Render register form UI
4
4
  */
5
5
 
6
- import React, { useState } from "react";
6
+ import React from "react";
7
7
  import { View, StyleSheet } from "react-native";
8
8
  import { AtomicInput, AtomicButton } from "@umituz/react-native-design-system-atoms";
9
9
  import { useLocalization } from "@umituz/react-native-localization";
10
- import {
11
- validateEmail,
12
- validatePassword,
13
- validatePasswordConfirmation,
14
- batchValidate,
15
- } from "@umituz/react-native-validation";
16
- import { useAuth } from "../hooks/useAuth";
10
+ import { useRegisterForm } from "../hooks/useRegisterForm";
17
11
  import { AuthErrorDisplay } from "./AuthErrorDisplay";
18
12
  import { AuthLink } from "./AuthLink";
19
13
  import { AuthLegalLinks } from "./AuthLegalLinks";
20
- import { getAuthErrorLocalizationKey } from "../utils/getAuthErrorMessage";
21
14
 
22
15
  interface RegisterFormProps {
23
16
  onNavigateToLogin: () => void;
@@ -35,100 +28,20 @@ export const RegisterForm: React.FC<RegisterFormProps> = ({
35
28
  onPrivacyPress,
36
29
  }) => {
37
30
  const { t } = useLocalization();
38
- const { signUp, loading, error } = useAuth();
39
-
40
- const [displayName, setDisplayName] = useState("");
41
- const [email, setEmail] = useState("");
42
- const [password, setPassword] = useState("");
43
- const [confirmPassword, setConfirmPassword] = useState("");
44
- const [localError, setLocalError] = useState<string | null>(null);
45
- const [fieldErrors, setFieldErrors] = useState<{
46
- displayName?: string;
47
- email?: string;
48
- password?: string;
49
- confirmPassword?: string;
50
- }>({});
51
-
52
- const handleDisplayNameChange = (text: string) => {
53
- setDisplayName(text);
54
- if (fieldErrors.displayName) {
55
- setFieldErrors({ ...fieldErrors, displayName: undefined });
56
- }
57
- if (localError) setLocalError(null);
58
- };
59
-
60
- const handleEmailChange = (text: string) => {
61
- setEmail(text);
62
- if (fieldErrors.email) {
63
- setFieldErrors({ ...fieldErrors, email: undefined });
64
- }
65
- if (localError) setLocalError(null);
66
- };
67
-
68
- const handlePasswordChange = (text: string) => {
69
- setPassword(text);
70
- if (fieldErrors.password) {
71
- setFieldErrors({ ...fieldErrors, password: undefined });
72
- }
73
- if (fieldErrors.confirmPassword) {
74
- setFieldErrors({ ...fieldErrors, confirmPassword: undefined });
75
- }
76
- if (localError) setLocalError(null);
77
- };
78
-
79
- const handleConfirmPasswordChange = (text: string) => {
80
- setConfirmPassword(text);
81
- if (fieldErrors.confirmPassword) {
82
- setFieldErrors({ ...fieldErrors, confirmPassword: undefined });
83
- }
84
- if (localError) setLocalError(null);
85
- };
86
-
87
- const handleSignUp = async () => {
88
- setLocalError(null);
89
- setFieldErrors({});
90
-
91
- const validationResult = batchValidate([
92
- {
93
- field: "email",
94
- validator: () => validateEmail(email.trim()),
95
- },
96
- {
97
- field: "password",
98
- validator: () =>
99
- validatePassword(password, {
100
- minLength: 6,
101
- requireUppercase: false,
102
- requireLowercase: false,
103
- requireNumber: false,
104
- }),
105
- },
106
- {
107
- field: "confirmPassword",
108
- validator: () =>
109
- validatePasswordConfirmation(password, confirmPassword),
110
- },
111
- ]);
112
-
113
- if (!validationResult.isValid) {
114
- setFieldErrors(validationResult.errors);
115
- return;
116
- }
117
-
118
- try {
119
- await signUp(
120
- email.trim(),
121
- password,
122
- displayName.trim() || undefined,
123
- );
124
- } catch (err: any) {
125
- const localizationKey = getAuthErrorLocalizationKey(err);
126
- const errorMessage = t(localizationKey);
127
- setLocalError(errorMessage);
128
- }
129
- };
130
-
131
- const displayError = localError || error;
31
+ const {
32
+ displayName,
33
+ email,
34
+ password,
35
+ confirmPassword,
36
+ fieldErrors,
37
+ loading,
38
+ handleDisplayNameChange,
39
+ handleEmailChange,
40
+ handlePasswordChange,
41
+ handleConfirmPasswordChange,
42
+ handleSignUp,
43
+ displayError,
44
+ } = useRegisterForm();
132
45
 
133
46
  return (
134
47
  <>
@@ -6,11 +6,9 @@
6
6
  * Adds app-specific state (guest mode, error handling) on top of Firebase Auth.
7
7
  */
8
8
 
9
- import { useEffect, useRef, useCallback, useState } from "react";
10
9
  import type { User } from "firebase/auth";
11
- import { DeviceEventEmitter } from "react-native";
12
- import { getAuthService } from "../../infrastructure/services/AuthService";
13
- import { useFirebaseAuth } from "@umituz/react-native-firebase-auth";
10
+ import { useAuthState } from "./useAuthState";
11
+ import { useAuthActions } from "./useAuthActions";
14
12
 
15
13
  export interface UseAuthResult {
16
14
  /** Current authenticated user */
@@ -49,239 +47,19 @@ export interface UseAuthResult {
49
47
  * ```
50
48
  */
51
49
  export function useAuth(): UseAuthResult {
52
- // Use Firebase Auth's built-in state management
53
- const { user: firebaseUser, loading: firebaseLoading } = useFirebaseAuth();
54
-
55
- // App-specific state
56
- // Initialize isGuest from service if available
57
- const [isGuest, setIsGuest] = useState(() => {
58
- const service = getAuthService();
59
- return service ? service.getIsGuestMode() : false;
60
- });
61
- const [error, setError] = useState<string | null>(null);
62
- const [loading, setLoading] = useState(false);
63
- const prevAuthState = useRef({ isAuthenticated: false, isGuest: false });
64
-
65
- // Sync Firebase Auth user with guest mode
66
- const user = isGuest ? null : firebaseUser;
67
- const isAuthenticated = !!user && !isGuest;
68
-
69
- // Update authStatus whenever authentication state changes
70
- useEffect(() => {
71
- if (firebaseLoading || loading) {
72
- // setAuthStatus('loading'); // This line is removed
73
- } else if (isAuthenticated) {
74
- // setAuthStatus('authenticated'); // This line is removed
75
- } else if (isGuest) {
76
- // setAuthStatus('guest'); // This line is removed
77
- } else {
78
- // setAuthStatus('unauthenticated'); // This line is removed
79
- }
80
- }, [isAuthenticated, isGuest, firebaseLoading, loading]);
81
-
82
- // Handle analytics initialization (if callbacks are provided in config)
83
- useEffect(() => {
84
- const authChanged =
85
- prevAuthState.current.isAuthenticated !== isAuthenticated ||
86
- prevAuthState.current.isGuest !== isGuest;
87
-
88
- // Analytics initialization is handled by AuthService callbacks (onAnalyticsInit, onAnalyticsInitGuest)
89
- // This effect is kept for backward compatibility but analytics should be configured via AuthConfig
90
-
91
- // Update previous state
92
- prevAuthState.current = { isAuthenticated, isGuest };
93
- }, [isAuthenticated, isGuest]);
94
-
95
- // Reset guest mode when user signs in
96
- useEffect(() => {
97
- if (firebaseUser && isGuest) {
98
- setIsGuest(false);
99
- }
100
- }, [firebaseUser, isGuest]);
101
-
102
- // Sync isGuest state with service on mount
103
- useEffect(() => {
104
- const service = getAuthService();
105
- if (service) {
106
- const serviceIsGuest = service.getIsGuestMode();
107
- if (serviceIsGuest !== isGuest) {
108
- setIsGuest(serviceIsGuest);
109
- }
110
- }
111
- }, []);
112
-
113
- // Listen for guest-mode-enabled event to update state
114
- useEffect(() => {
115
- const guestSubscription = DeviceEventEmitter.addListener(
116
- "guest-mode-enabled",
117
- () => {
118
- /* eslint-disable-next-line no-console */
119
- if (__DEV__) {
120
- console.log("[useAuth] Guest mode enabled event received");
121
- }
122
- setIsGuest(true);
123
- }
124
- );
125
-
126
- // Listen for user-authenticated event to ensure state updates
127
- const authSubscription = DeviceEventEmitter.addListener(
128
- "user-authenticated",
129
- () => {
130
- /* eslint-disable-next-line no-console */
131
- if (__DEV__) {
132
- console.log("[useAuth] User authenticated event received");
133
- }
134
- // Clear guest mode if set
135
- if (isGuest) {
136
- setIsGuest(false);
137
- }
138
- }
139
- );
140
-
141
- return () => {
142
- guestSubscription.remove();
143
- authSubscription.remove();
144
- };
145
- }, [isGuest]);
146
-
147
- const signUp = useCallback(async (
148
- email: string,
149
- password: string,
150
- displayName?: string
151
- ) => {
152
- const service = getAuthService();
153
- if (!service) {
154
- const err = "Auth service is not initialized";
155
- setError(err);
156
- throw new Error(err);
157
- }
158
- try {
159
- setLoading(true);
160
- setError(null);
161
- await service.signUp({ email, password, displayName });
162
- // Clear guest mode when user signs up
163
- if (isGuest) {
164
- setIsGuest(false);
165
- }
166
- // User state is updated by Firebase Auth's onAuthStateChanged
167
- } catch (err: any) {
168
- const errorMessage = err.message || "Sign up failed";
169
- setError(errorMessage);
170
- throw err;
171
- } finally {
172
- setLoading(false);
173
- }
174
- }, [isGuest]);
175
-
176
- const signIn = useCallback(async (email: string, password: string) => {
177
- /* eslint-disable-next-line no-console */
178
- if (__DEV__) {
179
- console.log("[useAuth] signIn called with email:", email);
180
- }
181
- const service = getAuthService();
182
- if (!service) {
183
- const err = "Auth service is not initialized";
184
- setError(err);
185
- throw new Error(err);
186
- }
187
- try {
188
- setLoading(true);
189
- setError(null);
190
- /* eslint-disable-next-line no-console */
191
- if (__DEV__) {
192
- console.log("[useAuth] Calling service.signIn()");
193
- }
194
- await service.signIn({ email, password });
195
- /* eslint-disable-next-line no-console */
196
- if (__DEV__) {
197
- console.log("[useAuth] Service.signIn() completed successfully");
198
- }
199
- // Clear guest mode when user signs in
200
- if (isGuest) {
201
- /* eslint-disable-next-line no-console */
202
- if (__DEV__) {
203
- console.log("[useAuth] Clearing guest mode after sign in");
204
- }
205
- setIsGuest(false);
206
- }
207
- // User state is updated by Firebase Auth's onAuthStateChanged
208
- } catch (err: any) {
209
- /* eslint-disable-next-line no-console */
210
- if (__DEV__) {
211
- console.error("[useAuth] Error in signIn:", err);
212
- }
213
- const errorMessage = err.message || "Failed to sign in";
214
- setError(errorMessage);
215
- throw err;
216
- } finally {
217
- setLoading(false);
218
- }
219
- }, [isGuest]);
220
-
221
- const signOut = useCallback(async () => {
222
- const service = getAuthService();
223
- if (!service) {
224
- return;
225
- }
226
- try {
227
- setLoading(true);
228
- await service.signOut();
229
- // User state is updated by Firebase Auth's onAuthStateChanged
230
- } finally {
231
- setLoading(false);
232
- }
233
- }, []);
234
-
235
- const continueAsGuest = useCallback(async () => {
236
- /* eslint-disable-next-line no-console */
237
- if (__DEV__) {
238
- console.log("[useAuth] continueAsGuest called");
239
- }
240
- const service = getAuthService();
241
- if (!service) {
242
- /* eslint-disable-next-line no-console */
243
- if (__DEV__) {
244
- console.log("[useAuth] No service, setting isGuest directly");
245
- }
246
- setIsGuest(true);
247
- return;
248
- }
249
- try {
250
- setLoading(true);
251
- /* eslint-disable-next-line no-console */
252
- if (__DEV__) {
253
- console.log("[useAuth] Calling service.setGuestMode()");
254
- }
255
- await service.setGuestMode();
256
- /* eslint-disable-next-line no-console */
257
- if (__DEV__) {
258
- console.log("[useAuth] Service.setGuestMode() completed, setting isGuest to true");
259
- }
260
- // State will be updated by event listener, but set it here too for immediate update
261
- setIsGuest(true);
262
- } catch (error) {
263
- /* eslint-disable-next-line no-console */
264
- if (__DEV__) {
265
- console.error("[useAuth] Error in continueAsGuest:", error);
266
- }
267
- // Even if service fails, set guest mode locally
268
- setIsGuest(true);
269
- } finally {
270
- setLoading(false);
271
- }
272
- }, []);
50
+ const state = useAuthState();
51
+ const actions = useAuthActions(state);
273
52
 
274
53
  return {
275
- user,
276
- loading: loading || firebaseLoading,
277
- isGuest,
278
- isAuthenticated,
279
- // authStatus, // This line is removed
280
- error,
281
- signUp,
282
- signIn,
283
- signOut,
284
- continueAsGuest,
285
- setError,
54
+ user: state.user,
55
+ loading: state.loading,
56
+ isGuest: state.isGuest,
57
+ isAuthenticated: state.isAuthenticated,
58
+ error: state.error,
59
+ signUp: actions.signUp,
60
+ signIn: actions.signIn,
61
+ signOut: actions.signOut,
62
+ continueAsGuest: actions.continueAsGuest,
63
+ setError: state.setError,
286
64
  };
287
65
  }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * useAuthActions Hook
3
+ * Single Responsibility: Handle authentication actions
4
+ */
5
+
6
+ import { useCallback } from "react";
7
+ import { getAuthService } from "../../infrastructure/services/AuthService";
8
+ import type { UseAuthStateResult } from "./useAuthState";
9
+
10
+ export interface UseAuthActionsResult {
11
+ signUp: (email: string, password: string, displayName?: string) => Promise<void>;
12
+ signIn: (email: string, password: string) => Promise<void>;
13
+ signOut: () => Promise<void>;
14
+ continueAsGuest: () => Promise<void>;
15
+ }
16
+
17
+ /**
18
+ * Hook for authentication actions
19
+ */
20
+ export function useAuthActions(
21
+ state: UseAuthStateResult
22
+ ): UseAuthActionsResult {
23
+ const { isGuest, setIsGuest, setLoading, setError } = state;
24
+
25
+ const signUp = useCallback(async (
26
+ email: string,
27
+ password: string,
28
+ displayName?: string
29
+ ) => {
30
+ const service = getAuthService();
31
+ if (!service) {
32
+ const err = "Auth service is not initialized";
33
+ setError(err);
34
+ throw new Error(err);
35
+ }
36
+ try {
37
+ setLoading(true);
38
+ setError(null);
39
+ await service.signUp({ email, password, displayName });
40
+ if (isGuest) {
41
+ setIsGuest(false);
42
+ }
43
+ } catch (err: any) {
44
+ const errorMessage = err.message || "Sign up failed";
45
+ setError(errorMessage);
46
+ throw err;
47
+ } finally {
48
+ setLoading(false);
49
+ }
50
+ }, [isGuest, setIsGuest, setLoading, setError]);
51
+
52
+ const signIn = useCallback(async (email: string, password: string) => {
53
+ /* eslint-disable-next-line no-console */
54
+ if (__DEV__) {
55
+ console.log("[useAuthActions] signIn called with email:", email);
56
+ }
57
+ const service = getAuthService();
58
+ if (!service) {
59
+ const err = "Auth service is not initialized";
60
+ setError(err);
61
+ throw new Error(err);
62
+ }
63
+ try {
64
+ setLoading(true);
65
+ setError(null);
66
+ /* eslint-disable-next-line no-console */
67
+ if (__DEV__) {
68
+ console.log("[useAuthActions] Calling service.signIn()");
69
+ }
70
+ await service.signIn({ email, password });
71
+ /* eslint-disable-next-line no-console */
72
+ if (__DEV__) {
73
+ console.log("[useAuthActions] Service.signIn() completed successfully");
74
+ }
75
+ if (isGuest) {
76
+ /* eslint-disable-next-line no-console */
77
+ if (__DEV__) {
78
+ console.log("[useAuthActions] Clearing guest mode after sign in");
79
+ }
80
+ setIsGuest(false);
81
+ }
82
+ } catch (err: any) {
83
+ /* eslint-disable-next-line no-console */
84
+ if (__DEV__) {
85
+ console.error("[useAuthActions] Error in signIn:", err);
86
+ }
87
+ const errorMessage = err.message || "Failed to sign in";
88
+ setError(errorMessage);
89
+ throw err;
90
+ } finally {
91
+ setLoading(false);
92
+ }
93
+ }, [isGuest, setIsGuest, setLoading, setError]);
94
+
95
+ const signOut = useCallback(async () => {
96
+ const service = getAuthService();
97
+ if (!service) {
98
+ return;
99
+ }
100
+ try {
101
+ setLoading(true);
102
+ await service.signOut();
103
+ } finally {
104
+ setLoading(false);
105
+ }
106
+ }, [setLoading]);
107
+
108
+ const continueAsGuest = useCallback(async () => {
109
+ /* eslint-disable-next-line no-console */
110
+ if (__DEV__) {
111
+ console.log("========================================");
112
+ console.log("[useAuthActions] 🎯 continueAsGuest() CALLED");
113
+ console.log("[useAuthActions] Current state:", {
114
+ isGuest,
115
+ loading: state.loading,
116
+ });
117
+ console.log("========================================");
118
+ }
119
+
120
+ const service = getAuthService();
121
+ if (!service) {
122
+ /* eslint-disable-next-line no-console */
123
+ if (__DEV__) {
124
+ console.log("[useAuthActions] ⚠️ No service available, setting isGuest directly");
125
+ }
126
+ setIsGuest(true);
127
+ return;
128
+ }
129
+
130
+ try {
131
+ /* eslint-disable-next-line no-console */
132
+ if (__DEV__) {
133
+ console.log("[useAuthActions] Setting loading to true...");
134
+ }
135
+ setLoading(true);
136
+
137
+ /* eslint-disable-next-line no-console */
138
+ if (__DEV__) {
139
+ console.log("[useAuthActions] 📞 Calling service.setGuestMode()...");
140
+ }
141
+ await service.setGuestMode();
142
+
143
+ /* eslint-disable-next-line no-console */
144
+ if (__DEV__) {
145
+ console.log("[useAuthActions] ✅ Service.setGuestMode() completed successfully");
146
+ console.log("[useAuthActions] Setting isGuest to true...");
147
+ }
148
+
149
+ setIsGuest(true);
150
+
151
+ /* eslint-disable-next-line no-console */
152
+ if (__DEV__) {
153
+ console.log("[useAuthActions] ✅ isGuest set to true");
154
+ }
155
+ } catch (error) {
156
+ /* eslint-disable-next-line no-console */
157
+ if (__DEV__) {
158
+ console.error("[useAuthActions] ❌ ERROR in continueAsGuest:", error);
159
+ console.error("[useAuthActions] Error details:", {
160
+ message: error instanceof Error ? error.message : String(error),
161
+ stack: error instanceof Error ? error.stack : undefined,
162
+ });
163
+ }
164
+ setIsGuest(true);
165
+ } finally {
166
+ /* eslint-disable-next-line no-console */
167
+ if (__DEV__) {
168
+ console.log("[useAuthActions] Setting loading to false...");
169
+ }
170
+ setLoading(false);
171
+ /* eslint-disable-next-line no-console */
172
+ if (__DEV__) {
173
+ console.log("[useAuthActions] ✅ continueAsGuest() FINISHED");
174
+ console.log("========================================");
175
+ }
176
+ }
177
+ }, [isGuest, setIsGuest, setLoading, state.loading]);
178
+
179
+ return {
180
+ signUp,
181
+ signIn,
182
+ signOut,
183
+ continueAsGuest,
184
+ };
185
+ }
186
+
@@ -0,0 +1,99 @@
1
+ /**
2
+ * useAuthState Hook
3
+ * Single Responsibility: Manage authentication state
4
+ */
5
+
6
+ import { useState, useEffect } from "react";
7
+ import type { User } from "firebase/auth";
8
+ import { DeviceEventEmitter } from "react-native";
9
+ import { getAuthService } from "../../infrastructure/services/AuthService";
10
+ import { useFirebaseAuth } from "@umituz/react-native-firebase-auth";
11
+
12
+ export interface UseAuthStateResult {
13
+ user: User | null;
14
+ isAuthenticated: boolean;
15
+ isGuest: boolean;
16
+ loading: boolean;
17
+ error: string | null;
18
+ setError: (error: string | null) => void;
19
+ setIsGuest: (isGuest: boolean) => void;
20
+ setLoading: (loading: boolean) => void;
21
+ }
22
+
23
+ /**
24
+ * Hook for managing authentication state
25
+ */
26
+ export function useAuthState(): UseAuthStateResult {
27
+ const { user: firebaseUser, loading: firebaseLoading } = useFirebaseAuth();
28
+ const [isGuest, setIsGuest] = useState(() => {
29
+ const service = getAuthService();
30
+ return service ? service.getIsGuestMode() : false;
31
+ });
32
+ const [error, setError] = useState<string | null>(null);
33
+ const [loading, setLoading] = useState(false);
34
+
35
+ const user = isGuest ? null : firebaseUser;
36
+ const isAuthenticated = !!user && !isGuest;
37
+
38
+ // Reset guest mode when user signs in
39
+ useEffect(() => {
40
+ if (firebaseUser && isGuest) {
41
+ setIsGuest(false);
42
+ }
43
+ }, [firebaseUser, isGuest]);
44
+
45
+ // Sync isGuest state with service on mount
46
+ useEffect(() => {
47
+ const service = getAuthService();
48
+ if (service) {
49
+ const serviceIsGuest = service.getIsGuestMode();
50
+ if (serviceIsGuest !== isGuest) {
51
+ setIsGuest(serviceIsGuest);
52
+ }
53
+ }
54
+ }, []);
55
+
56
+ // Listen for guest-mode-enabled event
57
+ useEffect(() => {
58
+ const guestSubscription = DeviceEventEmitter.addListener(
59
+ "guest-mode-enabled",
60
+ () => {
61
+ /* eslint-disable-next-line no-console */
62
+ if (__DEV__) {
63
+ console.log("[useAuthState] Guest mode enabled event received");
64
+ }
65
+ setIsGuest(true);
66
+ }
67
+ );
68
+
69
+ const authSubscription = DeviceEventEmitter.addListener(
70
+ "user-authenticated",
71
+ () => {
72
+ /* eslint-disable-next-line no-console */
73
+ if (__DEV__) {
74
+ console.log("[useAuthState] User authenticated event received");
75
+ }
76
+ if (isGuest) {
77
+ setIsGuest(false);
78
+ }
79
+ }
80
+ );
81
+
82
+ return () => {
83
+ guestSubscription.remove();
84
+ authSubscription.remove();
85
+ };
86
+ }, [isGuest]);
87
+
88
+ return {
89
+ user,
90
+ isAuthenticated,
91
+ isGuest,
92
+ loading: loading || firebaseLoading,
93
+ error,
94
+ setError,
95
+ setIsGuest,
96
+ setLoading,
97
+ };
98
+ }
99
+