"use client"; import { useEffect, useRef, useState } from "react"; import { ChevronDown, Clock3, Loader2, UserCircle } from "lucide-react"; import type { AuthUser } from "@/lib/auth/session"; import { USAGE_PRESET_OPTIONS, type PersonalUsageReport, type UsagePreset } from "@/lib/usage"; export function AccountUsageMenu({ user }: { user: AuthUser }) { const [open, setOpen] = useState(false); const [preset, setPreset] = useState("month"); const [report, setReport] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const containerRef = useRef(null); useEffect(() => { if (!open) return; const onPointerDown = (event: PointerEvent) => { if (!containerRef.current?.contains(event.target as Node)) setOpen(false); }; const onKeyDown = (event: KeyboardEvent) => { if (event.key === "Escape") setOpen(false); }; document.addEventListener("pointerdown", onPointerDown); document.addEventListener("keydown", onKeyDown); return () => { document.removeEventListener("pointerdown", onPointerDown); document.removeEventListener("keydown", onKeyDown); }; }, [open]); useEffect(() => { if (!open) return; const controller = new AbortController(); setLoading(true); setError(null); fetch(`/api/usage?preset=${preset}`, { cache: "no-store", signal: controller.signal }) .then(async (response) => { const payload = await response.json() as PersonalUsageReport & { error?: string }; if (!response.ok) throw new Error(payload.error || "读取用量失败"); setReport(payload); }) .catch((nextError) => { if (nextError instanceof DOMException && nextError.name === "AbortError") return; setError(nextError instanceof Error ? nextError.message : String(nextError)); }) .finally(() => { if (!controller.signal.aborted) setLoading(false); }); return () => controller.abort(); }, [open, preset]); return (
{open ? ( ) : null}
); } function formatUsageTime(value: string): string { return new Intl.DateTimeFormat("zh-CN", { timeZone: "Asia/Shanghai", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", hour12: false }).format(new Date(value)); }