import { useState, useEffect, useRef, useSyncExternalStore } from "react"; import { useTranslation } from "react-i18next"; import { ScrollText, Trash2, Copy, Check } from "lucide-react"; import { getLogs, clearLogs, subscribe, type LogLevel } from "../../services/logService"; type Filter = "all" | LogLevel; export default function LogViewerCard() { const { t } = useTranslation(); const [filter, setFilter] = useState("all"); const [copied, setCopied] = useState(false); const listRef = useRef(null); const logs = useSyncExternalStore(subscribe, getLogs, getLogs); const filtered = filter === "all" ? logs : logs.filter((l) => l.level === filter); useEffect(() => { if (listRef.current) { listRef.current.scrollTop = listRef.current.scrollHeight; } }, [filtered.length]); const handleCopy = async () => { const text = filtered .map((l) => { const time = new Date(l.timestamp).toLocaleTimeString(); return `[${time}] [${l.level.toUpperCase()}] ${l.message}`; }) .join("\n"); await navigator.clipboard.writeText(text); setCopied(true); setTimeout(() => setCopied(false), 2000); }; const levelColor: Record = { info: "text-[var(--muted-foreground)]", warn: "text-amber-500", error: "text-[var(--negative)]", }; const filters: { value: Filter; label: string }[] = [ { value: "all", label: t("settings.logs.filterAll") }, { value: "error", label: "Error" }, { value: "warn", label: "Warn" }, { value: "info", label: "Info" }, ]; return (

{t("settings.logs.title")}

{filters.map((f) => ( ))}
{filtered.length === 0 ? (

{t("settings.logs.empty")}

) : ( filtered.map((entry, i) => (
{new Date(entry.timestamp).toLocaleTimeString()} {entry.level} {entry.message}
)) )}
); }