@umituz/react-native-auth 3.4.30 → 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,417 @@
1
+ # useAuthBottomSheet
2
+
3
+ Authentication bottom sheet yönetimi için hook. Login/Register modal'ını göstermek, yönetmek ve social authentication işlemlerini gerçekleştirmek için kullanılır.
4
+
5
+ ## Özellikler
6
+
7
+ - Bottom sheet modal yönetimi
8
+ - Login/Register mod değiştirme
9
+ - Social authentication entegrasyonu
10
+ - Otomatik kapanma (başarılı authentication sonrası)
11
+ - Pending callback yönetimi
12
+
13
+ ## Kullanım
14
+
15
+ ```typescript
16
+ import { useAuthBottomSheet } from '@umituz/react-native-auth';
17
+ import { BottomSheetModal } from '@umituz/react-native-design-system';
18
+
19
+ function AuthBottomSheet() {
20
+ const {
21
+ modalRef,
22
+ mode,
23
+ providers,
24
+ googleLoading,
25
+ appleLoading,
26
+ handleDismiss,
27
+ handleClose,
28
+ handleNavigateToRegister,
29
+ handleNavigateToLogin,
30
+ handleGoogleSignIn,
31
+ handleAppleSignIn,
32
+ } = useAuthBottomSheet({
33
+ socialConfig: {
34
+ google: {
35
+ iosClientId: 'your-ios-client-id',
36
+ webClientId: 'your-web-client-id',
37
+ },
38
+ apple: { enabled: true },
39
+ },
40
+ });
41
+
42
+ return (
43
+ <BottomSheetModal ref={modalRef} onDismiss={handleDismiss}>
44
+ {mode === 'login' ? (
45
+ <LoginForm
46
+ onRegisterPress={handleNavigateToRegister}
47
+ onGoogleSignIn={handleGoogleSignIn}
48
+ onAppleSignIn={handleAppleSignIn}
49
+ googleLoading={googleLoading}
50
+ appleLoading={appleLoading}
51
+ />
52
+ ) : (
53
+ <RegisterForm
54
+ onLoginPress={handleNavigateToLogin}
55
+ onGoogleSignIn={handleGoogleSignIn}
56
+ onAppleSignIn={handleAppleSignIn}
57
+ googleLoading={googleLoading}
58
+ appleLoading={appleLoading}
59
+ />
60
+ )}
61
+ </BottomSheetModal>
62
+ );
63
+ }
64
+ ```
65
+
66
+ ## API
67
+
68
+ ### Parameters
69
+
70
+ | Param | Tip | Required | Açıklama |
71
+ |-------|------|----------|----------|
72
+ | `socialConfig` | `SocialAuthConfiguration` | No | Social auth konfigürasyonu |
73
+ | `onGoogleSignIn` | `() => Promise<void>` | No | Custom Google sign-in handler |
74
+ | `onAppleSignIn` | `() => Promise<void>` | No | Custom Apple sign-in handler |
75
+
76
+ #### SocialAuthConfiguration
77
+
78
+ ```typescript
79
+ interface SocialAuthConfiguration {
80
+ google?: GoogleAuthConfig;
81
+ apple?: { enabled: boolean };
82
+ }
83
+ ```
84
+
85
+ ### Return Value
86
+
87
+ | Prop | Tip | Açıklama |
88
+ |------|-----|----------|
89
+ | `modalRef` | `RefObject<BottomSheetModalRef>` | Bottom sheet modal referansı |
90
+ | `mode` | `'login' \| 'register'` | Mevcut mod |
91
+ | `providers` | `SocialAuthProvider[]` | Mevcut social provider'lar |
92
+ | `googleLoading` | `boolean` | Google loading durumu |
93
+ | `appleLoading` | `boolean` | Apple loading durumu |
94
+ | `handleDismiss` | `() => void` | Modal'ı kapatma (dismiss) |
95
+ | `handleClose` | `() => void` | Modal'ı kapatma ve temizleme |
96
+ | `handleNavigateToRegister` | `() => void` | Register moduna geçiş |
97
+ | `handleNavigateToLogin` | `() => void` | Login moduna geçiş |
98
+ | `handleGoogleSignIn` | `() => Promise<void>` | Google ile giriş |
99
+ | `handleAppleSignIn` | `() => Promise<void>` | Apple ile giriş |
100
+
101
+ ## Örnekler
102
+
103
+ ### Basit Auth Bottom Sheet
104
+
105
+ ```typescript
106
+ function AuthModal() {
107
+ const {
108
+ modalRef,
109
+ mode,
110
+ handleDismiss,
111
+ handleNavigateToRegister,
112
+ handleNavigateToLogin,
113
+ } = useAuthBottomSheet();
114
+
115
+ return (
116
+ <BottomSheetModal ref={modalRef} snapPoints={['80%']} onDismiss={handleDismiss}>
117
+ <View>
118
+ {mode === 'login' ? (
119
+ <>
120
+ <Text>Giriş Yap</Text>
121
+ <LoginForm />
122
+ <Button onPress={handleNavigateToRegister}>
123
+ Hesabınız yok mu? Kayıt Olun
124
+ </Button>
125
+ </>
126
+ ) : (
127
+ <>
128
+ <Text>Kayıt Ol</Text>
129
+ <RegisterForm />
130
+ <Button onPress={handleNavigateToLogin}>
131
+ Zaten hesabınız var mı? Giriş Yapın
132
+ </Button>
133
+ </>
134
+ )}
135
+ </View>
136
+ </BottomSheetModal>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ### Social Login ile
142
+
143
+ ```typescript
144
+ function AuthBottomSheetWithSocial() {
145
+ const {
146
+ modalRef,
147
+ mode,
148
+ providers,
149
+ googleLoading,
150
+ appleLoading,
151
+ handleDismiss,
152
+ handleNavigateToRegister,
153
+ handleNavigateToLogin,
154
+ handleGoogleSignIn,
155
+ handleAppleSignIn,
156
+ } = useAuthBottomSheet({
157
+ socialConfig: {
158
+ google: {
159
+ webClientId: Config.GOOGLE_WEB_CLIENT_ID,
160
+ iosClientId: Config.GOOGLE_IOS_CLIENT_ID,
161
+ },
162
+ apple: { enabled: Platform.OS === 'ios' },
163
+ },
164
+ });
165
+
166
+ return (
167
+ <BottomSheetModal ref={modalRef} snapPoints={['90%']} onDismiss={handleDismiss}>
168
+ <View>
169
+ {mode === 'login' ? (
170
+ <>
171
+ <LoginForm />
172
+
173
+ {/* Social login buttons */}
174
+ {providers.includes('google') && (
175
+ <SocialButton
176
+ provider="google"
177
+ onPress={handleGoogleSignIn}
178
+ loading={googleLoading}
179
+ />
180
+ )}
181
+
182
+ {providers.includes('apple') && (
183
+ <SocialButton
184
+ provider="apple"
185
+ onPress={handleAppleSignIn}
186
+ loading={appleLoading}
187
+ />
188
+ )}
189
+
190
+ <Button onPress={handleNavigateToRegister}>
191
+ Kayıt Ol
192
+ </Button>
193
+ </>
194
+ ) : (
195
+ <>
196
+ <RegisterForm />
197
+
198
+ {/* Social login buttons */}
199
+ {providers.includes('google') && (
200
+ <SocialButton
201
+ provider="google"
202
+ onPress={handleGoogleSignIn}
203
+ loading={googleLoading}
204
+ />
205
+ )}
206
+
207
+ {providers.includes('apple') && (
208
+ <SocialButton
209
+ provider="apple"
210
+ onPress={handleAppleSignIn}
211
+ loading={appleLoading}
212
+ />
213
+ )}
214
+
215
+ <Button onPress={handleNavigateToLogin}>
216
+ Giriş Yap
217
+ </Button>
218
+ </>
219
+ )}
220
+ </View>
221
+ </BottomSheetModal>
222
+ );
223
+ }
224
+ ```
225
+
226
+ ### Custom Social Login Handlers
227
+
228
+ ```typescript
229
+ function AuthBottomSheetWithCustomHandlers() {
230
+ const { showAuthModal } = useAuthModalStore();
231
+
232
+ const handleCustomGoogleSignIn = async () => {
233
+ try {
234
+ // Custom Google sign-in logic
235
+ const result = await customGoogleSignInFlow();
236
+
237
+ if (result.success) {
238
+ // Başarılı authentication sonrası modal otomatik kapanır
239
+ console.log('Google ile giriş başarılı');
240
+ }
241
+ } catch (error) {
242
+ Alert.alert('Hata', 'Google ile giriş başarısız');
243
+ }
244
+ };
245
+
246
+ const handleCustomAppleSignIn = async () => {
247
+ try {
248
+ // Custom Apple sign-in logic
249
+ const result = await customAppleSignInFlow();
250
+
251
+ if (result.success) {
252
+ console.log('Apple ile giriş başarılı');
253
+ }
254
+ } catch (error) {
255
+ Alert.alert('Hata', 'Apple ile giriş başarısız');
256
+ }
257
+ };
258
+
259
+ const {
260
+ modalRef,
261
+ mode,
262
+ googleLoading,
263
+ appleLoading,
264
+ handleDismiss,
265
+ handleNavigateToRegister,
266
+ handleNavigateToLogin,
267
+ handleGoogleSignIn,
268
+ handleAppleSignIn,
269
+ } = useAuthBottomSheet({
270
+ onGoogleSignIn: handleCustomGoogleSignIn,
271
+ onAppleSignIn: handleCustomAppleSignIn,
272
+ });
273
+
274
+ return (
275
+ <BottomSheetModal ref={modalRef} onDismiss={handleDismiss}>
276
+ {/* Auth form content */}
277
+ </BottomSheetModal>
278
+ );
279
+ }
280
+ ```
281
+
282
+ ### Auth Modal Tetikleme
283
+
284
+ ```typescript
285
+ function RequireAuthButton() {
286
+ const { showAuthModal } = useAuthModalStore();
287
+ const { isAuthenticated } = useAuth();
288
+
289
+ const handlePress = () => {
290
+ if (!isAuthenticated) {
291
+ // Login modal'ını göster
292
+ showAuthModal(undefined, 'login');
293
+ return;
294
+ }
295
+
296
+ // Auth gerektiren işlemi yap
297
+ console.log('İşlem başarılı');
298
+ };
299
+
300
+ return (
301
+ <Button onPress={handlePress}>
302
+ Auth Gerektiren İşlem
303
+ </Button>
304
+ );
305
+ }
306
+ ```
307
+
308
+ ### Pending Callback ile
309
+
310
+ ```typescript
311
+ function AddToFavoritesButton() {
312
+ const { showAuthModal } = useAuthModalStore();
313
+ const { isAuthenticated } = useAuth();
314
+
315
+ const handleAddToFavorites = async () => {
316
+ if (!isAuthenticated) {
317
+ // Authentication sonrası çalışacak callback'i kaydet
318
+ showAuthModal(async () => {
319
+ await addToFavorites(postId);
320
+ Alert.alert('Başarılı', 'Favorilere eklendi');
321
+ }, 'login');
322
+ return;
323
+ }
324
+
325
+ // Kullanıcı authenticated, doğrudan işlemi yap
326
+ await addToFavorites(postId);
327
+ Alert.alert('Başarılı', 'Favorilere eklendi');
328
+ };
329
+
330
+ return (
331
+ <Button onPress={handleAddToFavorites}>
332
+ Favorilere Ekle
333
+ </Button>
334
+ );
335
+ }
336
+ ```
337
+
338
+ ## Otomatik Kapanma
339
+
340
+ Hook, başarılı authentication sonrası otomatik olarak modal'ı kapatır:
341
+
342
+ - **Authenticated olmadan authenticated olmaya**: Kullanıcı giriş yaptığında
343
+ - **Anonymous'den authenticated olmaya**: Anonymous kullanıcı kayıt olduğunda
344
+
345
+ ```typescript
346
+ // Kullanıcı giriş yapar
347
+ // → useAuth store güncellenir
348
+ // → useAuthBottomSheet bunu tespit eder
349
+ // → Modal otomatik kapanır
350
+ // → Pending callback çalıştırılır
351
+ ```
352
+
353
+ ## Provider Kontrolü
354
+
355
+ Hook hangi provider'ların mevcut olduğunu otomatik belirler:
356
+
357
+ ```typescript
358
+ const { providers } = useAuthBottomSheet({
359
+ socialConfig: {
360
+ google: { webClientId: '...' },
361
+ apple: { enabled: true },
362
+ },
363
+ });
364
+
365
+ // iOS: ['apple', 'google'] veya ['google']
366
+ // Android: ['google']
367
+ // Web: ['google']
368
+ ```
369
+
370
+ ## Hata Yönetimi
371
+
372
+ ```typescript
373
+ function AuthBottomSheetWithErrorHandling() {
374
+ const {
375
+ modalRef,
376
+ mode,
377
+ handleGoogleSignIn,
378
+ handleAppleSignIn,
379
+ } = useAuthBottomSheet({
380
+ socialConfig: {
381
+ google: { webClientId: Config.GOOGLE_WEB_CLIENT_ID },
382
+ apple: { enabled: true },
383
+ },
384
+ });
385
+
386
+ const handleGoogleSignInWithErrorHandling = async () => {
387
+ try {
388
+ await handleGoogleSignIn();
389
+ // Hook hata yönetimini içeride yapar
390
+ } catch (error) {
391
+ // Additional error handling if needed
392
+ Alert.alert('Hata', 'Bir sorun oluştu');
393
+ }
394
+ };
395
+
396
+ return (
397
+ <BottomSheetModal ref={modalRef}>
398
+ <Button onPress={handleGoogleSignInWithErrorHandling}>
399
+ Google ile Giriş
400
+ </Button>
401
+ </BottomSheetModal>
402
+ );
403
+ }
404
+ ```
405
+
406
+ ## İlgili Component'ler
407
+
408
+ - [`AuthBottomSheet`](../components/AuthBottomSheet.md) - Bottom sheet component'i
409
+ - [`useAuthModalStore`](../stores/authModalStore.md) - Auth modal state store'u
410
+ - [`LoginForm`](../components/LoginForm.md) - Login form component'i
411
+ - [`RegisterForm`](../components/RegisterForm.md) - Register form component'i
412
+
413
+ ## İlgili Hook'lar
414
+
415
+ - [`useGoogleAuth`](./useSocialLogin.md#usegoogleauth) - Google auth hook'u
416
+ - [`useAppleAuth`](./useSocialLogin.md#useappleauth) - Apple auth hook'u
417
+ - [`useAuth`](./useAuth.md) - Ana auth state yönetimi
@@ -0,0 +1,248 @@
1
+ # useAuthRequired & useRequireAuth
2
+
3
+ Two hooks for authentication requirements in components.
4
+
5
+ ---
6
+
7
+ ## useAuthRequired
8
+
9
+ Check auth requirements and show modal if needed.
10
+
11
+ ### Usage
12
+
13
+ ```typescript
14
+ import { useAuthRequired } from '@umituz/react-native-auth';
15
+
16
+ function LikeButton() {
17
+ const { isAllowed, isLoading, requireAuth, checkAndRequireAuth } = useAuthRequired();
18
+
19
+ const handleLike = () => {
20
+ if (checkAndRequireAuth()) {
21
+ // User is authenticated, proceed
22
+ likePost();
23
+ }
24
+ // Otherwise, auth modal is shown automatically
25
+ };
26
+
27
+ return (
28
+ <Button onPress={handleLike} disabled={isLoading}>
29
+ {isAllowed ? 'Like' : 'Sign in to like'}
30
+ </Button>
31
+ );
32
+ }
33
+ ```
34
+
35
+ ### API
36
+
37
+ | Prop | Type | Description |
38
+ |------|------|-------------|
39
+ | `isAllowed` | `boolean` | Whether user is authenticated (not anonymous) |
40
+ | `isLoading` | `boolean` | Whether auth is still loading |
41
+ | `userId` | `string \| null` | Current user ID (null if not authenticated) |
42
+ | `requireAuth` | `() => void` | Show auth modal |
43
+ | `checkAndRequireAuth` | `() => boolean` | Check and show modal if needed, returns true/false |
44
+
45
+ ### Examples
46
+
47
+ #### Add to Favorites
48
+
49
+ ```typescript
50
+ function AddToFavoritesButton({ postId }) {
51
+ const { isAllowed, checkAndRequireAuth } = useAuthRequired();
52
+
53
+ const handleAddToFavorites = () => {
54
+ if (!checkAndRequireAuth()) {
55
+ return; // Auth modal opened, stop here
56
+ }
57
+
58
+ // User authenticated, proceed
59
+ addToFavorites(postId);
60
+ };
61
+
62
+ return (
63
+ <TouchableOpacity onPress={handleAddToFavorites}>
64
+ <HeartIcon filled={isAllowed} />
65
+ </TouchableOpacity>
66
+ );
67
+ }
68
+ ```
69
+
70
+ #### Post Comment
71
+
72
+ ```typescript
73
+ function CommentForm({ postId }) {
74
+ const { isAllowed, requireAuth, userId } = useAuthRequired();
75
+ const [comment, setComment] = useState('');
76
+
77
+ const handleSubmit = () => {
78
+ if (!isAllowed) {
79
+ requireAuth(); // Open auth modal
80
+ return;
81
+ }
82
+
83
+ // Submit comment
84
+ submitComment(postId, userId, comment);
85
+ setComment('');
86
+ };
87
+
88
+ return (
89
+ <View>
90
+ <TextInput
91
+ value={comment}
92
+ onChangeText={setComment}
93
+ placeholder={isAllowed ? "Write your comment..." : "Sign in to comment"}
94
+ editable={isAllowed}
95
+ />
96
+ <Button onPress={handleSubmit} disabled={!isAllowed}>
97
+ {isAllowed ? 'Submit' : 'Sign In'}
98
+ </Button>
99
+ </View>
100
+ );
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ## useRequireAuth
107
+
108
+ For components that **must** have an authenticated user. Throws if not authenticated.
109
+
110
+ ### Usage
111
+
112
+ ```typescript
113
+ import { useRequireAuth } from '@umituz/react-native-auth';
114
+
115
+ function UserProfile() {
116
+ const userId = useRequireAuth(); // string, not null
117
+
118
+ useEffect(() => {
119
+ // userId is guaranteed to be string
120
+ fetchUserData(userId);
121
+ }, [userId]);
122
+
123
+ return <ProfileContent userId={userId} />;
124
+ }
125
+ ```
126
+
127
+ ### useUserId (Safe Alternative)
128
+
129
+ Returns null if user is not authenticated:
130
+
131
+ ```typescript
132
+ import { useUserId } from '@umituz/react-native-auth';
133
+
134
+ function MaybeUserProfile() {
135
+ const userId = useUserId(); // string | null
136
+
137
+ if (!userId) {
138
+ return <LoginPrompt />;
139
+ }
140
+
141
+ return <ProfileContent userId={userId} />;
142
+ }
143
+ ```
144
+
145
+ ### Examples
146
+
147
+ #### Order History
148
+
149
+ ```typescript
150
+ function OrderHistory() {
151
+ const userId = useRequireAuth(); // User must be authenticated
152
+
153
+ const { data: orders, isLoading } = useQuery({
154
+ queryKey: ['orders', userId],
155
+ queryFn: () => fetchOrders(userId),
156
+ });
157
+
158
+ if (isLoading) return <LoadingSpinner />;
159
+
160
+ return (
161
+ <FlatList
162
+ data={orders}
163
+ renderItem={({ item }) => <OrderCard order={item} />}
164
+ />
165
+ );
166
+ }
167
+ ```
168
+
169
+ #### User Settings
170
+
171
+ ```typescript
172
+ function UserSettings() {
173
+ const userId = useRequireAuth();
174
+
175
+ const updateSettings = async (settings: UserSettings) => {
176
+ await updateUserSettings(userId, settings);
177
+ };
178
+
179
+ return <SettingsForm onSave={updateSettings} />;
180
+ }
181
+ ```
182
+
183
+ ### Error Handling
184
+
185
+ Wrap components using `useRequireAuth` with Error Boundary:
186
+
187
+ ```typescript
188
+ function App() {
189
+ return (
190
+ <ErrorBoundary fallback={<LoginScreen />}>
191
+ <Routes>
192
+ <Route path="/settings" element={<UserSettings />} />
193
+ <Route path="/orders" element={<OrderHistory />} />
194
+ </Routes>
195
+ </ErrorBoundary>
196
+ );
197
+ }
198
+ ```
199
+
200
+ ## Comparison Table
201
+
202
+ | Situation | Hook | Why |
203
+ |-----------|------|-----|
204
+ | Check auth before action | `useAuthRequired` | Can show modal, graceful degradation |
205
+ | Show auth modal | `useAuthRequired` | Has `requireAuth()` method |
206
+ | Component requires auth | `useRequireAuth` | Type-safe, non-null userId |
207
+ | Optional auth | `useUserId` | Safe, can return null |
208
+
209
+ ## Code Comparison
210
+
211
+ ```typescript
212
+ // ❌ Wrong - useRequireAuth with modal attempt
213
+ function BadComponent() {
214
+ const userId = useRequireAuth(); // Will throw!
215
+
216
+ const handleClick = () => {
217
+ // Never reaches here
218
+ };
219
+ }
220
+
221
+ // ✅ Good - useAuthRequired with modal
222
+ function GoodComponent() {
223
+ const { isAllowed, requireAuth } = useAuthRequired();
224
+
225
+ const handleClick = () => {
226
+ if (!isAllowed) {
227
+ requireAuth(); // Show modal
228
+ return;
229
+ }
230
+ // Perform action
231
+ };
232
+ }
233
+
234
+ // ✅ Good - useRequireAuth for required auth
235
+ function ProtectedComponent() {
236
+ const userId = useRequireAuth(); // Type-safe: string
237
+
238
+ // Use userId
239
+ useEffect(() => {
240
+ fetchUserData(userId);
241
+ }, [userId]);
242
+ }
243
+ ```
244
+
245
+ ## Related Hooks
246
+
247
+ - [`useAuth`](./useAuth.md) - Main auth state management
248
+ - [`useAuthModalStore`](../stores/authModalStore.ts) - Auth modal state