@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.
@@ -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
- }