@umituz/web-firebase 3.0.1 → 3.2.1

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.
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Auth Hook
3
- * @description React hook for authentication operations
4
- * Uses new domain services - no adapter injection needed
3
+ * @description React hook for authentication with Google & Apple OAuth
5
4
  */
6
5
 
7
6
  import { useCallback, useEffect, useState } from 'react'
@@ -10,34 +9,69 @@ import type { User as FirestoreUser } from '../../domains/firestore/entities'
10
9
  import { authService } from '../../domains/auth/services'
11
10
  import { firestoreService } from '../../domains/firestore/services'
12
11
  import { useFirebaseContext } from '../providers/FirebaseProvider'
12
+ import { getAuthConfig } from '../../domain/config/auth.config'
13
13
 
14
14
  export interface UseAuthResult {
15
+ // State
15
16
  firebaseUser: FirebaseUser | null
16
17
  user: FirestoreUser | null
17
18
  loading: boolean
18
19
  error: Error | null
19
20
  isAuthenticated: boolean
20
21
  isEmailVerified: boolean
22
+
23
+ // Email/Password Auth
21
24
  signIn: (email: string, password: string) => Promise<FirebaseUser>
22
25
  signUp: (email: string, password: string, displayName: string) => Promise<FirebaseUser>
23
- signInWithGoogle: () => Promise<FirebaseUser>
26
+
27
+ // OAuth Providers
28
+ signInWithGoogle: (useRedirect?: boolean) => Promise<FirebaseUser>
29
+ signInWithApple: (useRedirect?: boolean) => Promise<FirebaseUser>
30
+
31
+ // Provider Management
32
+ linkGoogle: () => Promise<void>
33
+ linkApple: () => Promise<void>
34
+ unlinkProvider: (providerId: string) => Promise<void>
35
+
36
+ // Account Management
24
37
  signOut: () => Promise<void>
25
38
  sendPasswordReset: (email: string) => Promise<void>
26
39
  resendEmailVerification: () => Promise<void>
27
40
  updateProfile: (updates: { displayName?: string; photoURL?: string }) => Promise<void>
41
+ updateEmail: (newEmail: string, password: string) => Promise<void>
42
+ updatePassword: (currentPassword: string, newPassword: string) => Promise<void>
43
+ deleteAccount: (password: string) => Promise<void>
44
+
45
+ // Token Management
46
+ getIdToken: (forceRefresh?: boolean) => Promise<string>
47
+ refreshToken: () => Promise<void>
48
+
49
+ // User Data
28
50
  refreshUser: () => Promise<void>
51
+
52
+ // Config
53
+ googleEnabled: boolean
54
+ appleEnabled: boolean
55
+ emailPasswordEnabled: boolean
29
56
  }
30
57
 
