@umituz/react-native-auth 3.4.32 → 3.4.33

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.
@@ -6,322 +6,294 @@ Hooks for profile update operations and profile editing form management.
6
6
 
7
7
  ## useProfileUpdate
8
8
 
9
- Hook for profile update operations. Implementation should be provided by the app using Firebase SDK or backend API.
9
+ Hook for updating user profile information (display name, photo URL).
10
10
 
11
- ### Usage
11
+ ### Strategy
12
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**:
13
22
  ```typescript
14
23
  import { useProfileUpdate } from '@umituz/react-native-auth';
24
+ ```
15
25
 
16
- function ProfileSettings() {
17
- const { updateProfile, isUpdating, error } = useProfileUpdate();
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
18
68
 
19
- const handleUpdate = async (data: UpdateProfileParams) => {
20
- try {
21
- await updateProfile(data);
22
- } catch (err) {
23
- console.error(err);
24
- }
25
- };
69
+ ---
26
70
 
27
- return <ProfileForm onSave={handleUpdate} />;
28
- }
29
- ```
71
+ ## useProfileEdit
30
72
 
31
- ### API
73
+ Hook for managing profile editing form state and validation.
32
74
 
33
- | Prop | Type | Description |
34
- |------|------|-------------|
35
- | `updateProfile` | `(params: UpdateProfileParams) => Promise<void>` | Profile update function |
36
- | `isUpdating` | `boolean` | Update in progress |
37
- | `error` | `string \| null` | Error message |
75
+ ### Strategy
38
76
 
39
- ### Create Your Own Implementation
77
+ **Purpose**: Provides form state management for profile editing with validation and change tracking.
40
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**:
41
86
  ```typescript
42
- function useProfileUpdate() {
43
- const { user } = useAuth();
44
- const [isUpdating, setIsUpdating] = useState(false);
45
- const [error, setError] = useState<string | null>(null);
46
-
47
- const updateProfile = async (params: UpdateProfileParams) => {
48
- if (!user) {
49
- throw new Error("No user logged in");
50
- }
51
-
52
- if (user.isAnonymous) {
53
- throw new Error("Anonymous users cannot update profile");
54
- }
55
-
56
- setIsUpdating(true);
57
- setError(null);
58
-
59
- try {
60
- // Update profile in Firebase Auth
61
- await updateProfile(user, {
62
- displayName: params.displayName,
63
- photoURL: params.photoURL,
64
- });
65
-
66
- // Update user document in Firestore
67
- await updateDoc(doc(db, 'users', user.uid), {
68
- displayName: params.displayName,
69
- photoURL: params.photoURL,
70
- updatedAt: serverTimestamp(),
71
- });
72
- } catch (err) {
73
- const message = err instanceof Error ? err.message : 'Update failed';
74
- setError(message);
75
- throw err;
76
- } finally {
77
- setIsUpdating(false);
78
- }
79
- };
80
-
81
- return { updateProfile, isUpdating, error };
82
- }
87
+ import { useProfileEdit } from '@umituz/react-native-auth';
83
88
  ```
84
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
+
85
134
  ---
86
135
 
87
- ## useProfileEdit
136
+ ## Validation Strategy
88
137
 
89
- Hook for simple profile editing with form state management.
138
+ ### Strategy
90
139
 
91
- ### Usage
140
+ **Purpose**: Ensure profile data meets requirements before submission.
92
141
 
93
- ```typescript
94
- import { useProfileEdit } from '@umituz/react-native-auth';
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
95
147
 
96
- function EditProfileScreen({ navigation }) {
97
- const {
98
- formState,
99
- setDisplayName,
100
- setEmail,
101
- setPhotoURL,
102
- resetForm,
103
- validateForm,
104
- } = useProfileEdit({
105
- displayName: user?.displayName || '',
106
- email: user?.email || '',
107
- photoURL: user?.photoURL || null,
108
- });
109
-
110
- const handleSave = () => {
111
- const { isValid, errors } = validateForm();
112
-
113
- if (!isValid) {
114
- Alert.alert('Error', errors.join('\n'));
115
- return;
116
- }
117
-
118
- updateProfile({
119
- displayName: formState.displayName,
120
- photoURL: formState.photoURL,
121
- });
122
-
123
- navigation.goBack();
124
- };
125
-
126
- return (
127
- <ScrollView>
128
- <TextInput
129
- value={formState.displayName}
130
- onChangeText={setDisplayName}
131
- placeholder="Full Name"
132
- />
133
-
134
- <TextInput
135
- value={formState.email}
136
- onChangeText={setEmail}
137
- placeholder="Email"
138
- editable={false}
139
- />
140
-
141
- <AvatarUploader
142
- photoURL={formState.photoURL}
143
- onImageSelected={setPhotoURL}
144
- />
145
-
146
- <View style={styles.buttons}>
147
- <Button onPress={navigation.goBack}>Cancel</Button>
148
- <Button
149
- onPress={handleSave}
150
- disabled={!formState.isModified}
151
- >
152
- Save
153
- </Button>
154
- </View>
155
- </ScrollView>
156
- );
157
- }
158
- ```
148
+ **MUST NOT**:
149
+ - Allow empty display names
150
+ - Accept invalid email formats
151
+ - Submit with validation errors
152
+ - Hide validation errors
159
153
 
160
- ### API
154
+ ### Constraints
161
155
 
162
- #### Return Value
156
+ **DISPLAY NAME VALIDATION**:
157
+ - Required field
158
+ - Minimum length: 1 character
159
+ - Maximum length: 100 characters
160
+ - No special character restrictions
163
161
 
164
- | Prop | Type | Description |
165
- |------|------|-------------|
166
- | `formState` | `ProfileEditFormState` | Form state |
167
- | `setDisplayName` | `(value: string) => void` | Set display name |
168
- | `setEmail` | `(value: string) => void` | Set email |
169
- | `setPhotoURL` | `(value: string \| null) => void` | Set photo URL |
170
- | `resetForm` | `(initial: Partial<ProfileEditFormState>) => void` | Reset form |
171
- | `validateForm` | `() => { isValid: boolean; errors: string[] }` | Validate form |
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
172
167
 
173
- #### ProfileEditFormState
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)
174
173
 
175
- | Prop | Type | Description |
176
- |------|------|-------------|
177
- | `displayName` | `string` | Display name |
178
- | `email` | `string` | Email |
179
- | `photoURL` | `string \| null` | Photo URL |
180
- | `isModified` | `boolean` | Form has been modified |
174
+ **VALIDATION TIMING**:
175
+ - Real-time validation on input
176
+ - Final validation on submit
177
+ - Clear errors on correction
178
+ - Error messages localized
181
179
 
182
- ### Validation
180
+ ---
183
181
 
184
- `validateForm()` checks:
182
+ ## Anonymous User Handling
185
183
 
186
- - **Display name**: Cannot be empty
187
- - **Email**: Valid email format (if provided)
184
+ ### Strategy
188
185
 
189
- ```typescript
190
- const { isValid, errors } = validateForm();
186
+ **Purpose**: Prevent profile updates from anonymous users.
191
187
 
