@umituz/react-native-auth 4.3.56 → 4.3.58

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 (26) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +18 -2
  3. package/src/infrastructure/repositories/AuthRepository.ts +0 -3
  4. package/src/infrastructure/services/AuthService.ts +2 -1
  5. package/src/infrastructure/utils/listener/anonymousSignInHandler.ts +2 -8
  6. package/src/presentation/README.md +0 -4
  7. package/src/presentation/components/LoginForm.tsx +2 -1
  8. package/src/presentation/components/PasswordStrengthIndicator.tsx +1 -1
  9. package/src/presentation/components/RegisterForm.tsx +3 -1
  10. package/src/presentation/hooks/README.md +0 -4
  11. package/src/presentation/hooks/registerForm/registerFormSubmit.ts +2 -2
  12. package/src/presentation/hooks/useAccountManagement.md +1 -1
  13. package/src/presentation/hooks/useAuth.ts +9 -20
  14. package/src/presentation/hooks/useLoginForm.ts +6 -5
  15. package/src/presentation/hooks/usePasswordPromptNavigation.ts +2 -1
  16. package/src/presentation/hooks/useProfileEdit.ts +2 -2
  17. package/src/presentation/stores/initializeAuthListener.ts +4 -2
  18. package/src/presentation/utils/form/usePasswordValidation.hook.ts +2 -2
  19. package/src/presentation/utils/form/validation/formValidators.ts +1 -1
  20. package/src/presentation/utils/passwordPromptCallback.ts +4 -0
  21. package/src/application/services/ValidationService.ts +0 -16
  22. package/src/infrastructure/utils/listener/listenerLifecycle.util.ts +0 -19
  23. package/src/init/index.ts +0 -6
  24. package/src/presentation/components/form/index.ts +0 -3
  25. package/src/presentation/hooks/useProfileUpdate.md +0 -299
  26. package/src/presentation/utils/form/formValidation.util.ts +0 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-auth",
3
- "version": "4.3.56",
3
+ "version": "4.3.58",
4
4
  "description": "Authentication service for React Native apps - Secure, type-safe, and production-ready. Provider-agnostic design with dependency injection, configurable validation, and comprehensive error handling.",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
package/src/index.ts CHANGED
@@ -103,13 +103,29 @@ export { useAuthStore } from './presentation/stores/authStore';
103
103
  export { useAuthModalStore } from './presentation/stores/authModalStore';
104
104
  export { initializeAuthListener, resetAuthListener, isAuthListenerInitialized } from './presentation/stores/initializeAuthListener';
105
105
  export type { AuthState, AuthActions, UserType, AuthListenerOptions } from './types/auth-store.types';
106
- export * from './presentation/stores/auth.selectors';
106
+ export type { AuthModalMode } from './presentation/stores/auth.selectors';
107
+ export {
108
+ selectUser,
109
+ selectLoading,
110
+ selectError,
111
+ selectSetLoading,
112
+ selectSetError,
113
+ selectSetIsAnonymous,
114
+ selectShowAuthModal,
115
+ selectUserId,
116
+ selectIsAuthenticated,
117
+ selectHasFirebaseUser,
118
+ selectIsAnonymous,
119
+ selectUserType,
120
+ selectIsAuthReady,
121
+ selectFirebaseUserId,
122
+ } from './presentation/stores/auth.selectors';
107
123
 
108
124
  // =============================================================================
109
125
  // UTILITIES & INIT
110
126
  // =============================================================================
111
127
 
112
128
  export { getAuthErrorLocalizationKey, resolveErrorMessage } from './presentation/utils/getAuthErrorMessage';
113
- export { createAuthInitModule } from './init';
129
+ export { createAuthInitModule } from './init/createAuthInitModule';
114
130
  export type { AuthInitModuleConfig } from './init/createAuthInitModule';
115
131
 
@@ -109,9 +109,6 @@ export class AuthRepository implements IAuthRepository {
109
109
  throw new AuthError("Failed to map user");
110
110
  }
111
111
 
112
- // Ensure Firestore user document exists for existing users too
113
- await ensureUserDocument(result.data, { signUpMethod: "email" });
114
-
115
112
  return authUser;