31
58
  export function useAuth(): UseAuthResult {
32
59
  const { instances, loading, error } = useFirebaseContext()
33
60
  const [user, setUser] = useState<FirestoreUser | null>(null)
61
+ const config = getAuthConfig()
34
62
 
63
+ // Fetch user data from Firestore
35
64
  useEffect(() => {
36
65
  const fetchUser = async () => {
37
66
  const currentUser = instances?.auth.currentUser
38
67
  if (currentUser) {
39
- const userData = await firestoreService.getUser(currentUser.uid)
40
- setUser(userData)
68
+ try {
69
+ const userData = await firestoreService.getUser(currentUser.uid)
70
+ setUser(userData)
71
+ } catch (err) {
72
+ console.error('Error fetching user data:', err)
73
+ setUser(null)
74
+ }
41
75
  } else {
42
76
  setUser(null)
43
77
  }
@@ -45,78 +79,237 @@ export function useAuth(): UseAuthResult {
45
79
  fetchUser()
46
80
  }, [instances?.auth.currentUser])
47
81
 
82
+ // Email/Password Sign In
48
83
  const signIn = useCallback(async (email: string, password: string) => {
49
84
  const result = await authService.signIn(email, password)
50
85
  return result.user
51
86
  }, [])
52
87
 
88
+ // Email/Password Sign Up
53
89
  const signUp = useCallback(async (email: string, password: string, displayName: string) => {
54
90
  const userCredential = await authService.signUp(email, password, displayName)
55
91
 
56
- // Create user profile in Firestore
57
- const now = Date.now()
58
- await firestoreService.createUser(userCredential.user.uid, {
59
- profile: {
60
- id: userCredential.user.uid,
61
- email: email,
62
- displayName: displayName,
63
- createdAt: now,
64
- updatedAt: now,
65
- lastLoginAt: now,
66
- emailVerified: false,
67
- },
68
- settings: {
69
- theme: 'light',
70
- language: 'tr',
71
- timezone: 'Europe/Istanbul',
72
- currency: 'TRY',
73
- notifications: {
74
- email: true,
75
- push: true,
76
- marketing: false,
77
- security: true,
78
- weeklyDigest: false,
92
+ // Create user profile in Firestore if auto-create is enabled
93
+ if (config.shouldCreateUserDocument()) {
94
+ const now = Date.now()
95
+ const defaultSettings = config.getConfig().defaultUserSettings
96
+
97
+ await firestoreService.createUser(userCredential.user.uid, {
98
+ profile: {
99
+ id: userCredential.user.uid,
100
+ email: email,
101
+ displayName: displayName,
102
+ createdAt: now,
103
+ updatedAt: now,
104
+ lastLoginAt: now,
105
+ emailVerified: false,
106
+ },
107
+ settings: {
108
+ theme: defaultSettings?.theme ?? 'system',
109
+ language: defaultSettings?.language ?? 'en',
110
+ timezone: defaultSettings?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone,
111
+ currency: defaultSettings?.currency ?? 'USD',
112
+ notifications: {
113
+ email: defaultSettings?.notifications?.email ?? true,
114
+ push: defaultSettings?.notifications?.push ?? true,
115
+ marketing: defaultSettings?.notifications?.marketing ?? false,
116
+ security: defaultSettings?.notifications?.security ?? true,
117
+ weeklyDigest: defaultSettings?.notifications?.weeklyDigest ?? false,
118
+ },
119
+ privacy: {
120
+ profileVisibility: defaultSettings?.privacy?.profileVisibility ?? 'public',
121
+ showEmail: defaultSettings?.privacy?.showEmail ?? false,
122
+ showPhone: defaultSettings?.privacy?.showPhone ?? false,
123
+ dataSharing: defaultSettings?.privacy?.dataSharing ?? false,
124
+ },
79
125
  },
80
- privacy: {
81
- profileVisibility: 'public',
82
- showEmail: false,
83
- showPhone: false,
84
- dataSharing: false,
126
+ subscription: {
127
+ plan: config.getConfig().defaultSubscriptionPlan ?? 'free',
128
+ status: 'active',
129
+ cancelAtPeriodEnd: false,
130
+ createdAt: now,
131
+ updatedAt: now,
85
132
  },
86
- },
87
- subscription: {
88
- plan: 'free',
89
- status: 'active',
90
- cancelAtPeriodEnd: false,
91
- createdAt: now,
92
- updatedAt: now,
93
- },
94
- })
133
+ })
134
+ }
95
135
 
96
136
  return userCredential.user
97
- }, [])
137
+ }, [config])
138
+
139
+ // Google Sign In
140
+ const signInWithGoogleCallback = useCallback(async (useRedirect = false): Promise<FirebaseUser> => {
141
+ const result = await authService.signInWithGoogle(useRedirect)
142
+
143
+ // Create user profile in Firestore if it doesn't exist
144
+ if (config.shouldCreateUserDocument()) {
145
+ const existingUser = await firestoreService.getUser(result.user.uid)
146
+ if (!existingUser) {
147
+ const now = Date.now()
148
+ const defaultSettings = config.getConfig().defaultUserSettings
149
+
150
+ await firestoreService.createUser(result.user.uid, {
151
+ profile: {
152
+ id: result.user.uid,
153
+ email: result.user.email ?? '',
154
+ displayName: result.user.displayName ?? '',
155
+ photoURL: result.user.photoURL,
156
+ createdAt: now,
157
+ updatedAt: now,
158
+ lastLoginAt: now,
159
+ emailVerified: result.user.emailVerified,
160
+ },
161
+ settings: {
162
+ theme: defaultSettings?.theme ?? 'system',
163
+ language: defaultSettings?.language ?? 'en',
164
+ timezone: defaultSettings?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone,
165
+ currency: defaultSettings?.currency ?? 'USD',
166
+ notifications: {
167
+ email: defaultSettings?.notifications?.email ?? true,
168
+ push: defaultSettings?.notifications?.push ?? true,
169
+ marketing: defaultSettings?.notifications?.marketing ?? false,
170
+ security: defaultSettings?.notifications?.security ?? true,
171
+ weeklyDigest: defaultSettings?.notifications?.weeklyDigest ?? false,
172
+ },
173
+ privacy: {
174
+ profileVisibility: defaultSettings?.privacy?.profileVisibility ?? 'public',
175
+ showEmail: defaultSettings?.privacy?.showEmail ?? false,
176
+ showPhone: defaultSettings?.privacy?.showPhone ?? false,
177
+ dataSharing: defaultSettings?.privacy?.dataSharing ?? false,
178
+ },
179
+ },
180
+ subscription: {
181
+ plan: config.getConfig().defaultSubscriptionPlan ?? 'free',
182
+ status: 'active',
183
+ cancelAtPeriodEnd: false,
184
+ createdAt: now,
185
+ updatedAt: now,
186
+ },
187
+ })
188
+ }
189
+ }
98
190
 
99
- const signInWithGoogleCallback = useCallback(async () => {
100
- const result = await authService.signInWithGoogle()
101
191
  return result.user
102
- }, [])
192
+ }, [config])
193
+
194
+ // Apple Sign In
195
+ const signInWithAppleCallback = useCallback(async (useRedirect = false): Promise<FirebaseUser> => {
196
+ const result = await authService.signInWithApple(useRedirect)
197
+
198
+ // Create user profile in Firestore if it doesn't exist
199
+ if (config.shouldCreateUserDocument()) {
200
+ const existingUser = await firestoreService.getUser(result.user.uid)
201
+ if (!existingUser) {
202
+ const now = Date.now()
203
+ const defaultSettings = config.getConfig().defaultUserSettings
204
+
205
+ await firestoreService.createUser(result.user.uid, {
206
+ profile: {
207
+ id: result.user.uid,
208
+ email: result.user.email ?? '',
209
+ displayName: result.user.displayName ?? '',
210
+ photoURL: result.user.photoURL,
211
+ createdAt: now,
212
+ updatedAt: now,
213
+ lastLoginAt: now,
214
+ emailVerified: result.user.emailVerified,
215
+ },
216
+ settings: {
217
+ theme: defaultSettings?.theme ?? 'system',
218
+ language: defaultSettings?.language ?? 'en',
219
+ timezone: defaultSettings?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone,
220
+ currency: defaultSettings?.currency ?? 'USD',
221
+ notifications: {
222
+ email: defaultSettings?.notifications?.email ?? true,
223
+ push: defaultSettings?.notifications?.push ?? true,
224
+ marketing: defaultSettings?.notifications?.marketing ?? false,
225
+ security: defaultSettings?.notifications?.security ?? true,
226
+ weeklyDigest: defaultSettings?.notifications?.weeklyDigest ?? false,
227
+ },
228
+ privacy: {
229
+ profileVisibility: defaultSettings?.privacy?.profileVisibility ?? 'public',
230
+ showEmail: defaultSettings?.privacy?.showEmail ?? false,
231
+ showPhone: defaultSettings?.privacy?.showPhone ?? false,
232
+ dataSharing: defaultSettings?.privacy?.dataSharing ?? false,
233
+ },
234
+ },
235
+ subscription: {
236
+ plan: config.getConfig().defaultSubscriptionPlan ?? 'free',
237
+ status: 'active',
238
+ cancelAtPeriodEnd: false,
239
+ createdAt: now,
240
+ updatedAt: now,
241
+ },
242
+ })
243
+ }
244
+ }
245
+
246
+ return result.user
247
+ }, [config])
248
+
249
+ // Provider Linking
250
+ const linkGoogleCallback = useCallback(async () => {
251
+ await authService.linkGoogle()
252
+ // Refresh user data
253
+ const currentUser = instances?.auth.currentUser
254
+ if (currentUser) {
255
+ const userData = await firestoreService.getUser(currentUser.uid)
256
+ setUser(userData)
257
+ }
258
+ }, [instances])
259
+
260
+ const linkAppleCallback = useCallback(async () => {
261
+ await authService.linkApple()
262
+ // Refresh user data
263
+ const currentUser = instances?.auth.currentUser
264
+ if (currentUser) {
265
+ const userData = await firestoreService.getUser(currentUser.uid)
266
+ setUser(userData)
267
+ }
268
+ }, [instances])
103
269
 
270
+ const unlinkProviderCallback = useCallback(async (providerId: string) => {
271
+ await authService.unlinkProvider(providerId)
272
+ // Refresh user data
273
+ const currentUser = instances?.auth.currentUser
274
+ if (currentUser) {
275
+ const userData = await firestoreService.getUser(currentUser.uid)
276
+ setUser(userData)
277
+ }
278
+ }, [instances])
279
+
280
+ // Sign Out
104
281
  const signOut = useCallback(async () => {
105
282
  await authService.signOut()
283
+ setUser(null)
106
284
  }, [])
107
285
 
286
+ // Password Reset
108
287
  const sendPasswordReset = useCallback(async (email: string) => {
109
288
  await authService.sendPasswordReset(email)
110
289
  }, [])
111
290
 
291
+ // Email Verification
112
292
  const resendEmailVerification = useCallback(async () => {
113
293
  await authService.resendEmailVerification()
114
294
  }, [])
115
295
 
296
+ // Update Profile
116
297
  const updateProfile = useCallback(async (updates: { displayName?: string; photoURL?: string }) => {
117
298
  await authService.updateProfile(updates)
118
299
 
119
- // Refresh user data from Firestore if available
300
+ // Refresh user data from Firestore
301
+ const currentUser = instances?.auth.currentUser
302
+ if (currentUser) {
303
+ const userData = await firestoreService.getUser(currentUser.uid)
304
+ setUser(userData)
305
+ }
306
+ }, [instances])
307
+
308
+ // Update Email
309
+ const updateEmailCallback = useCallback(async (newEmail: string, password: string) => {
310
+ await authService.updateEmail(newEmail, password)
311
+
312
+ // Refresh user data
120
313
  const currentUser = instances?.auth.currentUser
121
314
  if (currentUser) {
122
315
  const userData = await firestoreService.getUser(currentUser.uid)
@@ -124,6 +317,27 @@ export function useAuth(): UseAuthResult {
124
317
  }
125
318
  }, [instances])
126
319
 
320
+ // Update Password
321
+ const updatePasswordCallback = useCallback(async (currentPassword: string, newPassword: string) => {
322
+ await authService.updatePassword(currentPassword, newPassword)
323
+ }, [])
324
+
325
+ // Delete Account
326
+ const deleteAccountCallback = useCallback(async (password: string) => {
327
+ await authService.deleteAccount(password)
328
+ setUser(null)
329
+ }, [])
330
+
331
+ // Token Management
332
+ const getIdTokenCallback = useCallback(async (forceRefresh = false) => {
333
+ return await authService.getIdToken(forceRefresh)
334
+ }, [])
335
+
336
+ const refreshTokenCallback = useCallback(async () => {
337
+ await authService.refreshToken()
338
+ }, [])
339
+
340
+ // Refresh User Data
127
341
  const refreshUser = useCallback(async () => {
128
342
  const currentUser = instances?.auth.currentUser
129
343
  if (currentUser) {
@@ -133,19 +347,46 @@ export function useAuth(): UseAuthResult {
133
347
  }, [instances])
134
348
 
135
349
  return {
350
+ // State
136
351
  firebaseUser: instances?.auth.currentUser || null,
137
352
  user,
138
353
  loading,
139
354
  error,
140
355
  isAuthenticated: !!instances?.auth.currentUser,
141
356
  isEmailVerified: instances?.auth.currentUser?.emailVerified || false,
357
+
358
+ // Email/Password Auth
142
359
  signIn,
143
360
  signUp,
361
+
362
+ // OAuth Providers
144
363
  signInWithGoogle: signInWithGoogleCallback,
364
+ signInWithApple: signInWithAppleCallback,
365
+
366
+ // Provider Management
367
+ linkGoogle: linkGoogleCallback,
368
+ linkApple: linkAppleCallback,
369
+ unlinkProvider: unlinkProviderCallback,
370
+
371
+ // Account Management
145
372
  signOut,
146
373
  sendPasswordReset,
147
374
  resendEmailVerification,
148
375
  updateProfile,
376
+ updateEmail: updateEmailCallback,
377
+ updatePassword: updatePasswordCallback,
378
+ deleteAccount: deleteAccountCallback,
379
+
380
+ // Token Management
381
+ getIdToken: getIdTokenCallback,
382
+ refreshToken: refreshTokenCallback,
383
+
384
+ // User Data
149
385
  refreshUser,
386
+
387
+ // Config
388
+ googleEnabled: config.isGoogleEnabled(),
389
+ appleEnabled: config.isAppleEnabled(),
390
+ emailPasswordEnabled: config.isEmailPasswordEnabled(),
150
391
  }
151
392
  }