@umituz/web-firebase 3.2.3 → 3.3.0
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/package.json +5 -2
- package/src/application/use-cases/auth/sign-in-with-google.use-case.ts +13 -11
- package/src/domain/interfaces/file.repository.interface.ts +28 -3
- package/src/domain/interfaces/user.repository.interface.ts +12 -40
- package/src/domains/firestore/services/firestore.service.ts +5 -1
- package/src/domains/storage/services/storage.service.ts +5 -1
- package/src/index.ts +2 -11
- package/src/infrastructure/firebase/auth.adapter.ts +7 -3
- package/src/infrastructure/firebase/client.ts +98 -44
- package/src/infrastructure/firebase/firestore.adapter.ts +5 -1
- package/src/infrastructure/firebase/storage.adapter.ts +5 -1
- package/src/presentation/hooks/useAuth.ts +0 -392
- package/src/presentation/hooks/useFirebaseAuth.ts +0 -122
- package/src/presentation/hooks/useFirestore.ts +0 -125
- package/src/presentation/hooks/useStorage.ts +0 -141
- package/src/presentation/index.ts +0 -10
- package/src/presentation/providers/FirebaseProvider.tsx +0 -90
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth Hook
|
|
3
|
-
* @description React hook for authentication with Google & Apple OAuth
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { useCallback, useEffect, useState } from 'react'
|
|
7
|
-
import type { User as FirebaseUser } from 'firebase/auth'
|
|
8
|
-
import type { User as FirestoreUser } from '../../domains/firestore/entities'
|
|
9
|
-
import { authService } from '../../domains/auth/services'
|
|
10
|
-
import { firestoreService } from '../../domains/firestore/services'
|
|
11
|
-
import { useFirebaseContext } from '../providers/FirebaseProvider'
|
|
12
|
-
import { getAuthConfig } from '../../domain/config/auth.config'
|
|
13
|
-
|
|
14
|
-
export interface UseAuthResult {
|
|
15
|
-
// State
|
|
16
|
-
firebaseUser: FirebaseUser | null
|
|
17
|
-
user: FirestoreUser | null
|
|
18
|
-
loading: boolean
|
|
19
|
-
error: Error | null
|
|
20
|
-
isAuthenticated: boolean
|
|
21
|
-
isEmailVerified: boolean
|
|
22
|
-
|
|
23
|
-
// Email/Password Auth
|
|
24
|
-
signIn: (email: string, password: string) => Promise<FirebaseUser>
|
|
25
|
-
signUp: (email: string, password: string, displayName: string) => 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
|
|
37
|
-
signOut: () => Promise<void>
|
|
38
|
-
sendPasswordReset: (email: string) => Promise<void>
|
|
39
|
-
resendEmailVerification: () => Promise<void>
|
|
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
|
|
50
|
-
refreshUser: () => Promise<void>
|
|
51
|
-
|
|
52
|
-
// Config
|
|
53
|
-
googleEnabled: boolean
|
|
54
|
-
appleEnabled: boolean
|
|
55
|
-
emailPasswordEnabled: boolean
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function useAuth(): UseAuthResult {
|
|
59
|
-
const { instances, loading, error } = useFirebaseContext()
|
|
60
|
-
const [user, setUser] = useState<FirestoreUser | null>(null)
|
|
61
|
-
const config = getAuthConfig()
|
|
62
|
-
|
|
63
|
-
// Fetch user data from Firestore
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
const fetchUser = async () => {
|
|
66
|
-
const currentUser = instances?.auth.currentUser
|
|
67
|
-
if (currentUser) {
|
|
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
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
setUser(null)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
fetchUser()
|
|
80
|
-
}, [instances?.auth.currentUser])
|
|
81
|
-
|
|
82
|
-
// Email/Password Sign In
|
|
83
|
-
const signIn = useCallback(async (email: string, password: string) => {
|
|
84
|
-
const result = await authService.signIn(email, password)
|
|
85
|
-
return result.user
|
|
86
|
-
}, [])
|
|
87
|
-
|
|
88
|
-
// Email/Password Sign Up
|
|
89
|
-
const signUp = useCallback(async (email: string, password: string, displayName: string) => {
|
|
90
|
-
const userCredential = await authService.signUp(email, password, displayName)
|
|
91
|
-
|
|
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
|
-
},
|
|
125
|
-
},
|
|
126
|
-
subscription: {
|
|
127
|
-
plan: config.getConfig().defaultSubscriptionPlan ?? 'free',
|
|
128
|
-
status: 'active',
|
|
129
|
-
cancelAtPeriodEnd: false,
|
|
130
|
-
createdAt: now,
|
|
131
|
-
updatedAt: now,
|
|
132
|
-
},
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return userCredential.user
|
|
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
|
-
}
|
|
190
|
-
|
|
191
|
-
return result.user
|
|
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])
|
|
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
|
|
281
|
-
const signOut = useCallback(async () => {
|
|
282
|
-
await authService.signOut()
|
|
283
|
-
setUser(null)
|
|
284
|
-
}, [])
|
|
285
|
-
|
|
286
|
-
// Password Reset
|
|
287
|
-
const sendPasswordReset = useCallback(async (email: string) => {
|
|
288
|
-
await authService.sendPasswordReset(email)
|
|
289
|
-
}, [])
|
|
290
|
-
|
|
291
|
-
// Email Verification
|
|
292
|
-
const resendEmailVerification = useCallback(async () => {
|
|
293
|
-
await authService.resendEmailVerification()
|
|
294
|
-
}, [])
|
|
295
|
-
|
|
296
|
-
// Update Profile
|
|
297
|
-
const updateProfile = useCallback(async (updates: { displayName?: string; photoURL?: string }) => {
|
|
298
|
-
await authService.updateProfile(updates)
|
|
299
|
-
|
|
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
|
|
313
|
-
const currentUser = instances?.auth.currentUser
|
|
314
|
-
if (currentUser) {
|
|
315
|
-
const userData = await firestoreService.getUser(currentUser.uid)
|
|
316
|
-
setUser(userData)
|
|
317
|
-
}
|
|
318
|
-
}, [instances])
|
|
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
|
|
341
|
-
const refreshUser = useCallback(async () => {
|
|
342
|
-
const currentUser = instances?.auth.currentUser
|
|
343
|
-
if (currentUser) {
|
|
344
|
-
const userData = await firestoreService.getUser(currentUser.uid)
|
|
345
|
-
setUser(userData)
|
|
346
|
-
}
|
|
347
|
-
}, [instances])
|
|
348
|
-
|
|
349
|
-
return {
|
|
350
|
-
// State
|
|
351
|
-
firebaseUser: instances?.auth.currentUser || null,
|
|
352
|
-
user,
|
|
353
|
-
loading,
|
|
354
|
-
error,
|
|
355
|
-
isAuthenticated: !!instances?.auth.currentUser,
|
|
356
|
-
isEmailVerified: instances?.auth.currentUser?.emailVerified || false,
|
|
357
|
-
|
|
358
|
-
// Email/Password Auth
|
|
359
|
-
signIn,
|
|
360
|
-
signUp,
|
|
361
|
-
|
|
362
|
-
// OAuth Providers
|
|
363
|
-
signInWithGoogle: signInWithGoogleCallback,
|
|
364
|
-
signInWithApple: signInWithAppleCallback,
|
|
365
|
-
|
|
366
|
-
// Provider Management
|
|
367
|
-
linkGoogle: linkGoogleCallback,
|
|
368
|
-
linkApple: linkAppleCallback,
|
|
369
|
-
unlinkProvider: unlinkProviderCallback,
|
|
370
|
-
|
|
371
|
-
// Account Management
|
|
372
|
-
signOut,
|
|
373
|
-
sendPasswordReset,
|
|
374
|
-
resendEmailVerification,
|
|
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
|
|
385
|
-
refreshUser,
|
|
386
|
-
|
|
387
|
-
// Config
|
|
388
|
-
googleEnabled: config.isGoogleEnabled(),
|
|
389
|
-
appleEnabled: config.isAppleEnabled(),
|
|
390
|
-
emailPasswordEnabled: config.isEmailPasswordEnabled(),
|
|
391
|
-
}
|
|
392
|
-
}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
type Auth,
|
|
4
|
-
type UserCredential,
|
|
5
|
-
type User,
|
|
6
|
-
onAuthStateChanged,
|
|
7
|
-
signInWithEmailAndPassword,
|
|
8
|
-
createUserWithEmailAndPassword,
|
|
9
|
-
signOut as firebaseSignOut,
|
|
10
|
-
updateProfile,
|
|
11
|
-
updatePassword,
|
|
12
|
-
sendPasswordResetEmail,
|
|
13
|
-
} from 'firebase/auth';
|
|
14
|
-
import type { FirebaseUser } from '../../domain/entities/firebase.entity';
|
|
15
|
-
|
|
16
|
-
function mapUser(u: User): FirebaseUser {
|
|
17
|
-
return {
|
|
18
|
-
uid: u.uid,
|
|
19
|
-
email: u.email,
|
|
20
|
-
displayName: u.displayName,
|
|
21
|
-
photoURL: u.photoURL,
|
|
22
|
-
emailVerified: u.emailVerified,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* useFirebaseAuth Hook
|
|
28
|
-
* @description Hook to manage Firebase authentication state and operations
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
export interface UseFirebaseAuthOptions {
|
|
32
|
-
onUserChange?: (user: FirebaseUser | null) => void;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface UseFirebaseAuthReturn {
|
|
36
|
-
user: FirebaseUser | null;
|
|
37
|
-
loading: boolean;
|
|
38
|
-
isAuthenticated: boolean;
|
|
39
|
-
signIn(email: string, password: string): Promise<UserCredential>;
|
|
40
|
-
signUp(email: string, password: string, name?: string): Promise<UserCredential>;
|
|
41
|
-
signOut(): Promise<void>;
|
|
42
|
-
updateUserProfile(name: string, photoURL?: string): Promise<void>;
|
|
43
|
-
updateUserPassword(newPassword: string): Promise<void>;
|
|
44
|
-
resetPassword(email: string): Promise<void>;
|
|
45
|
-
getIdToken(): Promise<string>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function useFirebaseAuth(
|
|
49
|
-
auth: Auth,
|
|
50
|
-
options?: UseFirebaseAuthOptions,
|
|
51
|
-
): UseFirebaseAuthReturn {
|
|
52
|
-
const [user, setUser] = useState<FirebaseUser | null>(null);
|
|
53
|
-
const [loading, setLoading] = useState(true);
|
|
54
|
-
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
const unsub = onAuthStateChanged(auth, (firebaseUser) => {
|
|
57
|
-
const mapped = firebaseUser ? mapUser(firebaseUser) : null;
|
|
58
|
-
setUser(mapped);
|
|
59
|
-
setLoading(false);
|
|
60
|
-
options?.onUserChange?.(mapped);
|
|
61
|
-
});
|
|
62
|
-
return unsub;
|
|
63
|
-
}, [auth, options]);
|
|
64
|
-
|
|
65
|
-
const signIn = useCallback(
|
|
66
|
-
(email: string, password: string) => signInWithEmailAndPassword(auth, email, password),
|
|
67
|
-
[auth],
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
const signUp = useCallback(
|
|
71
|
-
async (email: string, password: string, name?: string) => {
|
|
72
|
-
const cred = await createUserWithEmailAndPassword(auth, email, password);
|
|
73
|
-
if (name && cred.user) await updateProfile(cred.user, { displayName: name });
|
|
74
|
-
return cred;
|
|
75
|
-
},
|
|
76
|
-
[auth],
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
const signOut = useCallback(() => firebaseSignOut(auth), [auth]);
|
|
80
|
-
|
|
81
|
-
const updateUserProfile = useCallback(
|
|
82
|
-
async (name: string, photoURL?: string) => {
|
|
83
|
-
if (!auth.currentUser) throw new Error('No authenticated user');
|
|
84
|
-
await updateProfile(auth.currentUser, {
|
|
85
|
-
displayName: name,
|
|
86
|
-
...(photoURL !== undefined && { photoURL }),
|
|
87
|
-
});
|
|
88
|
-
},
|
|
89
|
-
[auth],
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
const updateUserPassword = useCallback(
|
|
93
|
-
async (newPassword: string) => {
|
|
94
|
-
if (!auth.currentUser) throw new Error('No authenticated user');
|
|
95
|
-
await updatePassword(auth.currentUser, newPassword);
|
|
96
|
-
},
|
|
97
|
-
[auth],
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
const resetPassword = useCallback(
|
|
101
|
-
(email: string) => sendPasswordResetEmail(auth, email),
|
|
102
|
-
[auth],
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
const getIdToken = useCallback(async () => {
|
|
106
|
-
if (!auth.currentUser) throw new Error('No authenticated user');
|
|
107
|
-
return auth.currentUser.getIdToken();
|
|
108
|
-
}, [auth]);
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
user,
|
|
112
|
-
loading,
|
|
113
|
-
isAuthenticated: !!user,
|
|
114
|
-
signIn,
|
|
115
|
-
signUp,
|
|
116
|
-
signOut,
|
|
117
|
-
updateUserProfile,
|
|
118
|
-
updateUserPassword,
|
|
119
|
-
resetPassword,
|
|
120
|
-
getIdToken,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firestore Hook
|
|
3
|
-
* @description React hook for Firestore real-time data
|
|
4
|
-
* Migrated from: /Users/umituz/Desktop/github/umituz/apps/web/app-growth-factory/src/domains/firebase/hooks/useFirestore.ts
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { useEffect, useState } from 'react'
|
|
8
|
-
import { doc, onSnapshot, query, collection, type QuerySnapshot, type DocumentData } from 'firebase/firestore'
|
|
9
|
-
import type { Firestore } from 'firebase/firestore'
|
|
10
|
-
|
|
11
|
-
export function useUser(db: Firestore, userId: string) {
|
|
12
|
-
const [user, setUser] = useState<any>(null)
|
|
13
|
-
const [loading, setLoading] = useState(true)
|
|
14
|
-
const [error, setError] = useState<Error | null>(null)
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
if (!userId) {
|
|
18
|
-
setUser(null)
|
|
19
|
-
setLoading(false)
|
|
20
|
-
return
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const unsubscribe = onSnapshot(doc(db, 'users', userId), (docSnap) => {
|
|
24
|
-
if (docSnap.exists()) {
|
|
25
|
-
setUser(docSnap.data())
|
|
26
|
-
} else {
|
|
27
|
-
setUser(null)
|
|
28
|
-
}
|
|
29
|
-
setLoading(false)
|
|
30
|
-
}, (err) => {
|
|
31
|
-
setError(err as Error)
|
|
32
|
-
setLoading(false)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
return () => unsubscribe()
|
|
36
|
-
}, [db, userId])
|
|
37
|
-
|
|
38
|
-
return { user, loading, error }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function useUserRealtime<T>(db: Firestore, collectionName: string, docId: string) {
|
|
42
|
-
const [data, setData] = useState<T | null>(null)
|
|
43
|
-
const [loading, setLoading] = useState(true)
|
|
44
|
-
const [error, setError] = useState<Error | null>(null)
|
|
45
|
-
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
if (!docId) {
|
|
48
|
-
setData(null)
|
|
49
|
-
setLoading(false)
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const unsubscribe = onSnapshot(doc(db, collectionName, docId), (docSnap) => {
|
|
54
|
-
if (docSnap.exists()) {
|
|
55
|
-
setData(docSnap.data() as T)
|
|
56
|
-
} else {
|
|
57
|
-
setData(null)
|
|
58
|
-
}
|
|
59
|
-
setLoading(false)
|
|
60
|
-
}, (err) => {
|
|
61
|
-
setError(err as Error)
|
|
62
|
-
setLoading(false)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
return () => unsubscribe()
|
|
66
|
-
}, [db, collectionName, docId])
|
|
67
|
-
|
|
68
|
-
return { data, loading, error }
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function useCollectionRealtime<T>(
|
|
72
|
-
db: Firestore,
|
|
73
|
-
collectionName: string,
|
|
74
|
-
constraints?: any[]
|
|
75
|
-
) {
|
|
76
|
-
const [data, setData] = useState<T[]>([])
|
|
77
|
-
const [loading, setLoading] = useState(true)
|
|
78
|
-
const [error, setError] = useState<Error | null>(null)
|
|
79
|
-
|
|
80
|
-
useEffect(() => {
|
|
81
|
-
const q = constraints
|
|
82
|
-
? query(collection(db, collectionName), ...constraints)
|
|
83
|
-
: collection(db, collectionName)
|
|
84
|
-
|
|
85
|
-
const unsubscribe = onSnapshot(q, (querySnap: QuerySnapshot<DocumentData>) => {
|
|
86
|
-
const items = querySnap.docs.map((doc) => ({ id: doc.id, ...doc.data() } as T))
|
|
87
|
-
setData(items)
|
|
88
|
-
setLoading(false)
|
|
89
|
-
}, (err) => {
|
|
90
|
-
setError(err as Error)
|
|
91
|
-
setLoading(false)
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
return () => unsubscribe()
|
|
95
|
-
}, [db, collectionName, JSON.stringify(constraints)])
|
|
96
|
-
|
|
97
|
-
return { data, loading, error }
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function useDocumentValue<T>(
|
|
101
|
-
db: Firestore,
|
|
102
|
-
collectionName: string,
|
|
103
|
-
docId: string
|
|
104
|
-
) {
|
|
105
|
-
const [data, setData] = useState<T | null>(null)
|
|
106
|
-
|
|
107
|
-
useEffect(() => {
|
|
108
|
-
if (!docId) {
|
|
109
|
-
setData(null)
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const unsubscribe = onSnapshot(doc(db, collectionName, docId), (docSnap) => {
|
|
114
|
-
if (docSnap.exists()) {
|
|
115
|
-
setData(docSnap.data() as T)
|
|
116
|
-
} else {
|
|
117
|
-
setData(null)
|
|
118
|
-
}
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
return () => unsubscribe()
|
|
122
|
-
}, [db, collectionName, docId])
|
|
123
|
-
|
|
124
|
-
return data
|
|
125
|
-
}
|