@umituz/react-native-auth 1.6.9 → 1.7.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.
@@ -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,282 +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("========================================");
239
- console.log("[useAuth] 🎯 continueAsGuest() CALLED");
240
- console.log("[useAuth] Current state:", {
241
- isGuest,
242
- loading,
243
- firebaseUser: firebaseUser?.uid || null,
244
- });
245
- console.log("========================================");
246
- }
247
-
248
- const service = getAuthService();
249
- if (!service) {
250
- /* eslint-disable-next-line no-console */
251
- if (__DEV__) {
252
- console.log("[useAuth] ⚠️ No service available, setting isGuest directly");
253
- }
254
- setIsGuest(true);
255
- return;
256
- }
257
-
258
- try {
259
- /* eslint-disable-next-line no-console */
260
- if (__DEV__) {
261
- console.log("[useAuth] Setting loading to true...");
262
- }
263
- setLoading(true);
264
-
265
- /* eslint-disable-next-line no-console */
266
- if (__DEV__) {
267
- console.log("[useAuth] 📞 Calling service.setGuestMode()...");
268
- }
269
- await service.setGuestMode();
270
-
271
- /* eslint-disable-next-line no-console */
272
- if (__DEV__) {
273
- console.log("[useAuth] ✅ Service.setGuestMode() completed successfully");
274
- console.log("[useAuth] Setting isGuest to true...");
275
- }
276
-
277
- // State will be updated by event listener, but set it here too for immediate update
278
- setIsGuest(true);
279
-
280
- /* eslint-disable-next-line no-console */
281
- if (__DEV__) {
282
- console.log("[useAuth] ✅ isGuest set to true");
283
- console.log("[useAuth] Current state after:", {
284
- isGuest: true,
285
- loading: true, // Still loading, will be set to false in finally
286
- });
287
- }
288
- } catch (error) {
289
- /* eslint-disable-next-line no-console */
290
- if (__DEV__) {
291
- console.error("[useAuth] ❌ ERROR in continueAsGuest:", error);
292
- console.error("[useAuth] Error details:", {
293
- message: error instanceof Error ? error.message : String(error),
294
- stack: error instanceof Error ? error.stack : undefined,
295
- });
296
- }
297
- // Even if service fails, set guest mode locally
298
- setIsGuest(true);
299
- } finally {
300
- /* eslint-disable-next-line no-console */
301
- if (__DEV__) {
302
- console.log("[useAuth] Setting loading to false...");
303
- }
304
- setLoading(false);
305
- /* eslint-disable-next-line no-console */
306
- if (__DEV__) {
307
- console.log("[useAuth] ✅ continueAsGuest() FINISHED");
308
- console.log("[useAuth] Final state:", {
309
- isGuest,
310
- loading: false,
311
- });
312
- console.log("========================================");
313
- }
314
- }
315
- }, [isGuest, firebaseUser]);
50
+ const state = useAuthState();
51
+ const actions = useAuthActions(state);
316
52
 
317
53
  return {
318
- user,
319
- loading: loading || firebaseLoading,
320
- isGuest,
321
- isAuthenticated,
322
- // authStatus, // This line is removed
323
- error,
324
- signUp,
325
- signIn,
326
- signOut,
327
- continueAsGuest,
328
- 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,
329
64
  };
330
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
+