PawTrace / frontend /src /auth.tsx
Elliott Duke
HomingPet: lost-dog reunification (FastAPI + React) with Render deploy
de1e3fc
Raw
History Blame Contribute Delete
1.72 kB
import { createContext, useContext, useEffect, useState, type ReactNode } from "react";
import { api, getToken, setToken } from "./api";
import type { User } from "./types";
interface AuthState {
user: User | null;
loading: boolean;
login: (email: string, password: string) => Promise<User>;
register: (b: { name: string; email: string; password: string; zip: string; phone?: string }) => Promise<void>;
logout: () => void;
}
const AuthContext = createContext<AuthState | null>(null);
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!getToken()) {
setLoading(false);
return;
}
api
.me()
.then(setUser)
.catch(() => setToken(null))
.finally(() => setLoading(false));
}, []);
async function login(email: string, password: string): Promise<User> {
const { access_token } = await api.login({ email, password });
setToken(access_token);
const me = await api.me();
setUser(me);
return me;
}
async function register(b: { name: string; email: string; password: string; zip: string; phone?: string }) {
const { access_token } = await api.register(b);
setToken(access_token);
setUser(await api.me());
}
function logout() {
setToken(null);
setUser(null);
}
return (
<AuthContext.Provider value={{ user, loading, login, register, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth(): AuthState {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error("useAuth must be used within AuthProvider");
return ctx;
}