Add login gate, calculation history, and AI markdown download.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
interface AuthState {
|
||||
loading: boolean;
|
||||
authEnabled: boolean;
|
||||
loggedIn: boolean;
|
||||
username?: string;
|
||||
refresh: () => Promise<void>;
|
||||
logout: () => Promise<void>;
|
||||
}
|
||||
|
||||
const AuthContext = createContext<AuthState | null>(null);
|
||||
|
||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [authEnabled, setAuthEnabled] = useState(false);
|
||||
const [loggedIn, setLoggedIn] = useState(true);
|
||||
const [username, setUsername] = useState<string>();
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
try {
|
||||
const res = await fetch("/api/auth/me", { cache: "no-store" });
|
||||
const data = await res.json();
|
||||
setAuthEnabled(!!data.authEnabled);
|
||||
setLoggedIn(!!data.loggedIn);
|
||||
setUsername(data.username);
|
||||
} catch {
|
||||
setAuthEnabled(false);
|
||||
setLoggedIn(true);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
}, [refresh]);
|
||||
|
||||
const logout = useCallback(async () => {
|
||||
await fetch("/api/auth/logout", { method: "POST" });
|
||||
await refresh();
|
||||
window.location.href = "/";
|
||||
}, [refresh]);
|
||||
|
||||
const value = useMemo(
|
||||
() => ({ loading, authEnabled, loggedIn, username, refresh, logout }),
|
||||
[loading, authEnabled, loggedIn, username, refresh, logout],
|
||||
);
|
||||
|
||||
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
||||
}
|
||||
|
||||
export function useAuth() {
|
||||
const ctx = useContext(AuthContext);
|
||||
if (!ctx) {
|
||||
throw new Error("useAuth must be used within AuthProvider");
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
export function useRequireAuthForPath(path: string): boolean {
|
||||
const { authEnabled, loggedIn } = useAuth();
|
||||
if (!authEnabled) {
|
||||
return true;
|
||||
}
|
||||
const protectedPaths = ["/liuyao", "/bazi", "/combined", "/history"];
|
||||
if (!protectedPaths.some((p) => path === p || path.startsWith(`${p}/`))) {
|
||||
return true;
|
||||
}
|
||||
return loggedIn;
|
||||
}
|
||||
Reference in New Issue
Block a user