import { useEffect, useState, useCallback } from "react"; import { Link } from "react-router-dom"; import { getActivityApi } from "../api/client.ts"; import { useActivityStream } from "../hooks/useActivityStream.ts"; import type { ActivityLog, OperationType } from "@fixonce/shared"; import type { ActivityEvent } from "../hooks/useActivityStream.ts"; export function RecentActivity() { const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [filterOp, setFilterOp] = useState(""); const loadLogs = useCallback(async () => { setLoading(true); setError(null); try { const params: Record = { limit: "100" }; if (filterOp) params.operation = filterOp; const data = await getActivityApi(params); setLogs(data); } catch (err) { setError(err instanceof Error ? err.message : "Failed to load activity"); } finally { setLoading(false); } }, [filterOp]); useEffect(() => { void loadLogs(); }, [loadLogs]); const handleStreamEvent = useCallback((event: ActivityEvent) => { const newLog: ActivityLog = { id: event.id, operation: event.operation as OperationType, memory_id: event.memory_id, details: event.details, created_at: event.created_at, }; setLogs((prev) => [newLog, ...prev]); }, []); const { connected } = useActivityStream(handleStreamEvent); return (

Activity Log

{connected ? "Live" : "Disconnected"}
{error &&

{error}

}
{loading ? (

Loading activity...

) : logs.length > 0 ? ( {logs.map((log) => ( ))}
Operation Memory Details Time
{log.operation} {log.memory_id ? ( {log.memory_id.slice(0, 8)}... ) : ( "-" )} {JSON.stringify(log.details, null, 0).slice(0, 100)} {new Date(log.created_at).toLocaleString()}
) : (

No activity logged yet.

)}
); } const inputStyle: React.CSSProperties = { padding: "0.4rem 0.5rem", border: "1px solid #ccc", borderRadius: "3px", fontSize: "0.9rem", }; const thStyle: React.CSSProperties = { textAlign: "left", padding: "0.5rem", borderBottom: "2px solid #ddd", }; const tdStyle: React.CSSProperties = { padding: "0.5rem", borderBottom: "1px solid #eee", }; const OP_COLORS: Record = { query: "#1565c0", create: "#2e7d32", update: "#ef6c00", feedback: "#6a1b9a", detect: "#00838f", }; function opBadge(operation: string): React.CSSProperties { return { display: "inline-block", padding: "0.15rem 0.5rem", borderRadius: "3px", fontSize: "0.75rem", fontWeight: 600, color: "#fff", background: OP_COLORS[operation] ?? "#666", }; }