import { useState } from 'react' import { Link, useSearchParams } from 'react-router-dom' import PublicLayout from '../../components/PublicLayout.jsx' import PageHeader from '../../components/PageHeader.jsx' import { Loading, ErrorState, EmptyState } from '../../components/PageState.jsx' import { useAsync } from '../../lib/useAsync.js' import { api } from '../../api/client.js' function SearchBox({ initial, onSubmit }) { const [term, setTerm] = useState(initial || '') return (
{ e.preventDefault() onSubmit(term.trim()) }} style={{ display: 'flex', gap: 8, maxWidth: 460, margin: '0 auto 8px' }} > setTerm(e.target.value)} className="input" placeholder="Search the wiki…" />
) } // Group published pages under their category, preserving category sort order and // collecting anything uncategorized into a trailing section. function groupByCategory(categories, pages) { const byId = new Map(categories.map((c) => [c.id, { ...c, pages: [] }])) const uncategorized = [] for (const page of pages) { const bucket = page.category_id != null ? byId.get(page.category_id) : null if (bucket) bucket.pages.push(page) else uncategorized.push(page) } const sections = [...byId.values()].filter((c) => c.pages.length > 0) if (uncategorized.length) { sections.push({ id: 'uncategorized', title: 'Other Pages', description: '', pages: uncategorized }) } return sections } function PageCard({ page }) { return (

{page.title}

{page.excerpt || 'Open the guide →'}

) } export default function Wiki() { const [searchParams, setSearchParams] = useSearchParams() const activeCategory = searchParams.get('category') const activeTag = searchParams.get('tag') const activeQ = searchParams.get('q') // Search / tag views fetch a filtered page list; otherwise all pages (grouped here). const pageOpts = activeQ ? { q: activeQ } : activeTag ? { tag: activeTag } : {} const { loading, error, data } = useAsync( () => Promise.all([api.wikiCategories(), api.wiki(pageOpts)]).then(([categories, pages]) => ({ categories, pages, })), [activeTag, activeQ], ) const allSections = data ? groupByCategory(data.categories, data.pages) : [] const sections = activeCategory ? allSections.filter((s) => s.slug === activeCategory) : allSections const hasPages = data && data.pages.length > 0 const flat = Boolean(activeTag || activeQ) // flat-list views const filtered = Boolean(activeCategory || activeTag || activeQ) const runSearch = (term) => setSearchParams(term ? { q: term } : {}) return (
{loading && } {error && } {!loading && !error && !hasPages && !filtered && No wiki pages yet.} {!loading && !error && filtered && (

← All sections {activeTag && · Tagged #{activeTag}} {activeQ && · Results for “{activeQ}”}

)} {/* Flat list: search results or a tag filter (both cross categories). */} {!loading && !error && flat && (data.pages.length === 0 ? ( {activeQ ? 'No pages match that search.' : 'No pages with this tag.'} ) : (
{data.pages.map((p) => ( ))}
))} {/* Category / full view: grouped sections. */} {!loading && !error && !flat && hasPages && activeCategory && sections.length === 0 && ( No pages in this section yet. )} {!flat && sections.map((section) => (

{section.title}

{section.description && (

{section.description}

)}
{section.pages.map((p) => ( ))}
))}
) }