Spaces:
Sleeping
Sleeping
| import { useState, useEffect, createContext, useContext, ReactNode, useCallback } from "react"; | |
| export interface AuthUser { | |
| id: number; | |
| name: string; | |
| email: string; | |
| team: string; | |
| role: string; | |
| avatarColor: string; | |
| createdAt: string; | |
| } | |
| interface AuthContextType { | |
| user: AuthUser | null; | |
| token: string | null; | |
| login: (email: string, password: string) => Promise<void>; | |
| logout: () => void; | |
| isLoading: boolean; | |
| error: string | null; | |
| // Legacy compatibility for pages still using activeUser | |
| activeUser: AuthUser | null; | |
| setActiveUserId: (id: number | null) => void; | |
| } | |
| const AuthContext = createContext<AuthContextType>({ | |
| user: null, | |
| token: null, | |
| login: async () => {}, | |
| logout: () => {}, | |
| isLoading: false, | |
| error: null, | |
| activeUser: null, | |
| setActiveUserId: () => {}, | |
| }); | |
| export function AuthProvider({ children }: { children: ReactNode }) { | |
| const [user, setUser] = useState<AuthUser | null>(null); | |
| const [token, setToken] = useState<string | null>(null); | |
| const [isLoading, setIsLoading] = useState(true); | |
| const [error, setError] = useState<string | null>(null); | |
| // On mount, restore from localStorage | |
| useEffect(() => { | |
| const savedToken = localStorage.getItem("teamtasker_token"); | |
| const savedUser = localStorage.getItem("teamtasker_user"); | |
| if (savedToken && savedUser) { | |
| try { | |
| const u = JSON.parse(savedUser) as AuthUser; | |
| setToken(savedToken); | |
| setUser(u); | |
| // Verify token is still valid | |
| fetch("/api/auth/me", { | |
| method: "POST", | |
| headers: { Authorization: `Bearer ${savedToken}` }, | |
| }).then(async (res) => { | |
| if (res.ok) { | |
| const data = await res.json(); | |
| setUser(data.user); | |
| localStorage.setItem("teamtasker_user", JSON.stringify(data.user)); | |
| } else { | |
| // Token invalid, clear | |
| setToken(null); | |
| setUser(null); | |
| localStorage.removeItem("teamtasker_token"); | |
| localStorage.removeItem("teamtasker_user"); | |
| } | |
| }).finally(() => setIsLoading(false)); | |
| } catch { | |
| setIsLoading(false); | |
| } | |
| } else { | |
| setIsLoading(false); | |
| } | |
| }, []); | |
| const login = useCallback(async (email: string, password: string) => { | |
| setIsLoading(true); | |
| setError(null); | |
| try { | |
| const res = await fetch("/api/auth/login", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ email, password }), | |
| }); | |
| const data = await res.json(); | |
| if (!res.ok) { | |
| setError(data.error ?? "فشل تسجيل الدخول"); | |
| return; | |
| } | |
| setToken(data.token); | |
| setUser(data.user); | |
| localStorage.setItem("teamtasker_token", data.token); | |
| localStorage.setItem("teamtasker_user", JSON.stringify(data.user)); | |
| } catch { | |
| setError("خطأ في الاتصال. حاول مجدداً."); | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| }, []); | |
| const logout = useCallback(() => { | |
| setToken(null); | |
| setUser(null); | |
| localStorage.removeItem("teamtasker_token"); | |
| localStorage.removeItem("teamtasker_user"); | |
| }, []); | |
| // Legacy shim — pages that still call setActiveUserId will do nothing harmful | |
| const setActiveUserId = useCallback((_id: number | null) => {}, []); | |
| return ( | |
| <AuthContext.Provider value={{ | |
| user, | |
| token, | |
| login, | |
| logout, | |
| isLoading, | |
| error, | |
| activeUser: user, | |
| setActiveUserId, | |
| }}> | |
| {children} | |
| </AuthContext.Provider> | |
| ); | |
| } | |
| export const useAuth = () => useContext(AuthContext); | |