50 lines
1.9 KiB
TypeScript
50 lines
1.9 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { useDeveloperFlags } from "@/components/developer-flags-provider";
|
|
|
|
type DebugEvent = { event: string; payload: Record<string, unknown>; ts: number };
|
|
|
|
export function EventDebugPanel() {
|
|
const { flags } = useDeveloperFlags();
|
|
const [open, setOpen] = useState(false);
|
|
const [events, setEvents] = useState<DebugEvent[]>(() => {
|
|
if (typeof window === "undefined") return [];
|
|
return ((window.__DOWNLOAD_NOVA_TRACKS__ ?? []) as DebugEvent[]).slice(-20).reverse();
|
|
});
|
|
|
|
useEffect(() => {
|
|
const handler = (e: Event) => {
|
|
const custom = e as CustomEvent<DebugEvent>;
|
|
setEvents((prev) => [custom.detail, ...prev].slice(0, 20));
|
|
};
|
|
window.addEventListener("download-nova-track", handler);
|
|
return () => window.removeEventListener("download-nova-track", handler);
|
|
}, []);
|
|
|
|
if (process.env.NODE_ENV === "production" || !flags.eventDebug) return null;
|
|
|
|
return (
|
|
<div className="fixed bottom-4 right-4 z-[60]">
|
|
<button className="cta-sub text-xs" onClick={() => setOpen((v) => !v)}>
|
|
埋点调试面板
|
|
</button>
|
|
{open && (
|
|
<div className="card-glass mt-2 w-[360px] max-w-[90vw] space-y-2">
|
|
<p className="text-xs text-slate-400">最近 20 条事件</p>
|
|
<div className="max-h-80 space-y-1 overflow-auto pr-1 text-xs">
|
|
{events.length === 0 && <p className="text-slate-500">暂无事件</p>}
|
|
{events.map((item, idx) => (
|
|
<div key={`${item.ts}-${idx}`} className="rounded-lg border border-white/10 bg-slate-900/30 p-2">
|
|
<p className="font-medium text-cyan-300">{item.event}</p>
|
|
<p className="mt-1 text-slate-400">{new Date(item.ts).toLocaleTimeString()}</p>
|
|
<pre className="mt-1 whitespace-pre-wrap text-slate-300">{JSON.stringify(item.payload)}</pre>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|