You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
77 lines
2.0 KiB
77 lines
2.0 KiB
"use client";
|
|
|
|
import {
|
|
createContext,
|
|
useCallback,
|
|
useContext,
|
|
useEffect,
|
|
useMemo,
|
|
useState,
|
|
type ReactNode,
|
|
} from "react";
|
|
import {
|
|
AUTH_TOKEN_KEY,
|
|
AUTH_USER_KEY,
|
|
} from "@/lib/frontend/constants";
|
|
import type { AdminUser } from "@/lib/frontend/types";
|
|
|
|
interface AuthContextValue {
|
|
user: AdminUser | null;
|
|
token: string | null;
|
|
ready: boolean;
|
|
login: (token: string, user: AdminUser) => void;
|
|
logout: () => void;
|
|
}
|
|
|
|
const AuthContext = createContext<AuthContextValue | null>(null);
|
|
|
|
export function AuthProvider({ children }: { children: ReactNode }) {
|
|
const [user, setUser] = useState<AdminUser | null>(null);
|
|
const [token, setToken] = useState<string | null>(null);
|
|
const [ready, setReady] = useState(false);
|
|
|
|
useEffect(() => {
|
|
try {
|
|
const storedToken = localStorage.getItem(AUTH_TOKEN_KEY);
|
|
const storedUser = localStorage.getItem(AUTH_USER_KEY);
|
|
if (storedToken && storedUser) {
|
|
setToken(storedToken);
|
|
setUser(JSON.parse(storedUser) as AdminUser);
|
|
}
|
|
} catch {
|
|
localStorage.removeItem(AUTH_TOKEN_KEY);
|
|
localStorage.removeItem(AUTH_USER_KEY);
|
|
}
|
|
setReady(true);
|
|
}, []);
|
|
|
|
const login = useCallback((nextToken: string, nextUser: AdminUser) => {
|
|
localStorage.setItem(AUTH_TOKEN_KEY, nextToken);
|
|
localStorage.setItem(AUTH_USER_KEY, JSON.stringify(nextUser));
|
|
setToken(nextToken);
|
|
setUser(nextUser);
|
|
}, []);
|
|
|
|
const logout = useCallback(() => {
|
|
localStorage.removeItem(AUTH_TOKEN_KEY);
|
|
localStorage.removeItem(AUTH_USER_KEY);
|
|
setToken(null);
|
|
setUser(null);
|
|
}, []);
|
|
|
|
const value = useMemo(
|
|
() => ({ user, token, ready, login, logout }),
|
|
[user, token, ready, login, logout],
|
|
);
|
|
|
|
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
|
}
|
|
|
|
export function useAuth(): AuthContextValue {
|
|
const ctx = useContext(AuthContext);
|
|
if (!ctx) {
|
|
throw new Error("useAuth 必须在 AuthProvider 内使用");
|
|
}
|
|
return ctx;
|
|
}
|