Spaces:
Sleeping
Sleeping
| 'use client'; | |
| import { useState, useEffect, createContext, useContext, type ReactNode } from 'react'; | |
| import type { User } from 'firebase/auth'; | |
| import { auth, database } from '@/firebase/client'; | |
| import { | |
| onAuthStateChanged, | |
| signInWithPopup, | |
| GoogleAuthProvider, | |
| signOut as firebaseSignOut, | |
| updateProfile, | |
| signInWithEmailAndPassword, | |
| createUserWithEmailAndPassword, | |
| deleteUser | |
| } from 'firebase/auth'; | |
| import { ref, set, get, update, remove } from 'firebase/database'; | |
| import { useToast } from '@/hooks/use-toast'; | |
| import { Loader2 } from 'lucide-react'; | |
| export interface UserMetadata { | |
| age: number; | |
| location: string; | |
| createdAt: string; | |
| displayName: string; | |
| email: string; | |
| photoURL: string; | |
| bio?: string; | |
| gender?: string; | |
| occupation?: string; | |
| interests?: string; | |
| } | |
| interface AuthContextType { | |
| user: User | null; | |
| userData: UserMetadata | null; | |
| loading: boolean; | |
| signInWithGoogle: () => Promise<void>; | |
| signInWithUsername: (username: string, pass: string, age: number, location: string, extra?: Partial<UserMetadata>) => Promise<void>; | |
| signOut: () => Promise<void>; | |
| updateUserProfile: (data: Partial<UserMetadata>) => Promise<void>; | |
| deleteUserAccount: () => Promise<void>; | |
| completeProfile: (data: Partial<UserMetadata>) => Promise<void>; | |
| } | |
| const AuthContext = createContext<AuthContextType | undefined>(undefined); | |
| export const AuthProvider = ({ children }: { children: ReactNode }) => { | |
| const [user, setUser] = useState<User | null>(null); | |
| const [userData, setUserData] = useState<UserMetadata | null>(null); | |
| const [loading, setLoading] = useState(true); | |
| const { toast } = useToast(); | |
| const fetchUserData = async (uid: string) => { | |
| const userRef = ref(database, 'users/' + uid); | |
| const snapshot = await get(userRef); | |
| if (snapshot.exists()) { | |
| setUserData(snapshot.val()); | |
| } else { | |
| setUserData(null); | |
| } | |
| }; | |
| useEffect(() => { | |
| const unsubscribe = onAuthStateChanged(auth, async (currentUser) => { | |
| setUser(currentUser); | |
| if (currentUser) { | |
| await fetchUserData(currentUser.uid); | |
| } else { | |
| setUserData(null); | |
| } | |
| setLoading(false); | |
| }); | |
| return () => unsubscribe(); | |
| }, []); | |
| const handleNewUser = async (user: User, data: Partial<UserMetadata> & { customName?: string }) => { | |
| const userRef = ref(database, 'users/' + user.uid); | |
| const payload: UserMetadata = { | |
| displayName: data.customName || user.displayName || 'مستخدم جديد', | |
| email: user.email || '', | |
| photoURL: user.photoURL || `https://api.dicebear.com/7.x/avataaars/svg?seed=${user.uid}`, | |
| createdAt: new Date().toISOString(), | |
| age: data.age || 18, | |
| location: data.location || '', | |
| bio: data.bio || '', | |
| gender: data.gender || '', | |
| occupation: data.occupation || '', | |
| interests: data.interests || '' | |
| }; | |
| await set(userRef, payload); | |
| if (data.customName) { | |
| await updateProfile(user, { displayName: data.customName }); | |
| } | |
| setUserData(payload); | |
| }; | |
| const signInWithGoogle = async () => { | |
| const provider = new GoogleAuthProvider(); | |
| try { | |
| const result = await signInWithPopup(auth, provider); | |
| const userRef = ref(database, 'users/' + result.user.uid); | |
| const snapshot = await get(userRef); | |
| if (!snapshot.exists()) { | |
| toast({ title: "يرجى إكمال بياناتك للمتابعة" }); | |
| } else { | |
| setUserData(snapshot.val()); | |
| toast({ title: `مرحباً بك ${result.user.displayName}` }); | |
| } | |
| } catch (error: any) { | |
| console.error("Sign-in error:", error); | |
| toast({ title: "فشل تسجيل الدخول", variant: "destructive" }); | |
| } | |
| }; | |
| const signInWithUsername = async (username: string, pass: string, age: number, location: string, extra?: Partial<UserMetadata>) => { | |
| const fakeEmail = `${username.toLowerCase().trim()}@proto.chat`; | |
| try { | |
| setLoading(true); | |
| const result = await signInWithEmailAndPassword(auth, fakeEmail, pass); | |
| await fetchUserData(result.user.uid); | |
| } catch (error: any) { | |
| if (error.code === 'auth/user-not-found' || error.code === 'auth/invalid-credential' || error.code === 'auth/invalid-email') { | |
| const result = await createUserWithEmailAndPassword(auth, fakeEmail, pass); | |
| await handleNewUser(result.user, { age, location, customName: username, ...extra }); | |
| } else { | |
| toast({ title: "خطأ في تسجيل الدخول", variant: "destructive" }); | |
| } | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const completeProfile = async (data: Partial<UserMetadata>) => { | |
| if (!user) return; | |
| const userRef = ref(database, 'users/' + user.uid); | |
| const existingData = userData || {}; | |
| const newData = { | |
| ...existingData, | |
| ...data, | |
| displayName: data.displayName || user.displayName || 'مستخدم', | |
| email: user.email || '', | |
| photoURL: user.photoURL || `https://api.dicebear.com/7.x/avataaars/svg?seed=${user.uid}`, | |
| createdAt: existingData.createdAt || new Date().toISOString(), | |
| }; | |
| await set(userRef, newData); | |
| setUserData(newData as UserMetadata); | |
| }; | |
| const signOut = async () => { | |
| await firebaseSignOut(auth); | |
| setUser(null); | |
| setUserData(null); | |
| }; | |
| const updateUserProfile = async (data: Partial<UserMetadata>) => { | |
| if (!user) return; | |
| if (data.displayName) { | |
| await updateProfile(user, { displayName: data.displayName }); | |
| } | |
| const userRef = ref(database, 'users/' + user.uid); | |
| await update(userRef, data); | |
| await fetchUserData(user.uid); | |
| toast({ title: "تم التحديث بنجاح" }); | |
| }; | |
| const deleteUserAccount = async () => { | |
| if (!user) return; | |
| const userRef = ref(database, 'users/' + user.uid); | |
| await remove(userRef); | |
| await deleteUser(user); | |
| toast({ title: "تم حذف الحساب" }); | |
| }; | |
| if (loading) { | |
| return ( | |
| <div className="flex h-screen w-full flex-col items-center justify-center bg-background gap-4"> | |
| <Loader2 className="h-12 w-12 animate-spin text-primary" /> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <AuthContext.Provider value={{ user, userData, loading, signInWithGoogle, signInWithUsername, signOut, updateUserProfile, deleteUserAccount, completeProfile }}> | |
| {children} | |
| </AuthContext.Provider> | |
| ); | |
| }; | |
| export const useAuth = () => { | |
| const context = useContext(AuthContext); | |
| if (!context) throw new Error('useAuth must be used within AuthProvider'); | |
| return context; | |
| }; | |