192
- if (!isValid) {
193
- errors.forEach(error => console.log(error));
194
- // ["Display name is required", "Invalid email format"]
195
- }
196
- ```
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
197
193
 
198
- ## Examples
194
+ **Constraints**:
195
+ - Anonymous users cannot update profile
196
+ - Show "Create account" prompt
197
+ - Guide to registration
198
+ - Preserve anonymous data during upgrade
199
199
 
200
- ### Profile Photo Upload
200
+ ---
201
201
 
202
- ```typescript
203
- function ProfilePhotoSection() {
204
- const { formState, setPhotoURL } = useProfileEdit(initialState);
205
-
206
- const handlePickImage = async () => {
207
- const result = await launchImageLibrary({
208
- mediaType: 'photo',
209
- quality: 0.8,
210
- });
211
-
212
- if (result.assets?.[0]) {
213
- // Upload to storage and get URL
214
- const url = await uploadToStorage(result.assets[0].uri);
215
- setPhotoURL(url);
216
- }
217
- };
218
-
219
- return (
220
- <TouchableOpacity onPress={handlePickImage}>
221
- {formState.photoURL ? (
222
- <Image source={{ uri: formState.photoURL }} />
223
- ) : (
224
- <View style={styles.placeholder}>
225
- <Text>Select Photo</Text>
226
- </View>
227
- )}
228
- </TouchableOpacity>
229
- );
230
- }
231
- ```
202
+ ## Error Handling
232
203
 
233
- ### Unsaved Changes Warning
204
+ ### Strategy
234
205
 
235
- ```typescript
236
- function EditProfileScreen({ navigation }) {
237
- const {
238
- formState,
239
- resetForm,
240
- validateForm
241
- } = useProfileEdit(initialState);
242
-
243
- useEffect(() => {
244
- const unsubscribe = navigation.addListener('beforeRemove', (e) => {
245
- if (!formState.isModified) {
246
- return;
247
- }
248
-
249
- e.preventDefault();
250
-
251
- Alert.alert(
252
- 'Unsaved Changes',
253
- 'You have unsaved changes. What would you like to do?',
254
- [
255
- { text: 'Don\'t Save', style: 'cancel' },
256
- {
257
- text: 'Save',
258
- onPress: () => {
259
- saveChanges();
260
- navigation.dispatch(e.data.action);
261
- }
262
- },
263
- {
264
- text: 'Discard',
265
- style: 'destructive',
266
- onPress: () => {
267
- resetForm(initialState);
268
- navigation.dispatch(e.data.action);
269
- }
270
- },
271
- ]
272
- );
273
- });
274
-
275
- return unsubscribe;
276
- }, [navigation, formState.isModified]);
277
-
278
- // ...
279
- }
280
- ```
206
+ **Purpose**: Graceful handling of profile update failures.
281
207
 
282
- ### Custom Validation
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
283
213
 
284
- ```typescript
285
- function ExtendedProfileEdit() {
286
- const {
287
- formState,
288
- setDisplayName,
289
- setEmail,
290
- setPhotoURL,
291
- validateForm
292
- } = useProfileEdit(initialState);
293
-
294
- const handleSave = () => {
295
- // Base validation
296
- const { isValid, errors } = validateForm();
297
-
298
- // Custom validation
299
- const customErrors = [];
300
-
301
- if (formState.displayName.length < 3) {
302
- customErrors.push('Display name must be at least 3 characters');
303
- }
304
-
305
- if (formState.photoURL && !isValidImageUrl(formState.photoURL)) {
306
- customErrors.push('Invalid image URL');
307
- }
308
-
309
- const allErrors = [...errors, ...customErrors];
310
-
311
- if (allErrors.length > 0) {
312
- Alert.alert('Error', allErrors.join('\n'));
313
- return;
314
- }
315
-
316
- saveProfile();
317
- };
318
-
319
- // ...
320
- }
321
- ```
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
+ ---
322
289
 
323
290
  ## Related Hooks
324
291
 
325
- - [`useUserProfile`](./useUserProfile.md) - Display profile data
326
- - [`useAuth`](./useAuth.md) - Main auth state management
327
- - [`useAccountManagement`](./useAccountManagement.md) - Account operations
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