@umituz/react-native-auth 3.4.29 → 3.4.31

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.
@@ -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
+ │ ├── AuthGradientBackground.tsx # Gradient background
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 gradient background.
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