116
113
  }
117
114
 
@@ -83,7 +83,8 @@ export class AuthService {
83
83
  const success = await this.anonymousModeService.clear(this.storageProvider);
84
84
  if (!success) {
85
85
  console.warn('[AuthService] Failed to clear anonymous mode from storage');
86
- // Force clear in memory to maintain consistency
86
+ // Force clear in memory to maintain consistency and prevent stale state
87
+ // Storage clear failure shouldn't block auth flow, so we force update memory
87
88
  this.anonymousModeService.setAnonymousMode(false);
88
89
  }
89
90
  }
@@ -12,7 +12,6 @@ const ANONYMOUS_RETRY_DELAY_MS = 1000;
12
12
  const ANONYMOUS_SIGNIN_TIMEOUT_MS = 10000;
13
13
 
14
14
  interface AnonymousSignInCallbacks {
15
- onSignInStart: () => void;
16
15
  onSignInSuccess: () => void;
17
16
  onSignInFailure: (error: Error) => void;
18
17
  }
@@ -31,7 +30,7 @@ interface AnonymousSignInOptions {
31
30
  */
32
31
  async function attemptAnonymousSignIn(
33
32
  auth: Auth,
34
- callbacks: AnonymousSignInCallbacks,
33
+ callbacks: Omit<AnonymousSignInCallbacks, 'onSignInStart'>,
35
34
  options: AnonymousSignInOptions = {}
36
35
  ): Promise<void> {
37
36
  const {
@@ -40,8 +39,6 @@ async function attemptAnonymousSignIn(
40
39
  timeout = ANONYMOUS_SIGNIN_TIMEOUT_MS,
41
40
  } = options;
42
41
 
43
- callbacks.onSignInStart();
44
-
45
42
  let timeoutId: ReturnType<typeof setTimeout> | undefined;
46
43
 
47
44
  try {
@@ -83,7 +80,7 @@ async function performAnonymousSignIn(
83
80
  } catch (error) {
84
81
  // If not last attempt, wait and retry
85
82
  if (attempt < maxRetries - 1) {
86
- await new Promise(resolve => setTimeout(() => resolve(undefined), retryDelay));
83
+ await new Promise(resolve => setTimeout(resolve, retryDelay));
87
84
  continue;
88
85
  }
89
86
 
@@ -119,9 +116,6 @@ export function createAnonymousSignInHandler(
119
116
  await attemptAnonymousSignIn(
120
117
  auth,
121
118
  {
122
- onSignInStart: () => {
123
- // Sign-in starting
124
- },
125
119
  onSignInSuccess: () => {
126
120
  // Listener will be triggered again with the new user
127
121
  },
@@ -27,7 +27,6 @@ React components, hooks, providers, stores, and navigation for authentication UI
27
27
  **hooks/useAuth.ts** - Main auth hook
28
28
  **hooks/useAuthRequired.ts** - Auth requirement checking
29
29
  **hooks/useUserProfile.ts** - Profile data fetching
30
- **hooks/useProfileUpdate.ts** - Profile updates
31
30
  **hooks/useAccountManagement.ts** - Account operations
32
31
  **hooks/useSocialLogin.ts** - Social auth management
33
32
  **hooks/useAuthBottomSheet.ts** - Modal management
@@ -212,13 +211,11 @@ import { useUserProfile } from '@umituz/react-native-auth';
212
211
 
213
212
  ---
214
213
 
215
- #### useProfileUpdate
216
214
 
217
215
  **PURPOSE**: Profile update operations
218
216
 
219
217
  **IMPORT PATH**:
220
218
  ```typescript
221
- import { useProfileUpdate } from '@umituz/react-native-auth';
222
219
  ```
223
220
 
224
221
  **RETURNS**:
@@ -238,7 +235,6 @@ import { useProfileUpdate } from '@umituz/react-native-auth';
238
235
  - Ignore errors
239
236
  - Update without user action
240
237
 
241
- **Documentation**: `hooks/useProfileUpdate.md`
242
238
 
243
239
  ---
244
240
 
@@ -4,7 +4,8 @@ import { AtomicButton } from "@umituz/react-native-design-system/atoms";
4
4
  import { useLoginForm } from "../hooks/useLoginForm";
5
5
  import { AuthErrorDisplay } from "./AuthErrorDisplay";
6
6
  import { AuthLink } from "./AuthLink";
7
- import { FormEmailInput, FormPasswordInput } from "./form";
7
+ import { FormEmailInput } from "./form/FormEmailInput";
8
+ import { FormPasswordInput } from "./form/FormPasswordInput";
8
9
 
9
10
  export interface LoginFormTranslations {
10
11
  email: string;
@@ -3,7 +3,7 @@ import { View, StyleSheet } from "react-native";
3
3
  import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
4
4
  import { AtomicText } from "@umituz/react-native-design-system/atoms";
5
5
  import type { ColorVariant } from "@umituz/react-native-design-system/typography";
6
- import type { PasswordRequirements } from "../../application/services/ValidationService";
6
+ import type { PasswordRequirements } from "../../infrastructure/utils/validation/types";
7
7
 
8
8
  export interface PasswordStrengthTranslations {
9
9
  minLength: string;
@@ -7,7 +7,9 @@ import { AuthLink } from "./AuthLink";
7
7
  import { AuthLegalLinks, type AuthLegalLinksTranslations } from "./AuthLegalLinks";
8
8
  import { PasswordStrengthIndicator, type PasswordStrengthTranslations } from "./PasswordStrengthIndicator";
9
9
  import { PasswordMatchIndicator, type PasswordMatchTranslations } from "./PasswordMatchIndicator";
10
- import { FormTextInput, FormEmailInput, FormPasswordInput } from "./form";
10
+ import { FormTextInput } from "./form/FormTextInput";
11
+ import { FormEmailInput } from "./form/FormEmailInput";
12
+ import { FormPasswordInput } from "./form/FormPasswordInput";
11
13
 
12
14
  export interface RegisterFormTranslations {
13
15
  displayName: string;
@@ -127,7 +127,6 @@ import { useUserProfile } from '@umituz/react-native-auth';
127
127
 
128
128
  ---
129
129
 
130
- ### useProfileUpdate & useProfileEdit
131
130
 
132
131
  **Purpose**: Profile update operations and form management
133
132
 
@@ -140,12 +139,10 @@ import { useUserProfile } from '@umituz/react-native-auth';
140
139
  **Import Path**:
141
140
  ```typescript
142
141
  import {
143
- useProfileUpdate,
144
142
  useProfileEdit
145
143
  } from '@umituz/react-native-auth';
146
144
  ```
147
145
 
148
- **File**: `useProfileUpdate.ts`
149
146
 
150
147
  **Rules**:
151
148
  - MUST validate before update
@@ -153,7 +150,6 @@ import {
153
150
  - MUST show errors to user
154
151
  - MUST not allow anonymous updates
155
152
 
156
- **Documentation**: `useProfileUpdate.md`
157
153
 
158
154
  ---
159
155
 
@@ -8,8 +8,8 @@ import { alertService } from "@umituz/react-native-design-system/molecules";
8
8
  import { DEFAULT_PASSWORD_CONFIG } from "../../../domain/value-objects/AuthConfig";
9
9
  import {
10
10
  validateRegisterForm,
11
- errorsToFieldErrors,
12
- } from "../../utils/form/formValidation.util";
11
+ } from "../../utils/form/validation/formValidators";
12
+ import { errorsToFieldErrors } from "../../utils/form/validation/formValidation.utils";
13
13
  import type { FieldErrors, RegisterFormTranslations } from "./useRegisterForm.types";
14
14
  import { sanitizeEmail, sanitizeName } from "../../../infrastructure/utils/validation/sanitization";
15
15
 
@@ -330,7 +330,7 @@ import { useAccountManagement } from '@umituz/react-native-auth';
330
330
 
331
331
  - **`useAuth`** (`src/presentation/hooks/useAuth.ts`) - Authentication state
332
332
  - **`useUserProfile`** (`src/presentation/hooks/useUserProfile.ts`) - Profile data
333
- - **`useProfileUpdate`** (`src/presentation/hooks/useProfileUpdate.md`) - Profile editing
333
+ - **`useProfileEdit`** (`src/presentation/hooks/useProfileEdit.ts`) - Profile editing form
334
334
 
335
335
  ## Related Components
336
336
 
@@ -3,7 +3,7 @@
3
3
  * React hook for authentication state management
4
4
  */
5
5
 
6
- import { useCallback, useRef } from "react";
6
+ import { useCallback } from "react";
7
7
  import { useAuthStore } from "../stores/authStore";
8
8
  import {
9
9
  selectUser,
@@ -62,23 +62,12 @@ export function useAuth(): UseAuthResult {
62
62
  const signOutMutation = useSignOutMutation();
63
63
  const anonymousModeMutation = useAnonymousModeMutation();
64
64
 
65
- // Store mutateAsync in refs to avoid recreating callbacks on every render.
66
- // useMutation returns a new object each render, but mutateAsync is stable.
67
- const signUpMutateRef = useRef(signUpMutation.mutateAsync);
68
- signUpMutateRef.current = signUpMutation.mutateAsync;
69
- const signInMutateRef = useRef(signInMutation.mutateAsync);
70
- signInMutateRef.current = signInMutation.mutateAsync;
71
- const signOutMutateRef = useRef(signOutMutation.mutateAsync);
72
- signOutMutateRef.current = signOutMutation.mutateAsync;
73
- const anonymousMutateRef = useRef(anonymousModeMutation.mutateAsync);
74
- anonymousMutateRef.current = anonymousModeMutation.mutateAsync;
75
-
76
65
  const signUp = useCallback(
77
66
  async (email: string, password: string, displayName?: string) => {
78
67
  try {
79
68
  setLoading(true);
80
69
  setError(null);
81
- await signUpMutateRef.current({ email, password, displayName });
70
+ await signUpMutation.mutateAsync({ email, password, displayName });
82
71
  // isAnonymous is automatically derived from firebaseUser by the auth listener
83
72
  } catch (err: unknown) {
84
73
  setError(err instanceof Error ? err.message : "Sign up failed");
@@ -87,7 +76,7 @@ export function useAuth(): UseAuthResult {
87
76
  setLoading(false);
88
77
  }
89
78
  },
90
- [setLoading, setError]
79
+ [setLoading, setError, signUpMutation.mutateAsync]
91
80
  );
92
81
 
93
82
  const signIn = useCallback(
@@ -95,7 +84,7 @@ export function useAuth(): UseAuthResult {
95
84
  try {
96
85
  setLoading(true);
97
86
  setError(null);
98
- await signInMutateRef.current({ email, password });
87
+ await signInMutation.mutateAsync({ email, password });
99
88
  // isAnonymous is automatically derived from firebaseUser by the auth listener
100
89
  } catch (err: unknown) {
101
90
  setError(err instanceof Error ? err.message : "Sign in failed");
@@ -104,27 +93,27 @@ export function useAuth(): UseAuthResult {
104
93
  setLoading(false);
105
94
  }
106
95
  },
107
- [setLoading, setError]
96
+ [setLoading, setError, signInMutation.mutateAsync]
108
97
  );
109
98
 
110
99
  const signOut = useCallback(async () => {
111
100
  try {
112
101
  setLoading(true);
113
102
  setError(null);
114
- await signOutMutateRef.current();
103
+ await signOutMutation.mutateAsync();
115
104
  } catch (err: unknown) {
116
105
  setError(err instanceof Error ? err.message : "Sign out failed");
117
106
  throw err;
118
107
  } finally {
119
108
  setLoading(false);
120
109
  }
121
- }, [setLoading, setError]);
110
+ }, [setLoading, setError, signOutMutation.mutateAsync]);
122
111
 
123
112
  const continueAnonymously = useCallback(async () => {
124
113
  try {
125
114
  setLoading(true);
126
115
  setError(null);
127
- await anonymousMutateRef.current();
116
+ await anonymousModeMutation.mutateAsync();
128
117
  // isAnonymous is automatically derived from firebaseUser by the auth listener
129
118
  } catch (err: unknown) {
130
119
  setError(err instanceof Error ? err.message : "Failed to continue anonymously");
@@ -132,7 +121,7 @@ export function useAuth(): UseAuthResult {
132
121
  } finally {
133
122
  setLoading(false);
134
123
  }
135
- }, [setLoading, setError]);
124
+ }, [setLoading, setError, anonymousModeMutation.mutateAsync]);
136
125
 
137
126
  return {
138
127
  user, userId, userType, loading, isAuthReady, isAnonymous, isAuthenticated, hasFirebaseUser, error,
@@ -1,6 +1,6 @@
1
1
  import { useState, useCallback } from "react";
2
2
  import { useAuth } from "./useAuth";
3
- import { validateLoginForm } from "../utils/form/formValidation.util";
3
+ import { validateLoginForm } from "../utils/form/validation/formValidators";
4
4
  import { alertService } from "@umituz/react-native-design-system/molecules";
5
5
  import { useFormFields } from "../utils/form/useFormField.hook";
6
6
  import { sanitizeEmail } from "../../infrastructure/utils/validation/sanitization";
@@ -79,10 +79,11 @@ export function useLoginForm(config?: UseLoginFormConfig): UseLoginFormResult {
79
79
  );
80
80
 
81
81
  if (!validation.isValid) {
82
- for (const error of validation.errors) {
83
- if (error.field === "email") setEmailError(error.message);
84
- if (error.field === "password") setPasswordError(error.message);
85
- }
82
+ // Collect errors first to avoid potential state update batching issues
83
+ const emailErrorMsg = validation.errors.find(e => e.field === "email")?.message || null;
84
+ const passwordErrorMsg = validation.errors.find(e => e.field === "password")?.message || null;
85
+ setEmailError(emailErrorMsg);
86
+ setPasswordError(passwordErrorMsg);
86
87
  return;
87
88
  }
88
89
 
@@ -38,7 +38,8 @@ export const usePasswordPromptNavigation = (
38
38
  ],
39
39
  })
40
40
  );
41
- } catch {
41
+ } catch (error) {
42
+ console.error('[usePasswordPromptNavigation] Navigation failed:', error);
42
43
  setPasswordPromptCallback(null);
43
44
  resolve(null);
44
45
  }
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { useState, useCallback } from "react";
8
- import { validateProfileForm } from "../utils/form/formValidation.util";
8
+ import { validateProfileForm } from "../utils/form/validation/formValidators";
9
9
 
10
10
  export interface ProfileEditFormState {
11
11
  displayName: string;
@@ -63,7 +63,7 @@ export const useProfileEdit = (
63
63
  displayName: formState.displayName,
64
64
  email: formState.email,
65
65
  },
66
- (key) => key // Pass-through function - returns key as-is since caller handles translation
66
+ key => key // Identity function for translation
67
67
  );
68
68
 
69
69
  return {
@@ -10,10 +10,12 @@ import type { AuthListenerOptions } from "../../types/auth-store.types";
10
10
  import {
11
11
  handleExistingInitialization,
12
12
  handleInitializationInProgress,
13
+ } from "../../infrastructure/utils/listener/cleanupHandlers";
14
+ import { setupAuthListener } from "../../infrastructure/utils/listener/setupListener";
15
+ import {
13
16
  handleNoFirebaseAuth,
14
- setupAuthListener,
15
17
  completeListenerSetup,
16
- } from "../../infrastructure/utils/listener/listenerLifecycle.util";
18
+ } from "../../infrastructure/utils/listener/initializationHandlers";
17
19
  import {
18
20
  startInitialization,
19
21
  isListenerInitialized,
@@ -7,8 +7,8 @@ import { useMemo } from "react";
7
7
  import {
8
8
  validatePasswordForRegister,
9
9
  validatePasswordConfirmation,
10
- type PasswordRequirements,
11
- } from "../../../application/services/ValidationService";
10
+ } from "../../../infrastructure/utils/AuthValidation";
11
+ import type { PasswordRequirements } from "../../../infrastructure/utils/validation/types";
12
12
  import type { PasswordConfig } from "../../../domain/value-objects/AuthConfig";
13
13
 
14
14
  interface UsePasswordValidationResult {
@@ -8,7 +8,7 @@ import {
8
8
  validatePasswordForLogin,
9
9
  validatePasswordForRegister,
10
10
  validatePasswordConfirmation,
11
- } from "../../../../application/services/ValidationService";
11
+ } from "../../../../infrastructure/utils/AuthValidation";
12
12
  import type { PasswordConfig } from "../../../../domain/value-objects/AuthConfig";
13
13
  import type {
14
14
  FormValidationResult,
@@ -1,6 +1,10 @@
1
1
  let callback: ((value: string | null) => void) | null = null;
2
2
 
3
3
  export const setPasswordPromptCallback = (cb: ((value: string | null) => void) | null): void => {
4
+ // Warn if overriding an existing callback (indicates potential bug)
5
+ if (callback && cb) {
6
+ console.warn('[passwordPromptCallback] Overriding existing callback - this may indicate a bug');
7
+ }
4
8
  callback = cb;
5
9
  };
6
10
 
@@ -1,16 +0,0 @@
1
- /**
2
- * Validation Service (Application Layer)
3
- * Facade for validation functions to be used by presentation layer
4
- * Follows DDD architecture - presentation imports from application, not infrastructure
5
- */
6
-
7
- export {
8
- validateEmail,
9
- validatePasswordForLogin,
10
- validatePasswordForRegister,
11
- validatePasswordConfirmation,
12
- } from "../../infrastructure/utils/AuthValidation";
13
-
14
- export type {
15
- PasswordRequirements,
16
- } from "../../infrastructure/utils/validation/types";
@@ -1,19 +0,0 @@
1
- /**
2
- * Auth Listener Lifecycle - Main Export
3
- * Exports all listener lifecycle utilities from modular files
4
- */
5
-
6
- // Cleanup handlers
7
- export {
8
- handleExistingInitialization,
9
- handleInitializationInProgress,
10
- } from "./cleanupHandlers";
11
-
12
- // Setup listener
13
- export { setupAuthListener } from "./setupListener";
14
-
15
- // Initialization handlers
16
- export {
17
- handleNoFirebaseAuth,
18
- completeListenerSetup,
19
- } from "./initializationHandlers";
package/src/init/index.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Auth Init Module
3
- * Provides factory for creating app initialization modules
4
- */
5
-
6
- export { createAuthInitModule } from './createAuthInitModule';
@@ -1,3 +0,0 @@
1
- export { FormEmailInput } from "./FormEmailInput";
2
- export { FormPasswordInput } from "./FormPasswordInput";
3
- export { FormTextInput } from "./FormTextInput";
@@ -1,299 +0,0 @@
1
- # useProfileUpdate & useProfileEdit
2
-
3
- Hooks for profile update operations and profile editing form management.
4
-
5
- ---
6
-
7
- ## useProfileUpdate
8
-
9
- Hook for updating user profile information (display name, photo URL).
10
-
11
- ### Strategy
12
-
13
- **Purpose**: Provides functionality to update user profile data in Firebase Auth and Firestore. Implementation provided by app using Firebase SDK.
14
-
15
- **When to Use**:
16
- - User profile editing screens
17
- - Settings screens with profile updates
18
- - Need to update display name or photo
19
- - Profile modification operations
20
-
21
- **Import Path**:
22
- ```typescript
23
- import { useProfileUpdate } from '@umituz/react-native-auth';
24
- ```
25
-
26
- **Hook Location**: `src/presentation/hooks/useProfileUpdate.ts`
27
-
28
- ### Rules
29
-
30
- **MUST**:
31
- - Validate user is authenticated before updating
32
- - Validate input data before calling update
33
- - Handle loading state during update
34
- - Display error messages on failure
35
- - Update both Firebase Auth and Firestore
36
- - Handle anonymous users appropriately
37
-
38
- **MUST NOT**:
39
- - Allow anonymous users to update profile
40
- - Update profile without validation
41
- - Expose sensitive error details
42
- - Allow partial updates (all-or-nothing)
43
-
44
- ### Constraints
45
-
46
- **PARAMETERS**:
47
- - `displayName?: string` - New display name
48
- - `photoURL?: string` - New profile photo URL
49
-
50
- **OPERATION RULES**:
51
- - Updates Firebase Auth user profile
52
- - Updates Firestore user document
53
- - Transactional (both or none)
54
- - Auto-updates auth state
55
- - Triggers profile listeners
56
-
57
- **LIMITATIONS**:
58
- - Cannot update email (use separate method)
59
- - Cannot update password (use separate method)
60
- - Anonymous users cannot update
61
- - Requires authentication
62
-
63
- **ERROR HANDLING**:
64
- - Validation errors before API call
65
- - Network errors during update
66
- - Permission errors (user not authenticated)
67
- - Firebase errors
68
-
69
- ---
70
-
71
- ## useProfileEdit
72
-
73
- Hook for managing profile editing form state and validation.
74
-
75
- ### Strategy
76
-
77
- **Purpose**: Provides form state management for profile editing with validation and change tracking.
78
-
79
- **When to Use**:
80
- - Profile editing forms
81
- - Settings screens with profile edits
82
- - Need form validation for profile data
83
- - Want to track form modifications
84
-
85
- **Import Path**:
86
- ```typescript
87
- import { useProfileEdit } from '@umituz/react-native-auth';
88
- ```
89
-
90
- **Hook Location**: `src/presentation/hooks/useProfileUpdate.ts`
91
-
92
- ### Rules
93
-
94
- **MUST**:
95
- - Validate form before submission
96
- - Show validation errors to user
97
- - Track form modifications
98
- - Handle email field as read-only
99
- - Provide clear error messages
100
- - Reset form after successful submission
101
-
102
- **MUST NOT**:
103
- - Allow invalid form submission
104
- - Allow email modification (read-only)
105
- - Submit unchanged data
106
- - Clear form without confirmation if modified
107
-
108
- ### Constraints
109
-
110
- **FORM FIELDS**:
111
- - `displayName: string` - Editable
112
- - `email: string` - Read-only
113
- - `photoURL: string | null` - Editable
114
- - `isModified: boolean` - Auto-calculated
115
-
116
- **VALIDATION RULES**:
117
- - Display name: Cannot be empty
118
- - Email: Valid format (if provided)
119
- - Photo URL: Valid URL format (if provided)
120
-
121
- **RETURNED FUNCTIONS**:
122
- - `setDisplayName: (value: string) => void`
123
- - `setEmail: (value: string) => void`
124
- - `setPhotoURL: (value: string | null) => void`
125
- - `resetForm: (initial: Partial<ProfileEditFormState>) => void`
126
- - `validateForm: () => { isValid: boolean; errors: string[] }`
127
-
128
- **CHANGE TRACKING**:
129
- - `isModified` automatically calculated
130
- - Compares current vs initial values
131
- - Triggers re-calculation on any change
132
- - Used to enable/disable save button
133
-
134
- ---
135
-
136
- ## Validation Strategy
137
-
138
- ### Strategy
139
-
140
- **Purpose**: Ensure profile data meets requirements before submission.
141
-
142
- **Rules**:
143
- - MUST validate all fields before submission
144
- - MUST show clear error messages
145
- - MUST prevent invalid submissions
146
- - MUST provide real-time validation feedback
147
-
148
- **MUST NOT**:
149
- - Allow empty display names
150
- - Accept invalid email formats
151
- - Submit with validation errors
152
- - Hide validation errors
153
-
154
- ### Constraints
155
-
156
- **DISPLAY NAME VALIDATION**:
157
- - Required field
158
- - Minimum length: 1 character
159
- - Maximum length: 100 characters
160
- - No special character restrictions
161
-
162
- **EMAIL VALIDATION**:
163
- - Valid email format required
164
- - Read-only field (cannot change)
165
- - Must match Firebase user email
166
- - Used for display only
167
-
168
- **PHOTO URL VALIDATION**:
169
- - Optional field
170
- - Must be valid URL if provided
171
- - Supports HTTP, HTTPS URLs
172
- - Can be cleared (set to null)
173
-
174
- **VALIDATION TIMING**:
175
- - Real-time validation on input
176
- - Final validation on submit
177
- - Clear errors on correction
178
- - Error messages localized
179
-
180
- ---
181
-
182
- ## Anonymous User Handling
183
-
184
- ### Strategy
185
-
186
- **Purpose**: Prevent profile updates from anonymous users.
187
-
188
- **Rules**:
189
- - MUST check user is not anonymous
190
- - MUST hide profile edit for anonymous users
191
- - MUST show upgrade prompt instead
192
- - MUST NOT allow anonymous profile updates
193
-
194
- **Constraints**:
195
- - Anonymous users cannot update profile
196
- - Show "Create account" prompt
197
- - Guide to registration
198
- - Preserve anonymous data during upgrade
199
-
200
- ---
201
-
202
- ## Error Handling
203
-
204
- ### Strategy
205
-
206
- **Purpose**: Graceful handling of profile update failures.
207
-
208
- **Rules**:
209
- - MUST catch all errors during update
210
- - MUST show user-friendly error messages
211
- - MUST allow retry after failures
212
- - MUST not lose form data on error
213
-
214
- **MUST NOT**:
215
- - Show raw error messages
216
- - Crash on update failures
217
- - Lose user input on errors
218
- - Block retry attempts
219
-
220
- ### Constraints
221
-
222
- **ERROR TYPES**:
223
- - Validation errors: Before API call
224
- - Network errors: During update
225
- - Permission errors: Not authenticated
226
- - Firebase errors: From service
227
-
228
- **ERROR RECOVERY**:
229
- - Keep form data on error
230
- - Allow user to retry
231
- - Clear errors on new input
232
- - Show retry button
233
-
234
- ---
235
-
236
- ## Performance Optimization
237
-
238
- ### Strategy
239
-
240
- **Purpose**: Efficient form state management and updates.
241
-
242
- **Rules**:
243
- - MUST minimize unnecessary re-renders
244
- - MUST debounce validation if expensive
245
- - MUST optimize form state updates
246
- - MUST prevent excessive recalculations
247
-
248
- **Constraints**:
249
- - Form state in local component
250
- - Efficient validation checks
251
- - Minimal prop drilling
252
- - Optimized re-render triggers
253
-
254
- ---
255
-
256
- ## Security Considerations
257
-
258
- ### Strategy
259
-
260
- **Purpose**: Secure profile data updates.
261
-
262
- **Rules**:
263
- - MUST validate user owns profile
264
- - MUST sanitize input data
265
- - MUST use secure upload for photos
266
- - MUST not expose sensitive data
267
-
268
- **MUST NOT**:
269
- - Allow cross-user profile updates
270
- - Accept unvalidated photo URLs
271
- - Expose user IDs in errors
272
- - Log profile data with sensitive info
273
-
274
- ### Constraints
275
-
276
- **PERMISSION CHECKS**:
277
- - User can only update own profile
278
- - Firebase security rules enforce
279
- - Server-side validation required
280
- - Token-based authentication
281
-
282
- **DATA SANITIZATION**:
283
- - Trim whitespace from names
284
- - Validate URL formats
285
- - Escape special characters
286
- - Prevent XSS attacks
287
-
288
- ---
289
-
290
- ## Related Hooks
291
-
292
- - **`useAuth`** (`src/presentation/hooks/useAuth.ts`) - Authentication state
293
- - **`useUserProfile`** (`src/presentation/hooks/useUserProfile.ts`) - Profile display data
294
- - **`useAccountManagement`** (`src/presentation/hooks/useAccountManagement.md`) - Account operations
295
-
296
- ## Related Components
297
-
298
- - **`ProfileSection`** (`src/presentation/components/ProfileComponents.md`) - Profile display
299
- - **`EditProfileForm`** (`src/presentation/components/ProfileComponents.md`) - Profile editing UI
@@ -1,14 +0,0 @@
1
- /**
2
- * Form Validation - Main Export
3
- * Exports all form validation utilities
4
- */
5
-
6
- // Validators
7
- export {
8
- validateLoginForm,
9
- validateRegisterForm,
10
- validateProfileForm,
11
- } from "./validation/formValidators";
12
-
13
- // Utilities
14
- export { errorsToFieldErrors } from "./validation/formValidation.utils";