@umituz/react-native-auth 3.4.30 → 3.4.32
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/README.md +426 -0
- package/package.json +1 -3
- package/src/application/README.md +513 -0
- package/src/domain/ConfigAndErrors.md +545 -0
- package/src/domain/README.md +293 -0
- package/src/domain/entities/AuthUser.md +377 -0
- package/src/domain/entities/UserProfile.md +443 -0
- package/src/infrastructure/README.md +576 -0
- package/src/infrastructure/services/README.md +417 -0
- package/src/presentation/README.md +770 -0
- package/src/presentation/components/AuthBackground.tsx +21 -0
- package/src/presentation/components/AuthContainer.tsx +3 -3
- package/src/presentation/components/LoginForm.md +222 -0
- package/src/presentation/components/PasswordIndicators.md +260 -0
- package/src/presentation/components/ProfileComponents.md +575 -0
- package/src/presentation/components/README.md +117 -0
- package/src/presentation/components/SocialLoginButtons.md +340 -0
- package/src/presentation/hooks/README.md +122 -0
- package/src/presentation/hooks/useAccountManagement.md +386 -0
- package/src/presentation/hooks/useAuth.md +255 -0
- package/src/presentation/hooks/useAuthBottomSheet.md +414 -0
- package/src/presentation/hooks/useAuthRequired.md +248 -0
- package/src/presentation/hooks/useProfileUpdate.md +327 -0
- package/src/presentation/hooks/useSocialLogin.md +356 -0
- package/src/presentation/hooks/useUserProfile.md +230 -0
- package/src/presentation/screens/README.md +198 -0
- package/src/presentation/components/AuthGradientBackground.tsx +0 -33
|
@@ -0,0 +1,770 @@
|
|
|
1
|
+
# Presentation Layer
|
|
2
|
+
|
|
3
|
+
React Native Auth package presentation layer. Contains React components, hooks, providers, stores, and navigation.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
presentation/
|
|
9
|
+
├── providers/
|
|
10
|
+
│ └── AuthProvider.tsx # Auth context provider
|
|
11
|
+
├── hooks/
|
|
12
|
+
│ ├── useAuth.ts # Main auth hook
|
|
13
|
+
│ ├── useAuthRequired.ts # Auth-required hook
|
|
14
|
+
│ ├── useRequireAuth.ts # Route protection hook
|
|
15
|
+
│ ├── useUserProfile.ts # User profile hook
|
|
16
|
+
│ ├── useProfileUpdate.ts # Profile update hook
|
|
17
|
+
│ ├── useProfileEdit.ts # Profile edit hook
|
|
18
|
+
│ ├── useAccountManagement.ts # Account management hook
|
|
19
|
+
│ ├── useSocialLogin.ts # Social login hook
|
|
20
|
+
│ ├── useGoogleAuth.ts # Google auth hook
|
|
21
|
+
│ ├── useAppleAuth.ts # Apple auth hook
|
|
22
|
+
│ ├── useAuthBottomSheet.ts # Auth bottom sheet hook
|
|
23
|
+
│ ├── useLoginForm.ts # Login form hook
|
|
24
|
+
│ ├── useRegisterForm.ts # Register form hook
|
|
25
|
+
│ └── mutations/
|
|
26
|
+
│ └── useAuthMutations.ts # Auth mutation hooks
|
|
27
|
+
├── components/
|
|
28
|
+
│ ├── AuthContainer.tsx # Main container
|
|
29
|
+
│ ├── AuthHeader.tsx # Header component
|
|
30
|
+
│ ├── AuthFormCard.tsx # Form card
|
|
31
|
+
│ ├── LoginForm.tsx # Login form
|
|
32
|
+
│ ├── RegisterForm.tsx # Register form
|
|
33
|
+
│ ├── EditProfileForm.tsx # Edit profile form
|
|
34
|
+
│ ├── EditProfileAvatar.tsx # Edit profile avatar
|
|
35
|
+
│ ├── PasswordStrengthIndicator.tsx # Password strength
|
|
36
|
+
│ ├── PasswordMatchIndicator.tsx # Password match
|
|
37
|
+
│ ├── SocialLoginButtons.tsx # Social login buttons
|
|
38
|
+
│ ├── ProfileSection.tsx # Profile section
|
|
39
|
+
│ ├── AccountActions.tsx # Account actions
|
|
40
|
+
│ ├── AuthBottomSheet.tsx # Bottom sheet modal
|
|
41
|
+
│ ├── AuthLegalLinks.tsx # Legal links
|
|
42
|
+
│ ├── AuthDivider.tsx # Divider
|
|
43
|
+
│ ├── AuthLink.tsx # Navigation link
|
|
44
|
+
│ ├── AuthErrorDisplay.tsx # Error display
|
|
45
|
+
│ ├── AuthBackground.tsx # Background component
|
|
46
|
+
│ └── icons/
|
|
47
|
+
│ ├── GoogleIconSvg.tsx # Google icon
|
|
48
|
+
│ └── AppleIconSvg.tsx # Apple icon
|
|
49
|
+
├── screens/
|
|
50
|
+
│ ├── LoginScreen.tsx # Login screen
|
|
51
|
+
│ ├── RegisterScreen.tsx # Register screen
|
|
52
|
+
│ ├── AccountScreen.tsx # Account screen
|
|
53
|
+
│ └── EditProfileScreen.tsx # Edit profile screen
|
|
54
|
+
├── navigation/
|
|
55
|
+
│ └── AuthNavigator.tsx # Auth navigator
|
|
56
|
+
├── stores/
|
|
57
|
+
│ ├── authStore.ts # Auth state store (Zustand)
|
|
58
|
+
│ └── authModalStore.ts # Auth modal store
|
|
59
|
+
└── utils/
|
|
60
|
+
└── accountDeleteHandler.util.ts # Account deletion handler
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Overview
|
|
64
|
+
|
|
65
|
+
The presentation layer provides all UI components and React hooks for authentication features in your React Native app.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
# Providers
|
|
70
|
+
|
|
71
|
+
## AuthProvider
|
|
72
|
+
|
|
73
|
+
Root provider that wraps your app and provides authentication context.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { AuthProvider } from '@umituz/react-native-auth';
|
|
77
|
+
|
|
78
|
+
function App() {
|
|
79
|
+
return (
|
|
80
|
+
<AuthProvider>
|
|
81
|
+
<AppNavigator />
|
|
82
|
+
</AuthProvider>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
# Hooks
|
|
90
|
+
|
|
91
|
+
## Core Hooks
|
|
92
|
+
|
|
93
|
+
### useAuth
|
|
94
|
+
|
|
95
|
+
Main authentication hook for managing auth state and operations.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { useAuth } from '@umituz/react-native-auth';
|
|
99
|
+
|
|
100
|
+
function MyComponent() {
|
|
101
|
+
const {
|
|
102
|
+
user,
|
|
103
|
+
userId,
|
|
104
|
+
userType,
|
|
105
|
+
loading,
|
|
106
|
+
isAuthReady,
|
|
107
|
+
isAnonymous,
|
|
108
|
+
isAuthenticated,
|
|
109
|
+
error,
|
|
110
|
+
signIn,
|
|
111
|
+
signUp,
|
|
112
|
+
signOut,
|
|
113
|
+
continueAnonymously,
|
|
114
|
+
setError,
|
|
115
|
+
} = useAuth();
|
|
116
|
+
|
|
117
|
+
if (loading) return <LoadingSpinner />;
|
|
118
|
+
|
|
119
|
+
if (!isAuthenticated) {
|
|
120
|
+
return <LoginScreen />;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<View>
|
|
125
|
+
<Text>Welcome, {user?.email}</Text>
|
|
126
|
+
<Button onPress={signOut}>Sign Out</Button>
|
|
127
|
+
</View>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### useAuthRequired
|
|
133
|
+
|
|
134
|
+
Check auth requirements and show modal if needed.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { useAuthRequired } from '@umituz/react-native-auth';
|
|
138
|
+
|
|
139
|
+
function LikeButton() {
|
|
140
|
+
const { isAllowed, checkAndRequireAuth } = useAuthRequired();
|
|
141
|
+
|
|
142
|
+
const handleLike = () => {
|
|
143
|
+
if (checkAndRequireAuth()) {
|
|
144
|
+
// User is authenticated, proceed
|
|
145
|
+
likePost();
|
|
146
|
+
}
|
|
147
|
+
// Otherwise, auth modal is shown automatically
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<Button onPress={handleLike}>
|
|
152
|
+
{isAllowed ? 'Like' : 'Sign in to like'}
|
|
153
|
+
</Button>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### useRequireAuth
|
|
159
|
+
|
|
160
|
+
Get userId or throw if not authenticated (for protected components).
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { useRequireAuth } from '@umituz/react-native-auth';
|
|
164
|
+
|
|
165
|
+
function UserProfile() {
|
|
166
|
+
const userId = useRequireAuth(); // Guaranteed to be string
|
|
167
|
+
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
fetchUserData(userId);
|
|
170
|
+
}, [userId]);
|
|
171
|
+
|
|
172
|
+
return <ProfileContent userId={userId} />;
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## User Profile Hooks
|
|
177
|
+
|
|
178
|
+
### useUserProfile
|
|
179
|
+
|
|
180
|
+
Fetch user profile data for display.
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { useUserProfile } from '@umituz/react-native-auth';
|
|
184
|
+
|
|
185
|
+
function ProfileHeader() {
|
|
186
|
+
const profile = useUserProfile({
|
|
187
|
+
accountRoute: '/account',
|
|
188
|
+
anonymousDisplayName: 'Guest User',
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
if (!profile) return <LoadingSpinner />;
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<View>
|
|
195
|
+
<Avatar source={{ uri: profile.avatarUrl }} />
|
|
196
|
+
<Text>{profile.displayName}</Text>
|
|
197
|
+
{profile.isAnonymous && <Text>Guest</Text>}
|
|
198
|
+
</View>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### useProfileUpdate
|
|
204
|
+
|
|
205
|
+
Profile update operations.
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import { useProfileUpdate } from '@umituz/react-native-auth';
|
|
209
|
+
|
|
210
|
+
function ProfileSettings() {
|
|
211
|
+
const { updateProfile, isUpdating, error } = useProfileUpdate();
|
|
212
|
+
|
|
213
|
+
const handleUpdate = async (data: UpdateProfileParams) => {
|
|
214
|
+
try {
|
|
215
|
+
await updateProfile(data);
|
|
216
|
+
} catch (err) {
|
|
217
|
+
console.error(err);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
return <ProfileForm onSave={handleUpdate} />;
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### useProfileEdit
|
|
226
|
+
|
|
227
|
+
Profile editing form state management.
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { useProfileEdit } from '@umituz/react-native-auth';
|
|
231
|
+
|
|
232
|
+
function EditProfileScreen() {
|
|
233
|
+
const {
|
|
234
|
+
formState,
|
|
235
|
+
setDisplayName,
|
|
236
|
+
setEmail,
|
|
237
|
+
setPhotoURL,
|
|
238
|
+
resetForm,
|
|
239
|
+
validateForm,
|
|
240
|
+
} = useProfileEdit({
|
|
241
|
+
displayName: user?.displayName || '',
|
|
242
|
+
email: user?.email || '',
|
|
243
|
+
photoURL: user?.photoURL || null,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const handleSave = () => {
|
|
247
|
+
const { isValid, errors } = validateForm();
|
|
248
|
+
if (!isValid) {
|
|
249
|
+
Alert.alert('Error', errors.join('\n'));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
updateProfile(formState);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
return <EditProfileForm {...props} />;
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Account Management Hooks
|
|
260
|
+
|
|
261
|
+
### useAccountManagement
|
|
262
|
+
|
|
263
|
+
Account management operations (logout, delete).
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { useAccountManagement } from '@umituz/react-native-auth';
|
|
267
|
+
|
|
268
|
+
function AccountSettings() {
|
|
269
|
+
const { logout, deleteAccount, isLoading, isDeletingAccount } = useAccountManagement({
|
|
270
|
+
onReauthRequired: async () => {
|
|
271
|
+
const result = await reauthenticateWithGoogle();
|
|
272
|
+
return result.success;
|
|
273
|
+
},
|
|
274
|
+
onPasswordRequired: async () => {
|
|
275
|
+
const password = await showPasswordPrompt();
|
|
276
|
+
return password;
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<View>
|
|
282
|
+
<Button onPress={logout}>Sign Out</Button>
|
|
283
|
+
<Button onPress={deleteAccount}>Delete Account</Button>
|
|
284
|
+
</View>
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Social Login Hooks
|
|
290
|
+
|
|
291
|
+
### useSocialLogin
|
|
292
|
+
|
|
293
|
+
General social login management.
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
import { useSocialLogin } from '@umituz/react-native-auth';
|
|
297
|
+
|
|
298
|
+
function LoginScreen() {
|
|
299
|
+
const {
|
|
300
|
+
signInWithGoogle,
|
|
301
|
+
signInWithApple,
|
|
302
|
+
googleLoading,
|
|
303
|
+
appleLoading,
|
|
304
|
+
googleConfigured,
|
|
305
|
+
appleAvailable,
|
|
306
|
+
} = useSocialLogin({
|
|
307
|
+
google: { webClientId: '...', iosClientId: '...' },
|
|
308
|
+
apple: { enabled: true },
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<View>
|
|
313
|
+
<Button onPress={signInWithGoogle} disabled={googleLoading}>
|
|
314
|
+
Google
|
|
315
|
+
</Button>
|
|
316
|
+
<Button onPress={signInWithApple} disabled={appleLoading}>
|
|
317
|
+
Apple
|
|
318
|
+
</Button>
|
|
319
|
+
</View>
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### useGoogleAuth
|
|
325
|
+
|
|
326
|
+
Google OAuth flow with expo-auth-session.
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
import { useGoogleAuth } from '@umituz/react-native-auth';
|
|
330
|
+
|
|
331
|
+
function LoginScreen() {
|
|
332
|
+
const { signInWithGoogle, googleLoading, googleConfigured } = useGoogleAuth({
|
|
333
|
+
iosClientId: Config.GOOGLE_IOS_CLIENT_ID,
|
|
334
|
+
webClientId: Config.GOOGLE_WEB_CLIENT_ID,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
return (
|
|
338
|
+
<Button onPress={signInWithGoogle} disabled={googleLoading}>
|
|
339
|
+
Sign in with Google
|
|
340
|
+
</Button>
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### useAppleAuth
|
|
346
|
+
|
|
347
|
+
Apple Sign-In functionality.
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
import { useAppleAuth } from '@umituz/react-native-auth';
|
|
351
|
+
|
|
352
|
+
function LoginScreen() {
|
|
353
|
+
const { signInWithApple, appleLoading, appleAvailable } = useAppleAuth();
|
|
354
|
+
|
|
355
|
+
if (!appleAvailable) return null;
|
|
356
|
+
|
|
357
|
+
return (
|
|
358
|
+
<Button onPress={signInWithApple} disabled={appleLoading}>
|
|
359
|
+
Sign in with Apple
|
|
360
|
+
</Button>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## UI Hooks
|
|
366
|
+
|
|
367
|
+
### useAuthBottomSheet
|
|
368
|
+
|
|
369
|
+
Authentication bottom sheet management.
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
import { useAuthBottomSheet } from '@umituz/react-native-auth';
|
|
373
|
+
|
|
374
|
+
function AuthBottomSheet() {
|
|
375
|
+
const {
|
|
376
|
+
modalRef,
|
|
377
|
+
mode,
|
|
378
|
+
providers,
|
|
379
|
+
googleLoading,
|
|
380
|
+
appleLoading,
|
|
381
|
+
handleDismiss,
|
|
382
|
+
handleGoogleSignIn,
|
|
383
|
+
handleAppleSignIn,
|
|
384
|
+
} = useAuthBottomSheet({
|
|
385
|
+
socialConfig: {
|
|
386
|
+
google: { webClientId: '...', iosClientId: '...' },
|
|
387
|
+
apple: { enabled: true },
|
|
388
|
+
},
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
return (
|
|
392
|
+
<BottomSheetModal ref={modalRef} onDismiss={handleDismiss}>
|
|
393
|
+
{mode === 'login' ? (
|
|
394
|
+
<LoginForm onGoogleSignIn={handleGoogleSignIn} />
|
|
395
|
+
) : (
|
|
396
|
+
<RegisterForm onGoogleSignIn={handleGoogleSignIn} />
|
|
397
|
+
)}
|
|
398
|
+
</BottomSheetModal>
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
# Components
|
|
406
|
+
|
|
407
|
+
## Layout Components
|
|
408
|
+
|
|
409
|
+
### AuthContainer
|
|
410
|
+
|
|
411
|
+
Main auth layout container with background component and scroll.
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
import { AuthContainer } from '@umituz/react-native-auth';
|
|
415
|
+
|
|
416
|
+
function LoginScreen() {
|
|
417
|
+
return (
|
|
418
|
+
<AuthContainer>
|
|
419
|
+
<AuthHeader title="Sign In" />
|
|
420
|
+
<LoginForm />
|
|
421
|
+
<SocialLoginButtons />
|
|
422
|
+
</AuthContainer>
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### AuthHeader
|
|
428
|
+
|
|
429
|
+
Header component for auth screens.
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
import { AuthHeader } from '@umituz/react-native-auth';
|
|
433
|
+
|
|
434
|
+
<AuthHeader
|
|
435
|
+
title="Welcome Back"
|
|
436
|
+
subtitle="Sign in to continue"
|
|
437
|
+
/>
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### AuthFormCard
|
|
441
|
+
|
|
442
|
+
Form card container with consistent styling.
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
import { AuthFormCard } from '@umituz/react-native-auth';
|
|
446
|
+
|
|
447
|
+
<AuthFormCard>
|
|
448
|
+
<LoginForm />
|
|
449
|
+
</AuthFormCard>
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
## Form Components
|
|
453
|
+
|
|
454
|
+
### LoginForm & RegisterForm
|
|
455
|
+
|
|
456
|
+
Pre-built authentication forms.
|
|
457
|
+
|
|
458
|
+
```typescript
|
|
459
|
+
import { LoginForm, RegisterForm } from '@umituz/react-native-auth';
|
|
460
|
+
|
|
461
|
+
function LoginScreen() {
|
|
462
|
+
const navigation = useNavigation();
|
|
463
|
+
|
|
464
|
+
return (
|
|
465
|
+
<LoginForm onNavigateToRegister={() => navigation.navigate('Register')} />
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function RegisterScreen() {
|
|
470
|
+
const navigation = useNavigation();
|
|
471
|
+
|
|
472
|
+
return (
|
|
473
|
+
<RegisterForm
|
|
474
|
+
onNavigateToLogin={() => navigation.navigate('Login')}
|
|
475
|
+
onTermsPress={() => navigation.navigate('Terms')}
|
|
476
|
+
onPrivacyPress={() => navigation.navigate('Privacy')}
|
|
477
|
+
/>
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Password Indicators
|
|
483
|
+
|
|
484
|
+
### PasswordStrengthIndicator
|
|
485
|
+
|
|
486
|
+
Visual password strength indicator.
|
|
487
|
+
|
|
488
|
+
```typescript
|
|
489
|
+
import { PasswordStrengthIndicator } from '@umituz/react-native-auth';
|
|
490
|
+
|
|
491
|
+
function RegisterForm() {
|
|
492
|
+
const [password, setPassword] = useState('');
|
|
493
|
+
const requirements = validatePasswordRequirements(password);
|
|
494
|
+
|
|
495
|
+
return (
|
|
496
|
+
<View>
|
|
497
|
+
<TextInput
|
|
498
|
+
value={password}
|
|
499
|
+
onChangeText={setPassword}
|
|
500
|
+
placeholder="Password"
|
|
501
|
+
secureTextEntry
|
|
502
|
+
/>
|
|
503
|
+
<PasswordStrengthIndicator requirements={requirements} />
|
|
504
|
+
</View>
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### PasswordMatchIndicator
|
|
510
|
+
|
|
511
|
+
Password matching indicator.
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
import { PasswordMatchIndicator } from '@umituz/react-native-auth';
|
|
515
|
+
|
|
516
|
+
function RegisterForm() {
|
|
517
|
+
const [password, setPassword] = useState('');
|
|
518
|
+
const [confirmPassword, setConfirmPassword] = useState('');
|
|
519
|
+
|
|
520
|
+
const passwordsMatch = password === confirmPassword && password.length > 0;
|
|
521
|
+
|
|
522
|
+
return (
|
|
523
|
+
<View>
|
|
524
|
+
<TextInput value={password} onChangeText={setPassword} />
|
|
525
|
+
<TextInput value={confirmPassword} onChangeText={setConfirmPassword} />
|
|
526
|
+
{confirmPassword.length > 0 && (
|
|
527
|
+
<PasswordMatchIndicator isMatch={passwordsMatch} />
|
|
528
|
+
)}
|
|
529
|
+
</View>
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
## Social Login Components
|
|
535
|
+
|
|
536
|
+
### SocialLoginButtons
|
|
537
|
+
|
|
538
|
+
Social login button group.
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
import { SocialLoginButtons } from '@umituz/react-native-auth';
|
|
542
|
+
|
|
543
|
+
function LoginScreen() {
|
|
544
|
+
const { signInWithGoogle, googleLoading } = useGoogleAuth({ ... });
|
|
545
|
+
const { signInWithApple, appleLoading } = useAppleAuth();
|
|
546
|
+
|
|
547
|
+
return (
|
|
548
|
+
<SocialLoginButtons
|
|
549
|
+
enabledProviders={['google', 'apple']}
|
|
550
|
+
onGooglePress={signInWithGoogle}
|
|
551
|
+
onApplePress={signInWithApple}
|
|
552
|
+
googleLoading={googleLoading}
|
|
553
|
+
appleLoading={appleLoading}
|
|
554
|
+
/>
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
## Profile Components
|
|
560
|
+
|
|
561
|
+
### ProfileSection
|
|
562
|
+
|
|
563
|
+
User profile display component.
|
|
564
|
+
|
|
565
|
+
```typescript
|
|
566
|
+
import { ProfileSection } from '@umituz/react-native-auth';
|
|
567
|
+
|
|
568
|
+
function SettingsScreen() {
|
|
569
|
+
const profile = useUserProfile();
|
|
570
|
+
|
|
571
|
+
return (
|
|
572
|
+
<ProfileSection
|
|
573
|
+
profile={{
|
|
574
|
+
displayName: profile?.displayName,
|
|
575
|
+
userId: profile?.userId,
|
|
576
|
+
isAnonymous: profile?.isAnonymous || false,
|
|
577
|
+
avatarUrl: profile?.avatarUrl,
|
|
578
|
+
}}
|
|
579
|
+
onPress={() => navigation.navigate('EditProfile')}
|
|
580
|
+
onSignIn={() => navigation.navigate('Login')}
|
|
581
|
+
/>
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### AccountActions
|
|
587
|
+
|
|
588
|
+
Account management actions component.
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
import { AccountActions } from '@umituz/react-native-auth';
|
|
592
|
+
|
|
593
|
+
function AccountSettings() {
|
|
594
|
+
const { logout, deleteAccount } = useAccountManagement();
|
|
595
|
+
|
|
596
|
+
const config = {
|
|
597
|
+
logoutText: 'Sign Out',
|
|
598
|
+
deleteAccountText: 'Delete Account',
|
|
599
|
+
logoutConfirmTitle: 'Sign Out',
|
|
600
|
+
logoutConfirmMessage: 'Are you sure you want to sign out?',
|
|
601
|
+
deleteConfirmTitle: 'Delete Account',
|
|
602
|
+
deleteConfirmMessage: 'This action cannot be undone. Continue?',
|
|
603
|
+
onLogout: logout,
|
|
604
|
+
onDeleteAccount: deleteAccount,
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
return <AccountActions config={config} />;
|
|
608
|
+
}
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
# Screens
|
|
614
|
+
|
|
615
|
+
Pre-built authentication screens.
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
import {
|
|
619
|
+
LoginScreen,
|
|
620
|
+
RegisterScreen,
|
|
621
|
+
AccountScreen,
|
|
622
|
+
EditProfileScreen,
|
|
623
|
+
} from '@umituz/react-native-auth';
|
|
624
|
+
|
|
625
|
+
// Use in navigation
|
|
626
|
+
<Stack.Screen
|
|
627
|
+
name="Login"
|
|
628
|
+
component={LoginScreen}
|
|
629
|
+
options={{ headerShown: false }}
|
|
630
|
+
/>
|
|
631
|
+
<Stack.Screen
|
|
632
|
+
name="Register"
|
|
633
|
+
component={RegisterScreen}
|
|
634
|
+
/>
|
|
635
|
+
<Stack.Screen
|
|
636
|
+
name="Account"
|
|
637
|
+
component={AccountScreen}
|
|
638
|
+
/>
|
|
639
|
+
<Stack.Screen
|
|
640
|
+
name="EditProfile"
|
|
641
|
+
component={EditProfileScreen}
|
|
642
|
+
/>
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
# Stores
|
|
648
|
+
|
|
649
|
+
## authStore
|
|
650
|
+
|
|
651
|
+
Main authentication state store (Zustand).
|
|
652
|
+
|
|
653
|
+
```typescript
|
|
654
|
+
import {
|
|
655
|
+
useAuthStore,
|
|
656
|
+
selectIsAuthenticated,
|
|
657
|
+
selectUserId,
|
|
658
|
+
getIsAuthenticated,
|
|
659
|
+
getUserId,
|
|
660
|
+
} from '@umituz/react-native-auth';
|
|
661
|
+
|
|
662
|
+
function Component() {
|
|
663
|
+
// Selectors prevent unnecessary re-renders
|
|
664
|
+
const isAuthenticated = useAuthStore(selectIsAuthenticated);
|
|
665
|
+
const userId = useAuthStore(selectUserId);
|
|
666
|
+
|
|
667
|
+
return <View>{/* ... */}</View>;
|
|
668
|
+
}
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
## authModalStore
|
|
672
|
+
|
|
673
|
+
Auth modal state store.
|
|
674
|
+
|
|
675
|
+
```typescript
|
|
676
|
+
import { useAuthModalStore } from '@umituz/react-native-auth';
|
|
677
|
+
|
|
678
|
+
function Component() {
|
|
679
|
+
const { showAuthModal, isVisible, mode, hideAuthModal } = useAuthModalStore();
|
|
680
|
+
|
|
681
|
+
const handleAuthRequired = () => {
|
|
682
|
+
showAuthModal(() => {
|
|
683
|
+
// Callback after successful auth
|
|
684
|
+
performAction();
|
|
685
|
+
}, 'login');
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
return <View>{/* ... */}</View>;
|
|
689
|
+
}
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
---
|
|
693
|
+
|
|
694
|
+
# Navigation
|
|
695
|
+
|
|
696
|
+
## AuthNavigator
|
|
697
|
+
|
|
698
|
+
Pre-configured authentication navigator.
|
|
699
|
+
|
|
700
|
+
```typescript
|
|
701
|
+
import { AuthNavigator } from '@umituz/react-native-auth';
|
|
702
|
+
|
|
703
|
+
function App() {
|
|
704
|
+
return (
|
|
705
|
+
<NavigationContainer>
|
|
706
|
+
<AuthNavigator />
|
|
707
|
+
</NavigationContainer>
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
# Best Practices
|
|
715
|
+
|
|
716
|
+
## 1. Use Hooks Over Direct Store Access
|
|
717
|
+
|
|
718
|
+
```typescript
|
|
719
|
+
// ✅ Good
|
|
720
|
+
function Component() {
|
|
721
|
+
const { user, signIn } = useAuth();
|
|
722
|
+
|
|
723
|
+
return <View>{/* ... */}</View>;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// ❌ Bad
|
|
727
|
+
function Component() {
|
|
728
|
+
const user = useAuthStore((state) => state.user);
|
|
729
|
+
|
|
730
|
+
return <View>{/* ... */}</View>;
|
|
731
|
+
}
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
## 2. Wrap with AuthProvider
|
|
735
|
+
|
|
736
|
+
```typescript
|
|
737
|
+
// ✅ Good
|
|
738
|
+
function App() {
|
|
739
|
+
return (
|
|
740
|
+
<AuthProvider>
|
|
741
|
+
<Navigator />
|
|
742
|
+
</AuthProvider>
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// ❌ Bad - Missing provider
|
|
747
|
+
function App() {
|
|
748
|
+
return <Navigator />;
|
|
749
|
+
}
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
## 3. Handle Loading States
|
|
753
|
+
|
|
754
|
+
```typescript
|
|
755
|
+
// ✅ Good
|
|
756
|
+
function Component() {
|
|
757
|
+
const { loading, isAuthReady, user } = useAuth();
|
|
758
|
+
|
|
759
|
+
if (loading) return <LoadingSpinner />;
|
|
760
|
+
if (!isAuthReady) return <InitializingScreen />;
|
|
761
|
+
|
|
762
|
+
return <View>{/* ... */}</View>;
|
|
763
|
+
}
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
## Related Modules
|
|
767
|
+
|
|
768
|
+
- **[Domain](../domain/README.md)** - Domain entities and business rules
|
|
769
|
+
- **[Application](../application/README.md)** - Application interfaces
|
|
770
|
+
- **[Infrastructure](../infrastructure/README.md)** - Infrastructure implementations
|