add auth
This commit is contained in:
86
frontend/src/auth/AuthContext.tsx
Normal file
86
frontend/src/auth/AuthContext.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { useState, useEffect, useCallback, type ReactNode } from "react";
|
||||
import { AuthContext, type AuthUser } from "./AuthTypes";
|
||||
|
||||
const BASE = "/api";
|
||||
|
||||
async function fetchMe(token: string) {
|
||||
try {
|
||||
const res = await fetch(`${BASE}/auth/me`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
if (!res.ok) return null;
|
||||
return res.json();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
const [user, setUser] = useState<AuthUser | null>(null);
|
||||
const [token, setToken] = useState<string | null>(() => localStorage.getItem("token"));
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
async function validateToken() {
|
||||
if (!token) return;
|
||||
const u = await fetchMe(token);
|
||||
if (cancelled) return;
|
||||
if (u) {
|
||||
setUser(u);
|
||||
} else {
|
||||
localStorage.removeItem("token");
|
||||
setToken(null);
|
||||
}
|
||||
}
|
||||
|
||||
validateToken().finally(() => {
|
||||
if (!cancelled) setIsLoading(false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [token]);
|
||||
|
||||
const login = useCallback(async (username: string, password: string) => {
|
||||
const res = await fetch(`${BASE}/auth/login`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username, password }),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const text = await res.text().catch(() => "");
|
||||
throw new Error(`${res.status}: ${text}`);
|
||||
}
|
||||
const data = await res.json();
|
||||
const newToken = data.access_token;
|
||||
localStorage.setItem("token", newToken);
|
||||
setToken(newToken);
|
||||
}, []);
|
||||
|
||||
const logout = useCallback(() => {
|
||||
localStorage.removeItem("token");
|
||||
setToken(null);
|
||||
setUser(null);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider
|
||||
value={{
|
||||
user,
|
||||
token,
|
||||
isAuthenticated: !!user,
|
||||
isLoading,
|
||||
login,
|
||||
logout,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user