@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.
- package/package.json +1 -1
- package/src/infrastructure/services/AuthService.ts +14 -173
- package/src/infrastructure/storage/GuestModeStorage.ts +54 -0
- package/src/infrastructure/utils/AuthErrorMapper.ts +57 -0
- package/src/infrastructure/utils/AuthEventEmitter.ts +29 -0
- package/src/infrastructure/utils/AuthValidation.ts +60 -0
- package/src/presentation/components/LoginForm.tsx +16 -106
- package/src/presentation/components/RegisterForm.tsx +17 -104
- package/src/presentation/hooks/useAuth.ts +14 -236
- package/src/presentation/hooks/useAuthActions.ts +186 -0
- package/src/presentation/hooks/useAuthState.ts +99 -0
- package/src/presentation/hooks/useLoginForm.ts +165 -0
- package/src/presentation/hooks/useRegisterForm.ts +170 -0
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Register Form Component
|
|
3
|
-
*
|
|
3
|
+
* Single Responsibility: Render register form UI
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import 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 {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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 {
|
|
12
|
-
import {
|
|
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
|
-
|
|
53
|
-
const
|
|
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
|
|
277
|
-
isGuest,
|
|
278
|
-
isAuthenticated,
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
+
|