import { useEffect, useMemo, useState } from 'react' import { diffWords } from 'diff' import Modal from '../../../components/Modal.jsx' import { dateTime } from '../../../lib/format.js' import { api } from '../../../api/client.js' // Plain-text view of a body, for a readable word-level diff. function toText(html) { if (!html) return '' if (typeof window === 'undefined' || !window.DOMParser) return html const doc = new DOMParser().parseFromString(html, 'text/html') return doc.body.textContent || '' } export default function WikiHistory({ slug, onClose, onRestored }) { const [revisions, setRevisions] = useState([]) const [current, setCurrent] = useState(null) const [selected, setSelected] = useState(null) // full revision snapshot const [loading, setLoading] = useState(true) const [busy, setBusy] = useState(false) const [error, setError] = useState('') useEffect(() => { let active = true Promise.all([api.admin.listWikiRevisions(slug), api.admin.getWiki(slug)]) .then(([revs, page]) => { if (!active) return setRevisions(revs) setCurrent(page) }) .catch(() => active && setError('Could not load history.')) .finally(() => active && setLoading(false)) return () => { active = false } }, [slug]) async function selectRevision(id) { setError('') try { const rev = await api.admin.getWikiRevision(slug, id) setSelected(rev) } catch (err) { setError(err.message || 'Could not load revision.') } } async function restore() { if (!selected) return if (!confirm(`Restore the page to revision #${selected.id}? This creates a new revision.`)) return setBusy(true) try { await api.admin.restoreWikiRevision(slug, selected.id) onRestored() } catch (err) { setError(err.message || 'Could not restore.') setBusy(false) } } // Diff the selected revision (old) against the current saved page (new). const parts = useMemo( () => (selected ? diffWords(toText(selected.body), toText(current?.body || '')) : []), [selected, current], ) return ( } > {loading && } {!loading && error && (

{error}

)} {!loading && !error && (
    {revisions.map((r, i) => (
  • ))} {revisions.length === 0 &&
  • No revisions yet.
  • }
{!selected ? (

Select a revision to see what changed between it and the current page.

) : ( <>

Diff: revision #{selected.id} → current

{parts.length === 0 || (parts.length === 1 && !parts[0].added && !parts[0].removed) ? ( No textual differences. ) : ( parts.map((p, i) => { let cls = '' if (p.added) cls = 'diff-add' else if (p.removed) cls = 'diff-del' return ( {p.value} ) }) )}
)}
)}
) }