@umituz/react-native-auth 3.4.32 → 3.4.34

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 (30) hide show
  1. package/README.md +347 -348
  2. package/package.json +2 -3
  3. package/src/application/README.md +323 -442
  4. package/src/domain/ConfigAndErrors.md +296 -431
  5. package/src/domain/README.md +361 -210
  6. package/src/domain/entities/AuthUser.md +231 -372
  7. package/src/domain/entities/UserProfile.md +271 -441
  8. package/src/index.ts +35 -0
  9. package/src/infrastructure/README.md +388 -444
  10. package/src/infrastructure/services/README.md +386 -312
  11. package/src/infrastructure/utils/validation/BaseValidators.ts +35 -0
  12. package/src/infrastructure/utils/validation/CollectionValidators.ts +56 -0
  13. package/src/infrastructure/utils/validation/DateValidators.ts +63 -0
  14. package/src/infrastructure/utils/validation/FormValidators.ts +22 -0
  15. package/src/infrastructure/utils/validation/NumberValidators.ts +55 -0
  16. package/src/infrastructure/utils/validation/StringValidators.ts +55 -0
  17. package/src/infrastructure/utils/validation/sanitization.ts +98 -0
  18. package/src/infrastructure/utils/validation/types.ts +15 -0
  19. package/src/presentation/README.md +631 -563
  20. package/src/presentation/components/ProfileComponents.md +307 -504
  21. package/src/presentation/components/README.md +254 -92
  22. package/src/presentation/hooks/README.md +247 -83
  23. package/src/presentation/hooks/useAccountManagement.md +295 -344
  24. package/src/presentation/hooks/useAuth.md +271 -227
  25. package/src/presentation/hooks/useAuthBottomSheet.md +417 -367
  26. package/src/presentation/hooks/useAuthRequired.md +308 -194
  27. package/src/presentation/hooks/useProfileUpdate.md +251 -279
  28. package/src/presentation/hooks/useSocialLogin.md +312 -287
  29. package/src/presentation/hooks/useUserProfile.md +259 -192
  30. package/src/presentation/screens/README.md +151 -153
@@ -1,443 +1,273 @@
1
1
  # UserProfile Entity
2
2
 
