"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { api } from "@/lib/client"; import { categoryLabel, slugify } from "@/lib/validate"; type Item = { name: string; count: number }; type Props = { kind: "category" | "tag"; items: Item[]; revision: string }; /** Rename / merge (both kinds) and remove (tags only) across every post. */ export default function TaxonomyTable({ kind, items, revision }: Props) { const router = useRouter(); const [drafts, setDrafts] = useState>({}); const [busy, setBusy] = useState(null); const [message, setMessage] = useState<{ kind: "ok" | "error"; text: string } | null>(null); const endpoint = kind === "category" ? "/api/categories" : "/api/tags"; const names = new Set(items.map((i) => i.name)); async function apply(from: string, to: string) { const target = kind === "category" ? slugify(to) : to.trim(); if (kind === "category" && !target) return; if (target === from) return; if (!target && !window.confirm(`Remove the tag "${from}" from every post?`)) return; if (target && names.has(target) && !window.confirm(`"${target}" already exists. Merge "${from}" into it?`)) return; setBusy(from); setMessage(null); try { const res = await api<{ changed: number }>(endpoint, { method: "PATCH", json: { from, to: target, revision } }); const verb = target ? `renamed to "${target}"` : "removed"; setMessage({ kind: "ok", text: `"${from}" ${verb} on ${res.changed} post(s).` }); setDrafts((d) => ({ ...d, [from]: "" })); router.refresh(); } catch (err) { setMessage({ kind: "error", text: (err as Error).message }); } finally { setBusy(null); } } return ( <> {message &&
{message.text}
} {kind === "category" && } {items.map((item) => { const draft = drafts[item.name] ?? ""; return ( {kind === "category" && } ); })} {items.length === 0 && ( )}
{kind}displayed asposts rename / merge into
{item.name} {categoryLabel(item.name)}{item.count} setDrafts((d) => ({ ...d, [item.name]: e.target.value }))} onKeyDown={(e) => e.key === "Enter" && draft.trim() && apply(item.name, draft)} /> {kind === "tag" && ( )}
None yet.
); }