Spaces:
Sleeping
Sleeping
File size: 3,645 Bytes
8314cf4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | 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);
|