3
- Kullanıcı profili entity'si. Firestore'da saklanan kullanıcı bilgilerini temsil eder.
4
-
5
- ## Tip Tanımları
6
-
7
- ```typescript
8
- import type { UserProfile, UpdateProfileParams } from '@umituz/react-native-auth';
9
-
10
- interface UserProfile {
11
- uid: string; // Kullanıcı ID'si
12
- email: string | null; // Email adresi
13
- displayName: string | null; // Görünen ad
14
- photoURL: string | null; // Profil fotoğrafı URL'si
15
- isAnonymous: boolean; // Anonymous kullanıcı mı
16
- createdAt: Date | null; // Hesap oluşturma tarihi
17
- lastLoginAt: Date | null; // Son giriş tarihi
18
- }
19
-
20
- interface UpdateProfileParams {
21
- displayName?: string; // Yeni görünen ad
22
- photoURL?: string; // Yeni profil fotoğrafı URL'si
23
- }
24
- ```
25
-
26
- ## Örnekler
27
-
28
- ### Tam Profil
29
-
30
- ```typescript
31
- const fullProfile: UserProfile = {
32
- uid: 'user-123',
33
- email: 'john@example.com',
34
- displayName: 'John Doe',
35
- photoURL: 'https://example.com/avatar.jpg',
36
- isAnonymous: false,
37
- createdAt: new Date('2024-01-01'),
38
- lastLoginAt: new Date('2024-01-15'),
39
- };
40
- ```
41
-
42
- ### Minimal Profil
43
-
44
- ```typescript
45
- const minimalProfile: UserProfile = {
46
- uid: 'user-456',
47
- email: 'jane@example.com',
48
- displayName: null,
49
- photoURL: null,
50
- isAnonymous: false,
51
- createdAt: null,
52
- lastLoginAt: null,
53
- };
54
- ```
55
-
56
- ### Anonymous Profil
57
-
58
- ```typescript
59
- const anonymousProfile: UserProfile = {
60
- uid: 'anon-789',
61
- email: null,
62
- displayName: null,
63
- photoURL: null,
64
- isAnonymous: true,
65
- createdAt: new Date(),
66
- lastLoginAt: new Date(),
67
- };
68
- ```
69
-
70
- ## Kullanım
71
-
72
- ### Profil Oluşturma
73
-
74
- ```typescript
75
- import { doc, setDoc, serverTimestamp } from 'firebase/firestore';
76
- import type { UserProfile } from '@umituz/react-native-auth';
77
-
78
- async function createUserProfile(uid: string, email: string): Promise<void> {
79
- const profile: UserProfile = {
80
- uid,
81
- email,
82
- displayName: null,
83
- photoURL: null,
84
- isAnonymous: false,
85
- createdAt: new Date(),
86
- lastLoginAt: new Date(),
87
- };
88
-
89
- await setDoc(doc(db, 'users', uid), {
90
- ...profile,
91
- createdAt: serverTimestamp(),
92
- lastLoginAt: serverTimestamp(),
93
- });
94
- }
95
- ```
96
-
97
- ### Profil Güncelleme
98
-
99
- ```typescript
100
- import { doc, updateDoc } from 'firebase/firestore';
101
- import type { UpdateProfileParams } from '@umituz/react-native-auth';
102
-
103
- async function updateUserProfile(
104
- uid: string,
105
- updates: UpdateProfileParams
106
- ): Promise<void> {
107
- const updateData: any = {};
108
-
109
- if (updates.displayName !== undefined) {
110
- updateData.displayName = updates.displayName;
111
- }
112
-
113
- if (updates.photoURL !== undefined) {
114
- updateData.photoURL = updates.photoURL;
115
- }
116
-
117
- updateData.updatedAt = serverTimestamp();
118
-
119
- await updateDoc(doc(db, 'users', uid), updateData);
120
- }
121
-
122
- // Kullanım
123
- await updateUserProfile('user-123', {
124
- displayName: 'Jane Smith',
125
- photoURL: 'https://example.com/new-avatar.jpg',
126
- });
127
- ```
128
-
129
- ### Profil Okuma
130
-
131
- ```typescript
132
- import { doc, getDoc } from 'firebase/firestore';
133
- import type { UserProfile } from '@umituz/react-native-auth';
134
-
135
- async function getUserProfile(uid: string): Promise<UserProfile | null> {
136
- const docRef = doc(db, 'users', uid);
137
- const docSnap = await getDoc(docRef);
138
-
139
- if (!docSnap.exists()) {
140
- return null;
141
- }
142
-
143
- const data = docSnap.data();
144
-
145
- return {
146
- uid: data.uid,
147
- email: data.email,
148
- displayName: data.displayName,
149
- photoURL: data.photoURL,
150
- isAnonymous: data.isAnonymous,
151
- createdAt: data.createdAt?.toDate() || null,
152
- lastLoginAt: data.lastLoginAt?.toDate() || null,
153
- };
154
- }
155
- ```
156
-
157
- ### AuthUser'dan UserProfile'a Dönüşüm
158
-
159
- ```typescript
160
- import type { AuthUser, UserProfile } from '@umituz/react-native-auth';
161
-
162
- function authUserToProfile(authUser: AuthUser): UserProfile {
163
- return {
164
- uid: authUser.uid,
165
- email: authUser.email,
166
- displayName: authUser.displayName,
167
- photoURL: authUser.photoURL,
168
- isAnonymous: authUser.isAnonymous,
169
- createdAt: null, // Firestore'dan gelecek
170
- lastLoginAt: new Date(),
171
- };
172
- }
173
- ```
174
-
175
- ## Validasyon
176
-
177
- ### DisplayName Validasyonu
178
-
179
- ```typescript
180
- function validateDisplayName(displayName: string): {
181
- valid: boolean;
182
- error?: string;
183
- } {
184
- if (displayName.length < 2) {
185
- return { valid: false, error: 'Display name en az 2 karakter olmalı' };
186
- }
187
-
188
- if (displayName.length > 50) {
189
- return { valid: false, error: 'Display name en fazla 50 karakter olabilir' };
190
- }
191
-
192
- return { valid: true };
193
- }
194
-
195
- // Kullanım
196
- const result = validateDisplayName('John');
197
- if (!result.valid) {
198
- console.error(result.error);
199
- }
200
- ```
201
-
202
- ### PhotoURL Validasyonu
203
-
204
- ```typescript
205
- function validatePhotoURL(url: string): {
206
- valid: boolean;
207
- error?: string;
208
- } {
209
- try {
210
- const parsed = new URL(url);
211
-
212
- if (!['http:', 'https:'].includes(parsed.protocol)) {
213
- return { valid: false, error: 'URL http veya https olmalı' };
214
- }
215
-
216
- // Image file extension kontrolü
217
- const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
218
- const hasImageExtension = imageExtensions.some(ext =>
219
- parsed.pathname.toLowerCase().endsWith(ext)
220
- );
221
-
222
- if (!hasImageExtension) {
223
- return { valid: false, error: 'Geçersiz resim formatı' };
224
- }
225
-
226
- return { valid: true };
227
- } catch {
228
- return { valid: false, error: 'Geçersiz URL' };
229
- }
230
- }
231
- ```
232
-
233
- ### Update Params Validasyonu
234
-
235
- ```typescript
236
- function validateUpdateParams(params: UpdateProfileParams): {
237
- valid: boolean;
238
- errors: string[];
239
- } {
240
- const errors: string[] = [];
241
-
242
- if (params.displayName !== undefined) {
243
- const nameResult = validateDisplayName(params.displayName);
244
- if (!nameResult.valid) {
245
- errors.push(nameResult.error!);
246
- }
247
- }
248
-
249
- if (params.photoURL !== undefined) {
250
- const photoResult = validatePhotoURL(params.photoURL);
251
- if (!photoResult.valid) {
252
- errors.push(photoResult.error!);
253
- }
254
- }
255
-
256
- return {
257
- valid: errors.length === 0,
258
- errors,
259
- };
260
- }
261
- ```
262
-
263
- ## Profil Photo Yükleme
264
-
265
- ### Firebase Storage ile Profil Fotoğrafı Yükleme
266
-
267
- ```typescript
268
- import { ref, uploadBytes, getDownloadURL } from 'firebase/storage';
269
- import * as ImagePicker from 'expo-image-picker';
270
-
271
- async function uploadProfilePhoto(
272
- uid: string,
273
- uri: string
274
- ): Promise<string> {
275
- // Dosyayı blob'a çevir
276
- const response = await fetch(uri);
277
- const blob = await response.blob();
278
-
279
- // Storage referansı oluştur
280
- const storageRef = ref(storage, `avatars/${uid}/${Date.now()}.jpg`);
281
-
282
- // Yükle
283
- await uploadBytes(storageRef, blob);
284
-
285
- // URL al
286
- const downloadURL = await getDownloadURL(storageRef);
287
-
288
- return downloadURL;
289
- }
290
-
291
- // Kullanım
292
- async function handleProfilePhotoUpload(uid: string) {
293
- // Resim seç
294
- const result = await ImagePicker.launchImageLibraryAsync({
295
- mediaTypes: ['images'],
296
- allowsEditing: true,
297
- aspect: [1, 1],
298
- quality: 0.8,
299
- });
300
-
301
- if (result.canceled) {
302
- return;
303
- }
304
-
305
- // Yükle
306
- const photoURL = await uploadProfilePhoto(uid, result.assets[0].uri);
307
-
308
- // Profili güncelle
309
- await updateUserProfile(uid, { photoURL });
310
- }
311
- ```
312
-
313
- ## Profil Tamamlama Kontrolü
314
-
315
- ```typescript
316
- function isProfileComplete(profile: UserProfile): boolean {
317
- return !!(
318
- profile.displayName &&
319
- profile.email &&
320
- profile.photoURL
321
- );
322
- }
323
-
324
- function getProfileCompleteness(profile: UserProfile): {
325
- percentage: number;
326
- missing: string[];
327
- } {
328
- const required: Array<keyof UserProfile> = [
329
- 'displayName',
330
- 'email',
331
- 'photoURL',
332
- ];
333
-
334
- const completed = required.filter(field => !!profile[field]);
335
- const percentage = (completed.length / required.length) * 100;
336
-
337
- const missing = required.filter(field => !profile[field]);
338
-
339
- return { percentage, missing };
340
- }
341
-
342
- // Kullanım
343
- const completeness = getProfileCompleteness(profile);
344
- console.log(`Profil %${completeness.percentage} tamamlandı`);
345
- console.log('Eksik:', completeness.missing); // ['displayName', 'photoURL']
346
- ```
347
-
348
- ## Profil İsim Görüntüleme
349
-
350
- ```typescript
351
- function getProfileDisplayName(profile: UserProfile): string {
352
- if (profile.displayName) {
353
- return profile.displayName;
354
- }
355
-
356
- if (profile.email) {
357
- const emailName = profile.email.split('@')[0];
358
- return emailName.charAt(0).toUpperCase() + emailName.slice(1);
359
- }
360
-
361
- if (profile.isAnonymous) {
362
- return 'Misafir';
363
- }
364
-
365
- return 'Kullanıcı';
366
- }
367
-
368
- function getProfileInitials(profile: UserProfile): string {
369
- if (profile.displayName) {
370
- const names = profile.displayName.trim().split(' ');
371
- if (names.length >= 2) {
372
- return (names[0][0] + names[names.length - 1][0]).toUpperCase();
373
- }
374
- return names[0][0].toUpperCase();
375
- }
376
-
377
- if (profile.email) {
378
- return profile.email[0].toUpperCase();
379
- }
380
-
381
- return '?';
382
- }
383
- ```
384
-
385
- ## Profil Meta Verileri
386
-
387
- ### Extra Fields Ekleme
388
-
389
- ```typescript
390
- interface ExtendedUserProfile extends UserProfile {
391
- bio?: string;
392
- location?: string;
393
- website?: string;
394
- phoneNumber?: string;
395
- dateOfBirth?: Date;
396
- gender?: 'male' | 'female' | 'other' | 'prefer_not_to_say';
397
- preferences?: {
398
- newsletter: boolean;
399
- notifications: boolean;
400
- language: string;
401
- };
402
- }
403
-
404
- // Kullanım
405
- const extendedProfile: ExtendedUserProfile = {
406
- ...baseProfile,
407
- bio: 'Software developer',
408
- location: 'Istanbul, Turkey',
409
- website: 'https://johndoe.com',
410
- preferences: {
411
- newsletter: true,
412
- notifications: true,
413
- language: 'tr',
414
- },
415
- };
416
- ```
417
-
418
- ## Firestore Index'leri
419
-
420
- ```json
421
- {
422
- "indexes": [
423
- {
424
- "collectionGroup": "users",
425
- "queryScope": "COLLECTION",
426
- "fields": [
427
- { "fieldPath": "displayName", "order": "ASCENDING" },
428
- { "fieldPath": "createdAt", "order": "DESCENDING" }
429
- ]
430
- }
431
- ]
432
- }
433
- ```
434
-
435
- ## İlgili Entity'ler
436
-
437
- - **[`AuthUser`](./AuthUser.md)** - Authentication kullanıcı entity'si
438
- - **[`UpdateProfileParams`](#tip-tanımları)** - Profil güncelleme parametreleri
439
-
440
- ## İlgili Hook'lar
441
-
442
- - **[`useUserProfile`](../../presentation/hooks/useUserProfile.md)** - Profil verileri hook'u
443
- - **[`useProfileUpdate`](../../presentation/hooks/useProfileUpdate.md)** - Profil güncelleme hook'u
3
+ User profile entity for Firestore document storage.
4
+
5
+ ---
6
+
7
+ ## Strategy
8
+
9
+ **Purpose**: Represents user profile data stored in Firestore. Contains display information, metadata, and profile settings.
10
+
11
+ **When to Use**:
12
+ - Storing user profile data
13
+ - Displaying user information
14
+ - Profile management operations
15
+ - User metadata tracking
16
+
17
+ **Location**: `src/domain/entities/UserProfile.ts`
18
+
19
+ ---
20
+
21
+ ## Type Definition
22
+
23
+ ### UserProfile Interface
24
+
25
+ **PROPERTIES**:
26
+ - `uid: string` - User ID
27
+ - `email: string | null` - Email address
28
+ - `displayName: string | null` - Display name
29
+ - `photoURL: string | null` - Profile photo URL
30
+ - `isAnonymous: boolean` - Anonymous flag
31
+ - `createdAt: Date | null` - Account creation date
32
+ - `lastLoginAt: Date | null` - Last login timestamp
33
+
34
+ ### UpdateProfileParams
35
+
36
+ **PROPERTIES**:
37
+ - `displayName?: string` - New display name
38
+ - `photoURL?: string` - New photo URL
39
+
40
+ **Rules**:
41
+ - MUST provide at least one field
42
+ - MUST validate updates before saving
43
+ - MUST handle partial updates
44
+
45
+ **Constraints**:
46
+ - Optional fields
47
+ - Only provided fields updated
48
+ - Validation applies
49
+
50
+ ---
51
+
52
+ ## Profile States
53
+
54
+ ### Complete Profile
55
+
56
+ **CHARACTERISTICS**:
57
+ - Has displayName
58
+ - Has email
59
+ - Has photoURL
60
+ - Not anonymous
61
+
62
+ **Rules**:
63
+ - SHOULD encourage completion
64
+ - MAY require for features
65
+ - MUST validate updates
66
+
67
+ ---
68
+
69
+ ### Minimal Profile
70
+
71
+ **CHARACTERISTICS**:
72
+ - May have null displayName
73
+ - Has email
74
+ - May not have photoURL
75
+ - Not anonymous
76
+
77
+ **Rules**:
78
+ - MUST have email
79
+ - CAN be incomplete
80
+ - SHOULD encourage completion
81
+
82
+ ---
83
+
84
+ ### Anonymous Profile
85
+
86
+ **CHARACTERISTICS**:
87
+ - isAnonymous = true
88
+ - Null email
89
+ - Null displayName
90
+ - Null photoURL
91
+
92
+ **Rules**:
93
+ - MUST treat as temporary
94
+ - SHOULD encourage upgrade
95
+ - MUST offer registration
96
+
97
+ ---
98
+
99
+ ## Profile Operations
100
+
101
+ ### Creation
102
+
103
+ **RULES**:
104
+ - MUST create on user registration
105
+ - MUST include uid
106
+ - MUST set initial timestamps
107
+ - MUST NOT delete existing profiles
108
+
109
+ **CONSTRAINTS**:
110
+ - One profile per uid
111
+ - Created in Firestore
112
+ - Auto-generated timestamps
113
+
114
+ ---
115
+
116
+ ### Updates
117
+
118
+ **RULES**:
119
+ - MUST validate input data
120
+ - MUST update updatedAt timestamp
121
+ - MUST preserve existing data
122
+ - MUST handle concurrent updates
123
+
124
+ **CONSTRAINTS**:
125
+ - Partial updates supported
126
+ - Fields not provided unchanged
127
+ - Validation required
128
+
129
+ ---
130
+
131
+ ### Deletion
132
+
133
+ **RULES**:
134
+ - MUST mark as deleted (not actual delete)
135
+ - MAY retain data for grace period
136
+ - MUST handle cleanup properly
137
+ - MUST be reversible (initially)
138
+
139
+ **CONSTRAINTS**:
140
+ - Soft delete recommended
141
+ - May have retention period
142
+ - Permanent delete after period
143
+
144
+ ---
145
+
146
+ ## Validation
147
+
148
+ ### Display Name Validation
149
+
150
+ **RULES**:
151
+ - MUST be 2-50 characters if provided
152
+ - MUST not contain only spaces
153
+ - SHOULD trim whitespace
154
+ - MAY allow special characters
155
+
156
+ **CONSTRAINTS**:
157
+ - Minimum length: 2 characters
158
+ - Maximum length: 100 characters
159
+ - Cannot be only whitespace
160
+
161
+ ---
162
+
163
+ ### Photo URL Validation
164
+
165
+ **RULES**:
166
+ - MUST be valid URL if provided
167
+ - MUST use HTTP or HTTPS
168
+ - SHOULD point to image file
169
+ - MUST be accessible
170
+
171
+ **CONSTRAINTS**:
172
+ - Valid URL format required
173
+ - HTTP or HTTPS protocol
174
+ - Image file extension preferred
175
+
176
+ ---
177
+
178
+ ## Profile Completeness
179
+
180
+ ### Completeness Calculation
181
+
182
+ **FACTORS**:
183
+ - displayName presence
184
+ - email presence
185
+ - photoURL presence
186
+
187
+ **RULES**:
188
+ - SHOULD track completeness percentage
189
+ - MAY require for features
190
+ - MUST show user what's missing
191
+
192
+ **CONSTRAINTS**:
193
+ - 3 core fields checked
194
+ - Percentage calculation
195
+ - Missing fields list
196
+
197
+ ---
198
+
199
+ ## Firestore Integration
200
+
201
+ ### Collection Structure
202
+
203
+ **COLLECTION**: `users`
204
+
205
+ **DOCUMENT ID**: User uid
206
+
207
+ **INDEXES**:
208
+ - displayName (ASCENDING)
209
+ - createdAt (DESCENDING)
210
+ - Composite indexes as needed
211
+
212
+ **Rules**:
213
+ - MUST use users collection by default
214
+ - MAY configure custom collection
215
+ - MUST create required indexes
216
+
217
+ ---
218
+
219
+ ### Timestamps
220
+
221
+ **SERVER TIMESTAMPS**:
222
+ - `createdAt` - Document creation
223
+ - `updatedAt` - Last update
224
+ - `lastLoginAt` - Last login
225
+
226
+ **Rules**:
227
+ - MUST use serverTimestamp() for creation
228
+ - MUST update on modification
229
+ - MUST track login time
230
+
231
+ ---
232
+
233
+ ## Privacy & Security
234
+
235
+ ### Data Access
236
+
237
+ **RULES**:
238
+ - MUST NOT expose sensitive data
239
+ - MUST validate read permissions
240
+ - MUST log profile access
241
+ - MUST respect privacy settings
242
+
243
+ **MUST NOT**:
244
+ - Show internal IDs publicly
245
+ - Expose email without permission
246
+ - Log full profile data
247
+
248
+ ---
249
+
250
+ ### Anonymous Profiles
251
+
252
+ **RULES**:
253
+ - MUST indicate anonymous status
254
+ - MUST NOT show as authenticated
255
+ - SHOULD encourage upgrade
256
+ - MUST preserve during upgrade
257
+
258
+ **CONSTRAINTS**:
259
+ - Temporary state
260
+ - Limited data
261
+ - Upgrade path available
262
+
263
+ ---
264
+
265
+ ## Related Entities
266
+
267
+ - **AuthUser** (`./AuthUser.md`) - Authentication user entity
268
+ - **UpdateProfileParams** (see above) - Update parameters
269
+
270
+ ## Related Infrastructure
271
+
272
+ - **UserDocumentService** (`../../infrastructure/services/UserDocumentService.ts`) - Document management
273
+ - **Firestore** - Database storage