"use client"; import { useMemo, useState } from "react"; import useSWR from "swr"; import { Brain, Plus, Search, Download, ShieldCheck } from "lucide-react"; import { fetcher } from "@/lib/client/fetcher"; import type { MemoryDTO } from "@/lib/client/types"; import { Button, Empty, Spinner, cn } from "@/components/ui"; import { MemoryCard } from "@/components/memory/memory-card"; import { AddMemoryDialog } from "@/components/memory/add-memory-dialog"; import { CATEGORIES, MemoryToggles, categoryLabel } from "@/components/memory/memory-shared"; interface Resp { memories: MemoryDTO[]; stats: { status: string; n: number }[] } export default function MemoryPage() { const [q, setQ] = useState(""); const [cat, setCat] = useState(null); const [add, setAdd] = useState(false); const { data, isLoading, mutate } = useSWR(`/api/memories${q ? `?q=${encodeURIComponent(q)}` : ""}`, fetcher, { keepPreviousData: true }); const stat = (s: string) => data?.stats.find(x => x.status === s)?.n ?? 0; const candidates = useMemo(() => (data?.memories ?? []).filter(m => m.status === "candidate"), [data]); const grouped = useMemo(() => { const list = (data?.memories ?? []).filter(m => m.status !== "candidate" && (!cat || m.category === cat)); const g = new Map(); for (const c of CATEGORIES) g.set(c.id, []); for (const m of list) { if (!g.has(m.category)) g.set(m.category, []); g.get(m.category)!.push(m); } return [...g.entries()].filter(([, v]) => v.length); }, [data, cat]); const refresh = () => void mutate(); return (

Mémoire

Faits durables réutilisés dans tes conversations. Tu vois tout, tu contrôles tout : rien n'est stocké en silence.

Markdown JSON
{[{ l: "Actifs", v: stat("active"), tone: "text-ok" }, { l: "Candidats", v: stat("candidate"), tone: "text-warn" }, { l: "Désactivés", v: stat("disabled"), tone: "text-muted" }].map(t => (
{t.v}
{t.l}
))}
{candidates.length > 0 && (

Candidats à approuver · {candidates.length}

{candidates.map(m => )}
)}
setQ(e.target.value)} placeholder="Rechercher dans la mémoire…" className="input !pl-8" />
{isLoading && }
{CATEGORIES.map(c => )}
{data && !grouped.length && } title={q ? "Aucun souvenir ne correspond" : "Aucun souvenir pour l'instant"} hint="Les souvenirs apparaissent au fil des conversations (extraction automatique) ou quand tu en ajoutes un." action={} />} {grouped.map(([c, items]) => (

{categoryLabel(c)} · {items.length}

{items.map(m => )}
))}
setAdd(false)} onAdded={refresh} />
); }