// ============================================================ // CMS — Learning Hub Content Manager. Faithful port of vanilla // public/components/cms.html + the loadCms / loadCmsContent / etc. // section of public/js/learningHub.js (@be14578). // // Server gates this with moderatorMiddleware (admin OR moderator), // so the route is mounted unconditionally and the server returns // 403 to non-moderators. The sidebar nav link is gated by // `me.user.role` to keep it hidden from clinicians. // // Sub-components live under src/pages/cms/: // StatsBar — 6-cell metrics summary // CategoriesPanel — category list + add/delete + filters // ContentList — table + toolbar (new article/quiz/pearl/presentation) // ContentEditor — title/category/type/body + per-quiz QuestionsEditor // // What's intentionally NOT in this first cut (each of these is a // follow-up commit if Daniel actually starts using them): // • AI generation panel (vanilla `lh-ai-panel`) // • WebDAV file picker for AI sources // • Drag-and-drop file upload for AI ingest // • Rich-text body editor (Quill toolbar) — body is a textarea // • Slide editor for presentations — body holds JSON for now // ============================================================ import { useState } from 'react'; import StatsBar from './cms/StatsBar'; import CategoriesPanel from './cms/CategoriesPanel'; import ContentList from './cms/ContentList'; import ContentEditor from './cms/ContentEditor'; import type { ContentType } from './cms/cms-types'; type View = { kind: 'list' } | { kind: 'edit'; id: number | null; type: ContentType }; export default function Cms() { const [statusFilter, setStatusFilter] = useState<'all' | 'published' | 'draft'>('all'); const [categoryFilter, setCategoryFilter] = useState('all'); const [view, setView] = useState({ kind: 'list' }); return (

Content Manager

Create and manage Learning Hub content, quizzes, and categories.

{view.kind === 'list' ? ( setView({ kind: 'edit', id, type: 'article' })} onCreate={(type) => setView({ kind: 'edit', id: null, type })} /> ) : ( setView({ kind: 'list' })} /> )}
); }