@anantagnanam/lms 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +23 -2
- package/astro/client.ts +73 -151
- package/astro/components/CourseOverview.astro +25 -3
- package/astro/components/LearnerDashboard.astro +6 -0
- package/astro/components/LearningShell.astro +10 -1
- package/astro/components/LessonAvailabilityNote.astro +26 -0
- package/astro/components/LessonContent.astro +53 -0
- package/astro/components/LessonPlayer.astro +40 -61
- package/astro/components/MediaPlayer.astro +55 -4
- package/astro/media-player.ts +99 -0
- package/astro/pages/author-preview.astro +71 -0
- package/astro/pages/course.astro +10 -0
- package/astro/pages/lesson.astro +3 -0
- package/astro/pages/library.astro +173 -0
- package/astro/pages/paths.astro +73 -0
- package/astro/quiz-drafts.ts +87 -0
- package/astro/quiz-player.ts +362 -0
- package/astro/styles.css +12 -0
- package/dist/admin.d.ts +3 -1
- package/dist/admin.js +585 -116
- package/dist/admin.js.map +1 -1
- package/dist/astro.js +3 -0
- package/dist/astro.js.map +1 -1
- package/dist/{constants-C0kT94tc.js → constants-Cnx7k82Z.js} +25 -3
- package/dist/constants-Cnx7k82Z.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/runtime.d.ts +104 -12
- package/dist/runtime.js +896 -116
- package/dist/runtime.js.map +1 -1
- package/dist/schemas.d.ts +68 -1
- package/dist/schemas.js +34 -2
- package/dist/schemas.js.map +1 -1
- package/dist/server.d.ts +11 -1
- package/dist/server.js +13 -2
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +107 -4
- package/package.json +1 -1
- package/dist/constants-C0kT94tc.js.map +0 -1
package/dist/admin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin.js","names":[],"sources":["../src/admin.tsx"],"sourcesContent":["import { useCallback, useEffect, useState, type FormEvent, type ReactNode } from \"react\";\nimport { apiFetch } from \"emdash/plugin-utils\";\nimport { API_BASE, PLUGIN_ID } from \"./constants.js\";\nimport { enrollmentCsvHeader, enrollmentCsvLines } from \"./csv.js\";\nimport {\n courseDataSchema,\n lessonSchema,\n moduleSchema,\n questionSchema,\n settingsSchema,\n quizSchema,\n assignmentSchema,\n} from \"./schemas.js\";\nimport type {\n Course,\n CourseData,\n Lesson,\n QuizQuestion,\n Page,\n LmsSettings,\n Cohort,\n PublicEnrollment,\n AssignmentSubmission,\n Discussion,\n Review,\n CohortMembership,\n CourseCard,\n Notification,\n AuditRecord,\n} from \"./types.js\";\n\nconst ADMIN_BASE = `/_emdash/admin/plugins/${PLUGIN_ID}`;\ntype UserChoice = { id: string; email: string; name: string | null };\ntype EnrollmentRow = PublicEnrollment & {\n learnerEmail: string;\n courseTitle: string;\n progressSummary: { percent: number } | null;\n lessonTitles: Record<string, string>;\n};\ntype Report = {\n total: number;\n courseCount: number;\n pending: number;\n active: number;\n completed: number;\n completedEver: number;\n suspended: number;\n cancelled: number;\n rejected: number;\n accessSources: Record<string, number>;\n accessDecisions: Record<string, number>;\n completionRate: number;\n};\n\nasync function api<T>(\n route: string,\n input: Record<string, unknown> = {},\n method = \"GET\",\n signal?: AbortSignal,\n): Promise<T> {\n let url = `${API_BASE}/${route}`;\n if (method === \"GET\") {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(input))\n if (value !== undefined && value !== \"\" && value !== null) params.set(key, String(value));\n url += `?${params}`;\n }\n const response = await apiFetch(url, {\n method,\n signal,\n credentials: \"same-origin\",\n ...(method !== \"GET\"\n ? { headers: { \"Content-Type\": \"application/json\" }, body: JSON.stringify(input) }\n : {}),\n });\n const result = (await response.json()) as {\n success: boolean;\n data?: T;\n error?: { message?: string };\n };\n if (!response.ok || !result.success)\n throw new Error(result.error?.message ?? \"The request could not be completed.\");\n return result.data as T;\n}\n\nfunction useLoad<T>(route: string, input: Record<string, unknown> = {}, enabled = true) {\n const key = JSON.stringify(input);\n const [generation, setGeneration] = useState(0);\n const [state, setState] = useState<{ data?: T; loading: boolean; error?: string }>({\n loading: enabled,\n });\n useEffect(() => {\n if (!enabled) {\n setState({ loading: false });\n return;\n }\n const controller = new AbortController();\n setState((old) => ({ ...old, loading: true, error: undefined }));\n void api<T>(route, JSON.parse(key), \"GET\", controller.signal)\n .then((data) => {\n if (!controller.signal.aborted) setState({ loading: false, data });\n })\n .catch((error: Error) => {\n if (!controller.signal.aborted) setState({ loading: false, error: error.message });\n });\n return () => controller.abort();\n }, [route, key, enabled, generation]);\n return { ...state, reload: () => setGeneration((value) => value + 1) };\n}\nfunction useAction() {\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState(\"\");\n const [message, setMessage] = useState(\"\");\n const run = async (action: () => Promise<void>, success = \"Saved.\") => {\n if (busy) return;\n setBusy(true);\n setError(\"\");\n setMessage(\"\");\n try {\n await action();\n setMessage(success);\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : \"The request failed.\");\n } finally {\n setBusy(false);\n }\n };\n return { busy, error, message, run };\n}\nfunction useChoices<T extends { id: string }>(route: string) {\n const [cursor, setCursor] = useState<string>();\n const [items, setItems] = useState<T[]>([]);\n const list = useLoad<Page<T>>(route, { cursor, limit: 100 });\n useEffect(() => {\n if (list.data)\n setItems((old) => [\n ...new Map([...old, ...list.data!.items].map((item) => [item.id, item])).values(),\n ]);\n }, [list.data]);\n return { ...list, items, more: () => setCursor(list.data?.cursor) };\n}\n\nfunction ChoicesField({\n label,\n value,\n choices,\n onChange,\n}: {\n label: string;\n value: string[];\n choices: { id: string; label: string }[];\n onChange: (ids: string[]) => void;\n}) {\n const all = [\n ...choices,\n ...value\n .filter((id) => !choices.some((choice) => choice.id === id))\n .map((id) => ({ id, label: `Saved selection · ${id.slice(0, 8)}` })),\n ];\n return (\n <fieldset className=\"lms-choices\">\n <legend>{label}</legend>\n {all.map((choice) => (\n <label className=\"lms-check\" key={choice.id}>\n <input\n type=\"checkbox\"\n checked={value.includes(choice.id)}\n onChange={(event) =>\n onChange(\n event.target.checked\n ? [...value, choice.id]\n : value.filter((id) => id !== choice.id),\n )\n }\n />\n {choice.label}\n </label>\n ))}\n {!all.length && <p>No choices loaded yet.</p>}\n </fieldset>\n );\n}\n\nfunction Notice({ error, message }: { error?: string; message?: string }) {\n return (\n <>\n {error && (\n <p role=\"alert\" className=\"lms-notice lms-error\">\n {error}\n </p>\n )}\n {message && (\n <p role=\"status\" className=\"lms-notice\">\n {message}\n </p>\n )}\n </>\n );\n}\nfunction Field({ label, children, help }: { label: string; children: ReactNode; help?: string }) {\n return (\n <label className=\"lms-field\">\n <span>{label}</span>\n {children}\n {help && <small>{help}</small>}\n </label>\n );\n}\nfunction Button({\n children,\n busy,\n danger,\n ...props\n}: React.ButtonHTMLAttributes<HTMLButtonElement> & { busy?: boolean; danger?: boolean }) {\n return (\n <button\n type=\"button\"\n {...props}\n className={`lms-button${danger ? \" lms-danger\" : \"\"}`}\n disabled={props.disabled || busy}\n >\n {busy ? \"Working…\" : children}\n </button>\n );\n}\nfunction Panel({ title, children }: { title?: string; children: ReactNode }) {\n return (\n <section className=\"lms-panel\">\n {title && <h2>{title}</h2>}\n {children}\n </section>\n );\n}\nfunction Pager({\n page,\n next,\n reset,\n}: {\n page?: { hasMore: boolean; cursor?: string };\n next: (cursor: string) => void;\n reset: () => void;\n}) {\n return (\n <div className=\"lms-actions\">\n <Button onClick={reset}>First page</Button>\n {page?.hasMore && page.cursor && (\n <Button onClick={() => next(page.cursor!)}>Next page</Button>\n )}\n </div>\n );\n}\nfunction PageFrame({\n title,\n description,\n children,\n}: {\n title: string;\n description?: string;\n children: ReactNode;\n}) {\n const academy = useLoad<{ basePath: string }>(\"academy\");\n return (\n <main className=\"ag-lms-admin\">\n <style>{css}</style>\n <header className=\"lms-page-header\">\n <div>\n <p className=\"lms-eyebrow\">ANANTA GNANAM · LEARNING</p>\n <h1>{title}</h1>\n {description && <p>{description}</p>}\n </div>\n <a\n href={academy.data?.basePath ?? \"/academy\"}\n className=\"lms-button\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Open academy ↗\n </a>\n </header>\n <nav className=\"lms-tabs\" aria-label=\"Learning administration\">\n {[\n [\"/\", \"Overview\"],\n [\"/courses\", \"Courses\"],\n [\"/learners\", \"Enrollments\"],\n [\"/assignments\", \"Assignments\"],\n [\"/community\", \"Community\"],\n [\"/cohorts\", \"Cohorts\"],\n [\"/reports\", \"Reports\"],\n [\"/notifications\", \"Notifications\"],\n [\"/audit\", \"Audit history\"],\n [\"/settings\", \"Settings\"],\n ].map(([path, label]) => (\n <a key={path} href={`${ADMIN_BASE}${path === \"/\" ? \"\" : path}`}>\n {label}\n </a>\n ))}\n </nav>\n {children}\n </main>\n );\n}\nfunction Metrics({ report }: { report?: Report }) {\n return (\n <div className=\"lms-metrics\">\n {[\n [\"Courses\", report?.courseCount],\n [\"Active enrollments\", report?.active],\n [\"Course completions\", report?.completedEver],\n [\"Awaiting approval\", report?.pending],\n [\"Completion rate\", report ? `${report.completionRate}%` : undefined],\n ].map(([label, value]) => (\n <div className=\"lms-panel\" key={label}>\n <span>{label}</span>\n <strong>{value ?? \"—\"}</strong>\n </div>\n ))}\n </div>\n );\n}\nfunction CoursePicker({\n value,\n onChange,\n allowAll = false,\n}: {\n value: string;\n onChange: (id: string) => void;\n allowAll?: boolean;\n}) {\n const [cursor, setCursor] = useState<string>();\n const [choices, setChoices] = useState<Course[]>([]);\n const list = useLoad<Page<Course>>(\"admin/courses\", { limit: 100, cursor });\n useEffect(() => {\n if (list.data)\n setChoices((old) => [\n ...new Map([...old, ...list.data!.items].map((course) => [course.id, course])).values(),\n ]);\n }, [list.data]);\n return (\n <div>\n <Field label=\"Course\">\n <select value={value} onChange={(event) => onChange(event.target.value)}>\n <option value=\"\">{allowAll ? \"All courses\" : \"Choose a course\"}</option>\n {choices.map((course) => (\n <option key={course.id} value={course.id}>\n {course.title} · {course.status}\n </option>\n ))}\n </select>\n </Field>\n {list.data?.hasMore && (\n <Button onClick={() => setCursor(list.data?.cursor)}>Load more courses</Button>\n )}\n <Notice error={list.error} />\n </div>\n );\n}\n\nexport function OverviewPage() {\n const report = useLoad<Report>(\"admin/report\");\n return (\n <PageFrame\n title=\"Learning overview\"\n description=\"Create learning paths, support your learners, and see their progress.\"\n >\n <Notice error={report.error} />\n <Metrics report={report.data} />\n <div className=\"lms-grid\">\n <Panel title=\"Course studio\">\n <p>Build modules with reading, video, audio, quizzes, assignments, and live sessions.</p>\n <a className=\"lms-button\" href={`${ADMIN_BASE}/courses`}>\n Manage courses\n </a>\n </Panel>\n <Panel title=\"Support learners\">\n <p>Review enrollment requests and give feedback on submitted work.</p>\n <div className=\"lms-actions\">\n <a className=\"lms-button\" href={`${ADMIN_BASE}/learners`}>\n Enrollments\n </a>\n <a className=\"lms-button\" href={`${ADMIN_BASE}/assignments`}>\n Grade assignments\n </a>\n </div>\n </Panel>\n </div>\n </PageFrame>\n );\n}\n\nexport function CoursesPage() {\n const [cursor, setCursor] = useState<string>();\n const [status, setStatus] = useState(\"\");\n const [edit, setEdit] = useState<{\n course: CourseData & { id?: string };\n revision: string | null;\n }>();\n const list = useLoad<Page<Course>>(\"admin/courses\", { cursor, status });\n const action = useAction();\n const open = (id: string) =>\n void action.run(async () => {\n const result = await api<{ course: Course; revision: string }>(\"admin/course\", { id });\n setEdit({ course: result.course, revision: result.revision });\n }, \"\");\n const importFile = async (file: File) => {\n if (file.size > 950_000) throw new Error(\"This course file is too large.\");\n const bundle = JSON.parse(await file.text()) as {\n format?: string;\n version?: number;\n course?: CourseData;\n };\n if (bundle.format !== \"anantagnanam-lms-course\" || bundle.version !== 1 || !bundle.course)\n throw new Error(\"Choose an Ananta Gnanam course export.\");\n setEdit({\n course: courseDataSchema.parse({ ...bundle.course, status: \"draft\" }),\n revision: null,\n });\n };\n if (edit)\n return (\n <CourseEditor\n initial={edit.course}\n initialRevision={edit.revision}\n onClose={() => {\n setEdit(undefined);\n list.reload();\n }}\n />\n );\n return (\n <PageFrame title=\"Courses\" description=\"Author, publish, and update your courses.\">\n <Notice error={list.error || action.error} message={action.message} />\n <div className=\"lms-toolbar\">\n <Button\n onClick={() =>\n setEdit({\n course: courseDataSchema.parse({ title: \"New course\", slug: \"new-course\" }),\n revision: null,\n })\n }\n >\n Create course\n </Button>\n <label className=\"lms-button\">\n Import course\n <input\n className=\"lms-file\"\n type=\"file\"\n accept=\"application/json,.json\"\n onChange={(event) => {\n const file = event.target.files?.[0];\n if (file) void action.run(() => importFile(file), \"\");\n event.target.value = \"\";\n }}\n />\n </label>\n <Field label=\"Status\">\n <select\n value={status}\n onChange={(event) => {\n setStatus(event.target.value);\n setCursor(undefined);\n }}\n >\n <option value=\"\">All statuses</option>\n {[\"draft\", \"published\", \"archived\"].map((value) => (\n <option key={value}>{value}</option>\n ))}\n </select>\n </Field>\n </div>\n {list.loading && <p role=\"status\">Loading courses…</p>}\n <div className=\"lms-course-grid\">\n {list.data?.items.map((course) => (\n <Panel key={course.id}>\n <span className=\"lms-badge\">{course.status}</span>\n <h2>{course.title}</h2>\n <p>{course.summary || \"Add a summary to introduce this course.\"}</p>\n <p className=\"lms-muted\">\n {course.modules.length} modules ·{\" \"}\n {course.modules.reduce((sum, module) => sum + module.lessons.length, 0)} lessons\n </p>\n <div className=\"lms-actions\">\n <Button busy={action.busy} onClick={() => open(course.id)}>\n Edit course\n </Button>\n <Button\n onClick={() =>\n void action.run(\n async () =>\n download(\n `${course.slug}.json`,\n JSON.stringify(\n await api(\"admin/course/export\", { id: course.id }),\n null,\n 2,\n ),\n \"application/json\",\n ),\n \"Course exported.\",\n )\n }\n >\n Export\n </Button>\n </div>\n </Panel>\n ))}\n </div>\n {list.data && !list.data.items.length && (\n <Panel>\n <p>No courses yet. Create your first course above.</p>\n </Panel>\n )}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nfunction CourseEditor({\n initial,\n initialRevision,\n onClose,\n}: {\n initial: CourseData & { id?: string };\n initialRevision: string | null;\n onClose: () => void;\n}) {\n const [course, setCourse] = useState(initial);\n const [revision, setRevision] = useState(initialRevision);\n const [saved, setSaved] = useState(JSON.stringify(initial));\n const [selected, setSelected] = useState<string | null>(\n initial.modules[0]?.lessons[0]?.id ?? null,\n );\n const [tab, setTab] = useState<\"details\" | \"curriculum\" | \"access\">(\"details\");\n const action = useAction();\n const dirty = !course.id || JSON.stringify(course) !== saved;\n const prerequisiteChoices = useChoices<CourseCard>(\"catalog\");\n const instructorChoices = useChoices<UserChoice>(\"admin/instructors\");\n useEffect(() => {\n if (!dirty) return;\n const handler = (event: BeforeUnloadEvent) => {\n event.preventDefault();\n };\n window.addEventListener(\"beforeunload\", handler);\n return () => window.removeEventListener(\"beforeunload\", handler);\n }, [dirty]);\n const patch = (data: Partial<CourseData>) => setCourse((old) => ({ ...old, ...data }));\n const updateModule = (index: number, data: Partial<CourseData[\"modules\"][number]>) =>\n setCourse((old) => ({\n ...old,\n modules: old.modules.map((module, i) => (i === index ? { ...module, ...data } : module)),\n }));\n const updateLesson = (id: string, data: Partial<Lesson>) =>\n setCourse((old) => ({\n ...old,\n modules: old.modules.map((module) => ({\n ...module,\n lessons: module.lessons.map((lesson) =>\n lesson.id === id ? { ...lesson, ...data } : lesson,\n ),\n })),\n }));\n const selectedLesson = course.modules\n .flatMap((module) => module.lessons)\n .find((lesson) => lesson.id === selected);\n const save = (status = course.status) =>\n void action.run(\n async () => {\n const parsed = courseDataSchema.safeParse({ ...course, status });\n if (!parsed.success)\n throw new Error(\n parsed.error.issues\n .slice(0, 5)\n .map((issue) => `${issue.path.join(\".\")}: ${issue.message}`)\n .join(\" \"),\n );\n const result = await api<{ course: Course; revision: string }>(\n \"admin/course/save\",\n { id: course.id, expectedRevision: revision, data: parsed.data },\n \"POST\",\n );\n setCourse(result.course);\n setRevision(result.revision);\n setSaved(JSON.stringify(result.course));\n },\n status === \"published\" ? \"Course published.\" : \"Course saved.\",\n );\n const reorderLesson = (moduleIndex: number, index: number, delta: number) => {\n const items = [...course.modules[moduleIndex]!.lessons];\n const to = index + delta;\n if (to < 0 || to >= items.length) return;\n [items[index], items[to]] = [items[to]!, items[index]!];\n updateModule(moduleIndex, { lessons: items });\n };\n return (\n <PageFrame\n title={course.title}\n description={dirty ? \"You have unsaved changes.\" : \"All changes saved.\"}\n >\n <Notice error={action.error} message={action.message} />\n <div className=\"lms-toolbar\">\n <Button\n onClick={() => {\n if (!dirty || window.confirm(\"Discard unsaved changes?\")) onClose();\n }}\n >\n Back to courses\n </Button>\n <Button busy={action.busy} onClick={() => save()}>\n Save {course.status}\n </Button>\n {course.status !== \"published\" && (\n <Button busy={action.busy} onClick={() => save(\"published\")}>\n Publish\n </Button>\n )}\n {course.status === \"published\" && (\n <Button busy={action.busy} onClick={() => save(\"archived\")}>\n Archive\n </Button>\n )}\n {course.id && course.status === \"draft\" && (\n <Button\n danger\n busy={action.busy}\n onClick={() => {\n if (window.confirm(`Delete the draft “${course.title}”?`))\n void action.run(async () => {\n await api(\n \"admin/course/delete\",\n { id: course.id, expectedRevision: revision },\n \"POST\",\n );\n onClose();\n }, \"\");\n }}\n >\n Delete draft\n </Button>\n )}\n </div>\n <div className=\"lms-tabs\" role=\"tablist\" aria-label=\"Course editor\">\n {([\"details\", \"curriculum\", \"access\"] as const).map((value) => (\n <Button\n key={value}\n role=\"tab\"\n aria-selected={tab === value}\n onClick={() => setTab(value)}\n >\n {value === \"access\"\n ? \"Enrollment & completion\"\n : value === \"details\"\n ? \"Course details\"\n : \"Curriculum\"}\n </Button>\n ))}\n </div>\n {tab === \"details\" && (\n <Panel>\n <div className=\"lms-grid\">\n <Field label=\"Course title\">\n <input\n value={course.title}\n maxLength={200}\n onChange={(event) => patch({ title: event.target.value })}\n />\n </Field>\n <Field label=\"Course URL\">\n <input\n value={course.slug}\n onChange={(event) => patch({ slug: event.target.value })}\n pattern=\"[a-z0-9]+(-[a-z0-9]+)*\"\n />\n </Field>\n <Field label=\"Category\">\n <input\n value={course.category}\n onChange={(event) => patch({ category: event.target.value })}\n />\n </Field>\n <Field label=\"Level\">\n <select\n value={course.level}\n onChange={(event) => patch({ level: event.target.value as CourseData[\"level\"] })}\n >\n {[\"all\", \"beginner\", \"intermediate\", \"advanced\"].map((level) => (\n <option key={level}>{level}</option>\n ))}\n </select>\n </Field>\n <Field label=\"Language\">\n <input\n value={course.language}\n onChange={(event) => patch({ language: event.target.value })}\n placeholder=\"en, ta, hi…\"\n />\n </Field>\n <Field label=\"Instructor name\">\n <input\n value={course.instructorName}\n onChange={(event) => patch({ instructorName: event.target.value })}\n />\n </Field>\n </div>\n <Field label=\"Summary\">\n <textarea\n rows={3}\n value={course.summary}\n onChange={(event) => patch({ summary: event.target.value })}\n maxLength={1000}\n />\n </Field>\n <Field label=\"Course description\">\n <textarea\n rows={7}\n value={course.description}\n onChange={(event) => patch({ description: event.target.value })}\n />\n </Field>\n <div className=\"lms-grid\">\n <Field label=\"Learning outcomes\" help=\"One outcome per line.\">\n <textarea\n rows={5}\n value={course.outcomes.join(\"\\n\")}\n onChange={(event) =>\n patch({ outcomes: event.target.value.split(\"\\n\").filter(Boolean) })\n }\n />\n </Field>\n <Field label=\"Requirements\" help=\"One requirement per line.\">\n <textarea\n rows={5}\n value={course.requirements.join(\"\\n\")}\n onChange={(event) =>\n patch({ requirements: event.target.value.split(\"\\n\").filter(Boolean) })\n }\n />\n </Field>\n <Field label=\"Tags\" help=\"Separate tags with commas.\">\n <input\n value={course.tags.join(\", \")}\n onChange={(event) =>\n patch({\n tags: event.target.value\n .split(\",\")\n .map((tag) => tag.trim())\n .filter(Boolean),\n })\n }\n />\n </Field>\n <Field label=\"Course image URL\">\n <input\n type=\"url\"\n value={course.featuredImage?.src ?? \"\"}\n onChange={(event) =>\n patch({\n featuredImage: event.target.value\n ? {\n id: course.featuredImage?.id ?? \"\",\n src: event.target.value,\n alt: course.featuredImage?.alt ?? \"\",\n }\n : null,\n })\n }\n />\n </Field>\n <Field label=\"Image description\">\n <input\n value={course.featuredImage?.alt ?? \"\"}\n onChange={(event) =>\n course.featuredImage &&\n patch({ featuredImage: { ...course.featuredImage, alt: event.target.value } })\n }\n />\n </Field>\n <div>\n <ChoicesField\n label=\"Additional instructors\"\n value={course.instructorIds}\n choices={instructorChoices.items.map((account) => ({\n id: account.id,\n label: account.name || account.email,\n }))}\n onChange={(instructorIds) => patch({ instructorIds })}\n />\n {instructorChoices.data?.hasMore && (\n <Button onClick={instructorChoices.more}>Load more instructors</Button>\n )}\n <Notice error={instructorChoices.error} />\n </div>\n </div>\n </Panel>\n )}\n {tab === \"access\" && (\n <Panel>\n <div className=\"lms-grid\">\n <Field label=\"Enrollment\">\n <select\n value={course.enrollmentMode}\n onChange={(event) =>\n patch({ enrollmentMode: event.target.value as CourseData[\"enrollmentMode\"] })\n }\n >\n <option value=\"open\">Free · open enrollment</option>\n <option value=\"approval\">Administrator approval</option>\n <option value=\"invite\">Invitation only</option>\n </select>\n </Field>\n <Field label=\"Access duration in days\" help=\"0 gives unlimited access.\">\n <input\n type=\"number\"\n min={0}\n max={3650}\n value={course.accessDays}\n onChange={(event) => patch({ accessDays: Number(event.target.value) })}\n />\n </Field>\n <Field label=\"Enrollment closes\">\n <input\n type=\"datetime-local\"\n value={localDate(course.enrollmentClosesAt)}\n onChange={(event) => patch({ enrollmentClosesAt: isoDate(event.target.value) })}\n />\n </Field>\n <div>\n <ChoicesField\n label=\"Prerequisite courses\"\n value={course.prerequisiteCourseIds}\n choices={prerequisiteChoices.items\n .filter((value) => value.id !== course.id)\n .map((value) => ({ id: value.id, label: value.title }))}\n onChange={(prerequisiteCourseIds) => patch({ prerequisiteCourseIds })}\n />\n {prerequisiteChoices.data?.hasMore && (\n <Button onClick={prerequisiteChoices.more}>Load more courses</Button>\n )}\n <Notice error={prerequisiteChoices.error} />\n </div>\n </div>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={course.sequential}\n onChange={(event) => patch({ sequential: event.target.checked })}\n />\n Require lessons in order\n </label>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={course.certificateEnabled}\n onChange={(event) => patch({ certificateEnabled: event.target.checked })}\n />\n Issue a certificate after all required lessons are passed\n </label>\n </Panel>\n )}\n {tab === \"curriculum\" && (\n <div className=\"lms-studio\">\n <aside className=\"lms-panel\">\n <h2>Modules & lessons</h2>\n {course.modules.map((module, moduleIndex) => (\n <section className=\"lms-module\" key={module.id}>\n <Field label={`Module ${moduleIndex + 1}`}>\n <input\n value={module.title}\n onChange={(event) => updateModule(moduleIndex, { title: event.target.value })}\n />\n </Field>\n <div className=\"lms-grid\">\n <Field label=\"Release after days\">\n <input\n type=\"number\"\n min={0}\n value={module.releaseDays}\n onChange={(event) =>\n updateModule(moduleIndex, { releaseDays: Number(event.target.value) })\n }\n />\n </Field>\n <Field label=\"Release date\">\n <input\n type=\"datetime-local\"\n value={localDate(module.unlockAt)}\n onChange={(event) =>\n updateModule(moduleIndex, { unlockAt: isoDate(event.target.value) })\n }\n />\n </Field>\n </div>\n <ol className=\"lms-lesson-list\">\n {module.lessons.map((lesson, lessonIndex) => (\n <li key={lesson.id}>\n <button\n className=\"lms-select-lesson\"\n aria-current={selected === lesson.id}\n onClick={() => setSelected(lesson.id)}\n >\n {lesson.title}\n <small>\n {lesson.kind}\n {lesson.required ? \" · required\" : \" · optional\"}\n </small>\n </button>\n <div className=\"lms-actions\">\n <Button\n aria-label={`Move ${lesson.title} up`}\n disabled={lessonIndex === 0}\n onClick={() => reorderLesson(moduleIndex, lessonIndex, -1)}\n >\n ↑\n </Button>\n <Button\n aria-label={`Move ${lesson.title} down`}\n disabled={lessonIndex === module.lessons.length - 1}\n onClick={() => reorderLesson(moduleIndex, lessonIndex, 1)}\n >\n ↓\n </Button>\n </div>\n </li>\n ))}\n </ol>\n <Button\n onClick={() => {\n const lesson = lessonSchema.parse({\n id: crypto.randomUUID(),\n title: \"New lesson\",\n });\n updateModule(moduleIndex, { lessons: [...module.lessons, lesson] });\n setSelected(lesson.id);\n }}\n >\n Add lesson\n </Button>\n {module.lessons.length === 0 && (\n <Button\n danger\n onClick={() =>\n patch({ modules: course.modules.filter((item) => item.id !== module.id) })\n }\n >\n Remove empty module\n </Button>\n )}\n <div className=\"lms-actions\">\n <Button\n disabled={moduleIndex === 0}\n aria-label={`Move module ${module.title} up`}\n onClick={() => {\n const next = [...course.modules];\n [next[moduleIndex], next[moduleIndex - 1]] = [\n next[moduleIndex - 1]!,\n next[moduleIndex]!,\n ];\n patch({ modules: next });\n }}\n >\n Move module up\n </Button>\n </div>\n </section>\n ))}\n <Button\n onClick={() =>\n patch({\n modules: [\n ...course.modules,\n moduleSchema.parse({\n id: crypto.randomUUID(),\n title: `Module ${course.modules.length + 1}`,\n }),\n ],\n })\n }\n >\n Add module\n </Button>\n </aside>\n <Panel title={selectedLesson?.title ?? \"Choose a lesson\"}>\n {selectedLesson ? (\n <LessonEditor\n lesson={selectedLesson}\n update={(data) => updateLesson(selectedLesson.id, data)}\n remove={() => {\n if (window.confirm(`Remove “${selectedLesson.title}” from the draft?`)) {\n patch({\n modules: course.modules.map((module) => ({\n ...module,\n lessons: module.lessons.filter((lesson) => lesson.id !== selectedLesson.id),\n })),\n });\n setSelected(null);\n }\n }}\n />\n ) : (\n <p>Add a module and a lesson to begin.</p>\n )}\n </Panel>\n </div>\n )}\n </PageFrame>\n );\n}\n\nfunction ContentPicker({\n value,\n onChange,\n}: {\n value: Lesson[\"contentSource\"];\n onChange: (value: Lesson[\"contentSource\"]) => void;\n}) {\n type CollectionChoice = {\n slug: string;\n label: string;\n fields: { slug: string; label: string; type: string }[];\n };\n type EntryChoice = { id: string; title: string };\n const schema = useLoad<CollectionChoice[]>(\"admin/content/collections\");\n const [collection, setCollection] = useState(value?.collection ?? \"\");\n const [cursor, setCursor] = useState<string>();\n const [entries, setEntries] = useState<EntryChoice[]>([]);\n const list = useLoad<Page<EntryChoice>>(\n \"admin/content/entries\",\n { collection, cursor, limit: 100 },\n !!collection,\n );\n useEffect(() => {\n if (list.data)\n setEntries((old) => [\n ...new Map([...old, ...list.data!.items].map((entry) => [entry.id, entry])).values(),\n ]);\n }, [list.data]);\n const fields = schema.data?.find((entry) => entry.slug === collection)?.fields ?? [];\n return (\n <details>\n <summary>Use published EmDash content</summary>\n <p>Choose a published entry and its text field to reuse formatted lesson content.</p>\n <Notice error={schema.error || list.error} />\n <div className=\"lms-grid\">\n <Field label=\"Collection\">\n <select\n value={collection}\n onChange={(event) => {\n setCollection(event.target.value);\n setCursor(undefined);\n setEntries([]);\n onChange(null);\n }}\n >\n <option value=\"\">Use this lesson's own content</option>\n {schema.data?.map((entry) => (\n <option key={entry.slug} value={entry.slug}>\n {entry.label}\n </option>\n ))}\n </select>\n </Field>\n {collection && (\n <>\n <Field label=\"Published entry\">\n <select\n value={value?.id ?? \"\"}\n onChange={(event) =>\n onChange(\n event.target.value\n ? {\n collection,\n id: event.target.value,\n field:\n value?.field ??\n fields.find((field) => field.type === \"portableText\")?.slug ??\n fields[0]?.slug ??\n \"content\",\n }\n : null,\n )\n }\n >\n <option value=\"\">Choose an entry</option>\n {value && !entries.some((entry) => entry.id === value.id) && (\n <option value={value.id}>Current linked entry</option>\n )}\n {entries.map((entry) => (\n <option key={entry.id} value={entry.id}>\n {entry.title}\n </option>\n ))}\n </select>\n </Field>\n <Field label=\"Content field\">\n <select\n value={value?.field ?? \"\"}\n disabled={!value}\n onChange={(event) => value && onChange({ ...value, field: event.target.value })}\n >\n <option value=\"\">Choose a field</option>\n {fields.map((field) => (\n <option key={field.slug} value={field.slug}>\n {field.label}\n </option>\n ))}\n </select>\n </Field>\n </>\n )}\n </div>\n {list.data?.hasMore && (\n <Button onClick={() => setCursor(list.data?.cursor)}>Load more entries</Button>\n )}\n </details>\n );\n}\n\nfunction LessonEditor({\n lesson,\n update,\n remove,\n}: {\n lesson: Lesson;\n update: (data: Partial<Lesson>) => void;\n remove: () => void;\n}) {\n return (\n <>\n <div className=\"lms-grid\">\n <Field label=\"Lesson title\">\n <input value={lesson.title} onChange={(event) => update({ title: event.target.value })} />\n </Field>\n <Field label=\"Lesson type\">\n <select\n value={lesson.kind}\n onChange={(event) => {\n const kind = event.target.value as Lesson[\"kind\"];\n update({\n kind,\n preview: [\"quiz\", \"assignment\", \"live\"].includes(kind) ? false : lesson.preview,\n quiz:\n kind === \"quiz\"\n ? (lesson.quiz ?? quizSchema.parse({ questions: [defaultQuestion()] }))\n : null,\n assignment:\n kind === \"assignment\"\n ? (lesson.assignment ??\n assignmentSchema.parse({ instructions: \"Submit your work here.\" }))\n : null,\n });\n }}\n >\n {[\"text\", \"video\", \"audio\", \"quiz\", \"assignment\", \"live\"].map((kind) => (\n <option key={kind}>{kind}</option>\n ))}\n </select>\n </Field>\n <Field label=\"Estimated minutes\">\n <input\n type=\"number\"\n min={0}\n value={lesson.durationMinutes}\n onChange={(event) => update({ durationMinutes: Number(event.target.value) })}\n />\n </Field>\n <Field label=\"Minimum study seconds\">\n <input\n type=\"number\"\n min={0}\n value={lesson.minStudySeconds}\n onChange={(event) => update({ minStudySeconds: Number(event.target.value) })}\n />\n </Field>\n </div>\n <Field label=\"Summary\">\n <textarea\n rows={2}\n value={lesson.summary}\n onChange={(event) => update({ summary: event.target.value })}\n />\n </Field>\n <Field label=\"Lesson text\">\n <textarea\n rows={12}\n value={lesson.body}\n onChange={(event) => update({ body: event.target.value })}\n />\n </Field>\n {[\"video\", \"audio\", \"live\"].includes(lesson.kind) && (\n <Field\n label={lesson.kind === \"live\" ? \"Meeting link\" : \"Media URL\"}\n help=\"Use a direct media file, YouTube link, or Vimeo link.\"\n >\n <input\n type=\"url\"\n value={lesson.mediaUrl ?? \"\"}\n onChange={(event) => update({ mediaUrl: event.target.value || null })}\n />\n </Field>\n )}\n {lesson.kind === \"live\" && (\n <Field label=\"Session starts\">\n <input\n type=\"datetime-local\"\n value={localDate(lesson.liveStartsAt)}\n onChange={(event) => update({ liveStartsAt: isoDate(event.target.value) })}\n />\n </Field>\n )}\n <div className=\"lms-actions\">\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={lesson.required}\n onChange={(event) => update({ required: event.target.checked })}\n />\n Required for completion\n </label>\n {![\"quiz\", \"assignment\", \"live\"].includes(lesson.kind) && (\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={lesson.preview}\n onChange={(event) => update({ preview: event.target.checked })}\n />\n Free preview\n </label>\n )}\n </div>\n <ContentPicker\n key={lesson.id}\n value={lesson.contentSource}\n onChange={(contentSource) => update({ contentSource })}\n />\n {lesson.kind === \"quiz\" && lesson.quiz && (\n <QuizEditor quiz={lesson.quiz} update={(quiz) => update({ quiz })} />\n )}\n {lesson.kind === \"assignment\" && lesson.assignment && (\n <Panel title=\"Assignment\">\n <Field label=\"Instructions\">\n <textarea\n rows={6}\n value={lesson.assignment.instructions}\n onChange={(event) =>\n update({ assignment: { ...lesson.assignment!, instructions: event.target.value } })\n }\n />\n </Field>\n <div className=\"lms-grid\">\n <Field label=\"Maximum points\">\n <input\n type=\"number\"\n min={1}\n value={lesson.assignment.maxPoints}\n onChange={(event) =>\n update({\n assignment: { ...lesson.assignment!, maxPoints: Number(event.target.value) },\n })\n }\n />\n </Field>\n <Field label=\"Passing points\">\n <input\n type=\"number\"\n min={1}\n value={lesson.assignment.passingPoints}\n onChange={(event) =>\n update({\n assignment: {\n ...lesson.assignment!,\n passingPoints: Number(event.target.value),\n },\n })\n }\n />\n </Field>\n <Field label=\"Due date\">\n <input\n type=\"datetime-local\"\n value={localDate(lesson.assignment.dueAt)}\n onChange={(event) =>\n update({\n assignment: { ...lesson.assignment!, dueAt: isoDate(event.target.value) },\n })\n }\n />\n </Field>\n </div>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={lesson.assignment.allowResubmission}\n onChange={(event) =>\n update({\n assignment: { ...lesson.assignment!, allowResubmission: event.target.checked },\n })\n }\n />\n Allow another submission after a failing grade\n </label>\n </Panel>\n )}\n <Panel title=\"Lesson resources\">\n {lesson.resources.map((resource, index) => (\n <div className=\"lms-resource\" key={resource.id}>\n <Field label={`Resource ${index + 1}`}>\n <input\n value={resource.title}\n onChange={(event) =>\n update({\n resources: lesson.resources.map((item) =>\n item.id === resource.id ? { ...item, title: event.target.value } : item,\n ),\n })\n }\n />\n </Field>\n <Field label=\"URL\">\n <input\n value={resource.url}\n onChange={(event) =>\n update({\n resources: lesson.resources.map((item) =>\n item.id === resource.id ? { ...item, url: event.target.value } : item,\n ),\n })\n }\n />\n </Field>\n <Button\n danger\n onClick={() =>\n update({ resources: lesson.resources.filter((item) => item.id !== resource.id) })\n }\n >\n Remove resource\n </Button>\n </div>\n ))}\n <Button\n onClick={() =>\n update({\n resources: [\n ...lesson.resources,\n { id: crypto.randomUUID(), title: \"New resource\", url: \"/\", description: \"\" },\n ],\n })\n }\n >\n Add resource\n </Button>\n </Panel>\n <Button danger onClick={remove}>\n Remove lesson\n </Button>\n </>\n );\n}\n\nfunction defaultQuestion(): QuizQuestion {\n return questionSchema.parse({\n id: crypto.randomUUID(),\n type: \"single\",\n prompt: \"New question\",\n options: [\n { id: \"a\", text: \"First option\" },\n { id: \"b\", text: \"Second option\" },\n ],\n correctAnswers: [\"a\"],\n });\n}\nfunction QuizEditor({\n quiz,\n update,\n}: {\n quiz: NonNullable<Lesson[\"quiz\"]>;\n update: (quiz: NonNullable<Lesson[\"quiz\"]>) => void;\n}) {\n const patchQuestion = (id: string, data: Partial<QuizQuestion>) =>\n update({\n ...quiz,\n questions: quiz.questions.map((question) =>\n question.id === id ? { ...question, ...data } : question,\n ),\n });\n return (\n <Panel title=\"Quiz\">\n <div className=\"lms-grid\">\n <Field label=\"Passing percentage\">\n <input\n type=\"number\"\n min={1}\n max={100}\n value={quiz.passingPercent}\n onChange={(event) => update({ ...quiz, passingPercent: Number(event.target.value) })}\n />\n </Field>\n <Field label=\"Maximum attempts\">\n <input\n type=\"number\"\n min={1}\n max={20}\n value={quiz.maxAttempts}\n onChange={(event) => update({ ...quiz, maxAttempts: Number(event.target.value) })}\n />\n </Field>\n <Field label=\"Time limit in minutes\" help=\"0 gives an untimed quiz.\">\n <input\n type=\"number\"\n min={0}\n max={180}\n value={quiz.timeLimitMinutes}\n onChange={(event) => update({ ...quiz, timeLimitMinutes: Number(event.target.value) })}\n />\n </Field>\n <Field label=\"Show explanations\">\n <select\n value={quiz.showFeedback}\n onChange={(event) =>\n update({ ...quiz, showFeedback: event.target.value as typeof quiz.showFeedback })\n }\n >\n <option value=\"after_pass\">After passing</option>\n <option value=\"after_submit\">After each submission</option>\n <option value=\"never\">Never</option>\n </select>\n </Field>\n </div>\n <div className=\"lms-actions\">\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={quiz.randomizeQuestions}\n onChange={(event) => update({ ...quiz, randomizeQuestions: event.target.checked })}\n />\n Shuffle questions\n </label>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={quiz.randomizeOptions}\n onChange={(event) => update({ ...quiz, randomizeOptions: event.target.checked })}\n />\n Shuffle choices\n </label>\n </div>\n {quiz.questions.map((question, index) => (\n <section className=\"lms-question\" key={question.id}>\n <h3>Question {index + 1}</h3>\n <div className=\"lms-grid\">\n <Field label=\"Type\">\n <select\n value={question.type}\n onChange={(event) => {\n const type = event.target.value as QuizQuestion[\"type\"];\n const options =\n type === \"true_false\"\n ? [\n { id: \"true\", text: \"True\" },\n { id: \"false\", text: \"False\" },\n ]\n : type === \"short\"\n ? []\n : question.options.length\n ? question.options\n : [\n { id: \"a\", text: \"First option\" },\n { id: \"b\", text: \"Second option\" },\n ];\n patchQuestion(question.id, {\n type,\n options,\n correctAnswers: type === \"short\" ? [\"Accepted answer\"] : [options[0]!.id],\n });\n }}\n >\n {[\n [\"single\", \"Single choice\"],\n [\"multiple\", \"Multiple choices\"],\n [\"true_false\", \"True or false\"],\n [\"short\", \"Short answer\"],\n ].map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </select>\n </Field>\n <Field label=\"Points\">\n <input\n type=\"number\"\n min={1}\n max={100}\n value={question.points}\n onChange={(event) =>\n patchQuestion(question.id, { points: Number(event.target.value) })\n }\n />\n </Field>\n </div>\n <Field label=\"Question\">\n <textarea\n rows={3}\n value={question.prompt}\n onChange={(event) => patchQuestion(question.id, { prompt: event.target.value })}\n />\n </Field>\n {question.type === \"short\" ? (\n <Field\n label=\"Accepted answers\"\n help=\"One answer per line. Matching ignores case and extra spaces.\"\n >\n <textarea\n value={question.correctAnswers.join(\"\\n\")}\n onChange={(event) =>\n patchQuestion(question.id, {\n correctAnswers: event.target.value.split(\"\\n\").filter(Boolean),\n })\n }\n />\n </Field>\n ) : (\n <fieldset>\n <legend>Answer choices · select the correct answers</legend>\n {question.options.map((option) => (\n <div className=\"lms-option\" key={option.id}>\n <input\n aria-label={`Mark ${option.text} correct`}\n type={question.type === \"multiple\" ? \"checkbox\" : \"radio\"}\n name={`correct-${question.id}`}\n checked={question.correctAnswers.includes(option.id)}\n onChange={(event) =>\n patchQuestion(question.id, {\n correctAnswers:\n question.type === \"multiple\"\n ? event.target.checked\n ? [...question.correctAnswers, option.id]\n : question.correctAnswers.filter((id) => id !== option.id)\n : [option.id],\n })\n }\n />\n <input\n aria-label=\"Answer text\"\n value={option.text}\n onChange={(event) =>\n patchQuestion(question.id, {\n options: question.options.map((item) =>\n item.id === option.id ? { ...item, text: event.target.value } : item,\n ),\n })\n }\n />\n {question.type !== \"true_false\" && question.options.length > 2 && (\n <Button\n aria-label={`Remove answer ${option.text}`}\n onClick={() =>\n patchQuestion(question.id, {\n options: question.options.filter((item) => item.id !== option.id),\n correctAnswers: question.correctAnswers.filter((id) => id !== option.id),\n })\n }\n >\n ×\n </Button>\n )}\n </div>\n ))}\n {question.type !== \"true_false\" && question.options.length < 10 && (\n <Button\n onClick={() =>\n patchQuestion(question.id, {\n options: [\n ...question.options,\n { id: crypto.randomUUID(), text: \"New option\" },\n ],\n })\n }\n >\n Add answer choice\n </Button>\n )}\n </fieldset>\n )}\n <Field label=\"Explanation\">\n <textarea\n rows={2}\n value={question.explanation}\n onChange={(event) => patchQuestion(question.id, { explanation: event.target.value })}\n />\n </Field>\n <div className=\"lms-actions\">\n <Button\n disabled={index === 0}\n aria-label={`Move question ${index + 1} up`}\n onClick={() => {\n const next = [...quiz.questions];\n [next[index], next[index - 1]] = [next[index - 1]!, next[index]!];\n update({ ...quiz, questions: next });\n }}\n >\n Move up\n </Button>\n <Button\n danger\n disabled={quiz.questions.length < 2}\n onClick={() =>\n update({\n ...quiz,\n questions: quiz.questions.filter((item) => item.id !== question.id),\n })\n }\n >\n Remove question\n </Button>\n </div>\n </section>\n ))}\n {quiz.questions.length < 50 && (\n <Button\n onClick={() => update({ ...quiz, questions: [...quiz.questions, defaultQuestion()] })}\n >\n Add question\n </Button>\n )}\n </Panel>\n );\n}\n\nfunction localDate(value: string | null): string {\n if (!value) return \"\";\n const date = new Date(value);\n const offset = date.getTimezoneOffset() * 60_000;\n return new Date(date.getTime() - offset).toISOString().slice(0, 16);\n}\nfunction isoDate(value: string): string | null {\n return value ? new Date(value).toISOString() : null;\n}\nfunction download(name: string, body: string, type: string) {\n const url = URL.createObjectURL(new Blob([body], { type }));\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = name;\n anchor.click();\n setTimeout(() => URL.revokeObjectURL(url), 1000);\n}\n\nfunction EnrollmentAccessEditor({\n row,\n close,\n saved,\n}: {\n row: EnrollmentRow;\n close: () => void;\n saved: () => void;\n}) {\n const [status, setStatus] = useState(\n row.status === \"pending\" || row.status === \"completed\" ? \"active\" : row.status,\n );\n const [reason, setReason] = useState(row.decisionReason ?? \"\");\n const [startsAt, setStartsAt] = useState(row.accessStartsAt);\n const [expiresAt, setExpiresAt] = useState(row.accessExpiresAt);\n const action = useAction();\n return (\n <Panel title={`Manage ${row.learnerName}'s access`}>\n <p>{row.courseTitle}</p>\n <Notice error={action.error} />\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void action.run(async () => {\n await api(\n \"admin/enrollment/save\",\n {\n courseId: row.courseId,\n userId: row.userId,\n status,\n reason,\n accessStartsAt: startsAt,\n accessExpiresAt: expiresAt,\n },\n \"POST\",\n );\n saved();\n });\n }}\n >\n <div className=\"lms-grid\">\n <Field label=\"Enrollment decision\">\n <select\n value={status}\n onChange={(event) => setStatus(event.target.value as typeof status)}\n >\n {[\"active\", \"rejected\", \"suspended\", \"cancelled\"].map((value) => (\n <option key={value} value={value}>\n {value === \"active\" ? \"Approve / restore access\" : value}\n </option>\n ))}\n </select>\n </Field>\n <Field label=\"Access starts\">\n <input\n type=\"datetime-local\"\n value={localDate(startsAt)}\n onChange={(event) => setStartsAt(isoDate(event.target.value))}\n />\n </Field>\n <Field label=\"Access expires\">\n <input\n type=\"datetime-local\"\n value={localDate(expiresAt)}\n onChange={(event) => setExpiresAt(isoDate(event.target.value))}\n />\n </Field>\n <Field label=\"Decision note\">\n <textarea\n maxLength={1000}\n value={reason}\n onChange={(event) => setReason(event.target.value)}\n />\n </Field>\n </div>\n <p>\n These access dates apply to this learner's course enrollment. Leave blank for no\n additional date restriction.\n </p>\n <div className=\"lms-actions\">\n <Button type=\"submit\" busy={action.busy}>\n Save access\n </Button>\n <Button onClick={close}>Close</Button>\n </div>\n </form>\n </Panel>\n );\n}\n\nexport function LearnersPage() {\n const [courseId, setCourseId] = useState(\"\");\n const [status, setStatus] = useState(\"\");\n const [cursor, setCursor] = useState<string>();\n const [email, setEmail] = useState(\"\");\n const [managing, setManaging] = useState<EnrollmentRow>();\n const list = useLoad<Page<EnrollmentRow>>(\"admin/enrollments\", { courseId, status, cursor });\n const action = useAction();\n const update = (row: EnrollmentRow, next: string) =>\n void action.run(async () => {\n await api(\n \"admin/enrollment/save\",\n { courseId: row.courseId, userId: row.userId, status: next },\n \"POST\",\n );\n list.reload();\n }, \"Enrollment updated.\");\n const add = (event: FormEvent) => {\n event.preventDefault();\n void action.run(async () => {\n if (!courseId) throw new Error(\"Choose a course first.\");\n const target = await api<UserChoice>(\"admin/learner/find\", { courseId, email }, \"POST\");\n await api(\"admin/enrollment/save\", { courseId, userId: target.id, status: \"active\" }, \"POST\");\n setEmail(\"\");\n list.reload();\n }, \"Learner enrolled.\");\n };\n return (\n <PageFrame\n title=\"Enrollments\"\n description=\"Approve requests, enroll learners, and manage access.\"\n >\n <Notice error={list.error || action.error} message={action.message} />\n {managing && (\n <EnrollmentAccessEditor\n key={managing.id}\n row={managing}\n close={() => setManaging(undefined)}\n saved={() => {\n setManaging(undefined);\n list.reload();\n }}\n />\n )}\n <div className=\"lms-grid\">\n <CoursePicker\n value={courseId}\n allowAll\n onChange={(id) => {\n setCourseId(id);\n setCursor(undefined);\n }}\n />\n <Field label=\"Status\">\n <select\n value={status}\n onChange={(event) => {\n setStatus(event.target.value);\n setCursor(undefined);\n }}\n >\n <option value=\"\">All statuses</option>\n {[\"pending\", \"active\", \"completed\", \"rejected\", \"suspended\", \"cancelled\"].map(\n (value) => (\n <option key={value}>{value}</option>\n ),\n )}\n </select>\n </Field>\n </div>\n {courseId && (\n <Panel title=\"Enroll an existing account\">\n <form onSubmit={add} className=\"lms-toolbar\">\n <Field label=\"Learner email\">\n <input\n type=\"email\"\n required\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n />\n </Field>\n <Button type=\"submit\" busy={action.busy}>\n Enroll learner\n </Button>\n </form>\n </Panel>\n )}\n <Panel>\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Learner</th>\n <th>Course</th>\n <th>Progress</th>\n <th>Status</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n {list.data?.items.map((row) => (\n <tr key={row.id}>\n <td>\n {row.learnerName}\n <small>{row.learnerEmail}</small>\n </td>\n <td>{row.courseTitle}</td>\n <td>\n {row.progressSummary?.percent ?? 0}%\n <small>\n {row.completedAt\n ? new Date(row.completedAt).toLocaleDateString()\n : \"In progress\"}\n </small>\n </td>\n <td>\n {row.status}\n <small>Access: {row.effectiveAccess}</small>\n <small>Source: {row.accessSource}</small>\n </td>\n <td>\n <div className=\"lms-actions\">\n <Button onClick={() => setManaging(row)}>Manage access</Button>\n {row.status === \"pending\" && (\n <Button danger busy={action.busy} onClick={() => update(row, \"rejected\")}>\n Reject\n </Button>\n )}\n {[\"pending\", \"rejected\", \"suspended\", \"cancelled\"].includes(row.status) && (\n <Button busy={action.busy} onClick={() => update(row, \"active\")}>\n {row.status === \"pending\" ? \"Approve\" : \"Restore\"}\n </Button>\n )}\n {[\"active\", \"completed\"].includes(row.status) && (\n <Button busy={action.busy} onClick={() => update(row, \"suspended\")}>\n Suspend\n </Button>\n )}\n {row.status !== \"cancelled\" && (\n <Button\n danger\n busy={action.busy}\n onClick={() => {\n if (\n window.confirm(`Cancel ${row.learnerName}'s access to this course?`)\n )\n update(row, \"cancelled\");\n }}\n >\n Cancel\n </Button>\n )}\n {row.certificate && !row.certificate.revokedAt && (\n <Button\n danger\n busy={action.busy}\n onClick={() => {\n const reason = window.prompt(\"Reason for revoking this certificate:\");\n if (reason?.trim())\n void action.run(async () => {\n await api(\n \"admin/certificate/revoke\",\n { courseId: row.courseId, userId: row.userId, reason },\n \"POST\",\n );\n list.reload();\n }, \"Certificate revoked.\");\n }}\n >\n Revoke certificate\n </Button>\n )}\n </div>\n <details>\n <summary>Learning record</summary>\n {Object.entries(row.progress).map(([id, progress]) => (\n <p key={id}>\n {row.lessonTitles[id] ?? \"Lesson\"} ·{\" \"}\n {progress.completedAt ? \"Complete\" : \"Started\"} ·{\" \"}\n {progress.quizAttempts.length} quiz attempts ·{\" \"}\n {progress.assignments.length} submissions\n </p>\n ))}\n </details>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {list.data && !list.data.items.length && <p>No enrollments match this filter.</p>}\n </Panel>\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nexport function AssignmentsPage() {\n const [courseId, setCourseId] = useState(\"\");\n const [cursor, setCursor] = useState<string>();\n const list = useLoad<\n Page<\n AssignmentSubmission & {\n userId: string;\n learnerName: string;\n courseId: string;\n lessonId: string;\n }\n >\n >(\"admin/assignments\", { courseId, cursor }, !!courseId);\n const [selected, setSelected] = useState<\n AssignmentSubmission & {\n userId: string;\n learnerName: string;\n courseId: string;\n lessonId: string;\n }\n >();\n const [points, setPoints] = useState(0);\n const [feedback, setFeedback] = useState(\"\");\n const action = useAction();\n const grade = (event: FormEvent) => {\n event.preventDefault();\n if (!selected) return;\n void action.run(async () => {\n await api(\n \"admin/assignment/grade\",\n {\n courseId: selected.courseId,\n lessonId: selected.lessonId,\n userId: selected.userId,\n submissionId: selected.id,\n points,\n feedback,\n },\n \"POST\",\n );\n setSelected(undefined);\n list.reload();\n }, \"Grade saved and learner notified.\");\n };\n return (\n <PageFrame\n title=\"Assignments\"\n description=\"Read submissions and provide clear, useful feedback.\"\n >\n <Notice error={list.error || action.error} message={action.message} />\n <CoursePicker\n value={courseId}\n onChange={(id) => {\n setCourseId(id);\n setCursor(undefined);\n setSelected(undefined);\n }}\n />\n {!courseId && (\n <Panel>\n <p>Choose a course to view its submissions.</p>\n </Panel>\n )}\n {selected && (\n <Panel title={`Grade ${selected.learnerName}'s submission`}>\n <p className=\"lms-body\">{selected.body}</p>\n {selected.attachmentUrl && (\n <a href={selected.attachmentUrl} target=\"_blank\" rel=\"noopener noreferrer\">\n Open attachment ↗\n </a>\n )}\n <form onSubmit={grade}>\n <Field\n label={`Points out of ${selected.maxPoints}`}\n help={`Passing grade: ${selected.passingPoints}`}\n >\n <input\n type=\"number\"\n required\n min={0}\n max={selected.maxPoints}\n value={points}\n onChange={(event) => setPoints(Number(event.target.value))}\n />\n </Field>\n <Field label=\"Feedback\">\n <textarea\n rows={6}\n value={feedback}\n onChange={(event) => setFeedback(event.target.value)}\n />\n </Field>\n <div className=\"lms-actions\">\n <Button type=\"submit\" busy={action.busy}>\n Save grade\n </Button>\n <Button onClick={() => setSelected(undefined)}>Close</Button>\n </div>\n </form>\n </Panel>\n )}\n {list.data?.items.map((item) => (\n <Panel key={item.id}>\n <div className=\"lms-toolbar\">\n <h2>{item.learnerName}</h2>\n <span className=\"lms-badge\">{item.status}</span>\n <small>{new Date(item.submittedAt).toLocaleString()}</small>\n </div>\n <p className=\"lms-body\">{item.body}</p>\n {item.attachmentUrl && (\n <p>\n <a href={item.attachmentUrl} target=\"_blank\" rel=\"noopener noreferrer\">\n Open attachment ↗\n </a>\n </p>\n )}\n {item.status === \"graded\" ? (\n <>\n <p>\n {item.points}/{item.maxPoints} points\n </p>\n <p className=\"lms-body\">{item.feedback}</p>\n </>\n ) : (\n <Button\n onClick={() => {\n setSelected(item);\n setPoints(0);\n setFeedback(\"\");\n }}\n >\n Review & grade\n </Button>\n )}\n </Panel>\n ))}\n {list.data && !list.data.items.length && (\n <Panel>\n <p>No submissions on this page.</p>\n </Panel>\n )}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nexport function CommunityPage() {\n const [courseId, setCourseId] = useState(\"\");\n const [kind, setKind] = useState<\"discussions\" | \"reviews\">(\"discussions\");\n const [status, setStatus] = useState(\"pending\");\n const [cursor, setCursor] = useState<string>();\n const list = useLoad<Page<(Discussion | Review) & { revision: string }>>(`admin/${kind}`, {\n courseId,\n status,\n cursor,\n });\n const action = useAction();\n const moderate = (item: (Discussion | Review) & { revision: string }, next: string) =>\n void action.run(async () => {\n await api(\n `admin/${kind === \"reviews\" ? \"review\" : \"discussion\"}/moderate`,\n { id: item.id, expectedRevision: item.revision, status: next },\n \"POST\",\n );\n list.reload();\n }, \"Moderation saved.\");\n return (\n <PageFrame\n title=\"Learning community\"\n description=\"Moderate lesson discussions and course reviews.\"\n >\n <Notice error={list.error || action.error} message={action.message} />\n <div className=\"lms-grid\">\n <CoursePicker\n value={courseId}\n allowAll\n onChange={(id) => {\n setCourseId(id);\n setCursor(undefined);\n }}\n />\n <Field label=\"Content\">\n <select\n value={kind}\n onChange={(event) => {\n setKind(event.target.value as typeof kind);\n setCursor(undefined);\n }}\n >\n <option value=\"discussions\">Discussions</option>\n <option value=\"reviews\">Reviews</option>\n </select>\n </Field>\n <Field label=\"Status\">\n <select\n value={status}\n onChange={(event) => {\n setStatus(event.target.value);\n setCursor(undefined);\n }}\n >\n {[\"pending\", \"published\", \"hidden\"].map((value) => (\n <option key={value}>{value}</option>\n ))}\n </select>\n </Field>\n </div>\n {list.data?.items.map((item) => (\n <Panel key={item.id}>\n <h2>\n {item.authorName}\n {\"rating\" in item ? ` · ${item.rating}/5` : \"\"}\n </h2>\n <p className=\"lms-body\">{item.body}</p>\n <p className=\"lms-muted\">\n {new Date(item.createdAt).toLocaleString()} · {item.status}\n </p>\n <div className=\"lms-actions\">\n {item.status !== \"published\" && (\n <Button busy={action.busy} onClick={() => moderate(item, \"published\")}>\n Publish\n </Button>\n )}\n {item.status !== \"hidden\" && (\n <Button danger busy={action.busy} onClick={() => moderate(item, \"hidden\")}>\n Hide\n </Button>\n )}\n </div>\n </Panel>\n ))}\n {list.data && !list.data.items.length && (\n <Panel>\n <p>No community posts match this filter.</p>\n </Panel>\n )}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nfunction CohortMembershipQueue() {\n const cohorts = useChoices<Cohort>(\"admin/cohorts\");\n const [cohortId, setCohortId] = useState(\"\");\n const [status, setStatus] = useState(\"pending\");\n const [cursor, setCursor] = useState<string>();\n const [reason, setReason] = useState(\"\");\n const list = useLoad<Page<CohortMembership>>(\"admin/cohort/memberships\", {\n cohortId,\n status,\n cursor,\n });\n const action = useAction();\n const decide = (membership: CohortMembership, next: string) =>\n void action.run(async () => {\n const result = await api<{\n results: { courseId: string; success: boolean; error?: string }[];\n }>(\n \"admin/cohort/decision\",\n { cohortId: membership.cohortId, userId: membership.userId, status: next, reason },\n \"POST\",\n );\n list.reload();\n const failures = result.results.filter((item) => !item.success);\n if (failures.length)\n throw new Error(\n `Membership saved; ${failures.length} course access updates need attention. ${failures.map((item) => item.error).join(\" \")} Review the learner's course enrollment and retry access.`,\n );\n }, \"Cohort membership updated.\");\n return (\n <Panel title=\"Cohort membership requests\">\n <Notice error={list.error || action.error} message={action.message} />\n <div className=\"lms-grid\">\n <Field label=\"Cohort\">\n <select\n value={cohortId}\n onChange={(event) => {\n setCohortId(event.target.value);\n setCursor(undefined);\n }}\n >\n <option value=\"\">All cohorts</option>\n {cohorts.items.map((cohort) => (\n <option key={cohort.id} value={cohort.id}>\n {cohort.title}\n </option>\n ))}\n </select>\n {cohorts.data?.hasMore && <Button onClick={cohorts.more}>Load more cohorts</Button>}\n </Field>\n <Field label=\"Membership status\">\n <select\n value={status}\n onChange={(event) => {\n setStatus(event.target.value);\n setCursor(undefined);\n }}\n >\n <option value=\"\">All statuses</option>\n {[\"pending\", \"active\", \"rejected\", \"suspended\", \"cancelled\"].map((value) => (\n <option key={value}>{value}</option>\n ))}\n </select>\n </Field>\n <Field label=\"Decision note (optional)\">\n <input\n value={reason}\n maxLength={1000}\n onChange={(event) => setReason(event.target.value)}\n />\n </Field>\n </div>\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Learner</th>\n <th>Cohort</th>\n <th>Membership</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n {list.data?.items.map((membership) => (\n <tr key={membership.id}>\n <td>\n {membership.learnerName}\n <small>{membership.learnerEmail}</small>\n </td>\n <td>\n {cohorts.items.find((cohort) => cohort.id === membership.cohortId)?.title ??\n \"Cohort\"}\n </td>\n <td>\n {membership.status}\n {membership.reason && <small>{membership.reason}</small>}\n </td>\n <td>\n <div className=\"lms-actions\">\n <Button busy={action.busy} onClick={() => decide(membership, \"active\")}>\n {membership.status === \"pending\"\n ? \"Approve\"\n : membership.status === \"active\"\n ? \"Retry course access\"\n : \"Restore\"}\n </Button>\n {membership.status === \"pending\" && (\n <Button\n danger\n busy={action.busy}\n onClick={() => decide(membership, \"rejected\")}\n >\n Reject\n </Button>\n )}\n {membership.status === \"active\" && (\n <Button busy={action.busy} onClick={() => decide(membership, \"suspended\")}>\n Suspend membership\n </Button>\n )}\n {membership.status !== \"cancelled\" && (\n <Button\n danger\n busy={action.busy}\n onClick={() => decide(membership, \"cancelled\")}\n >\n Cancel membership\n </Button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {list.data && !list.data.items.length && <p>No membership requests match this filter.</p>}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </Panel>\n );\n}\n\nexport function CohortsPage() {\n const [cursor, setCursor] = useState<string>();\n const list = useLoad<Page<Cohort & { revision: string }>>(\"admin/cohorts\", { cursor });\n const courses = useChoices<Course>(\"admin/courses\");\n const users = useChoices<UserChoice>(\"admin/users\");\n const academy = useLoad<{ basePath: string }>(\"academy\");\n const [edit, setEdit] = useState<{\n id?: string;\n revision: string | null;\n title: string;\n courseIds: string[];\n memberIds: string[];\n startsAt: string | null;\n endsAt: string | null;\n }>();\n const action = useAction();\n const save = (event: FormEvent) => {\n event.preventDefault();\n if (!edit) return;\n void action.run(async () => {\n const { id, revision, ...data } = edit;\n await api(\"admin/cohort/save\", { id, expectedRevision: revision, data }, \"POST\");\n setEdit(undefined);\n list.reload();\n }, \"Cohort saved.\");\n };\n const enroll = (cohort: Cohort & { revision: string }) =>\n void action.run(async () => {\n let offset = 0;\n let hasMore = true;\n const errors: string[] = [];\n while (hasMore) {\n const result = await api<{\n nextOffset: number;\n hasMore: boolean;\n results: { success: boolean; error?: string }[];\n }>(\n \"admin/cohort/enroll\",\n { id: cohort.id, expectedRevision: cohort.revision, offset },\n \"POST\",\n );\n offset = result.nextOffset;\n hasMore = result.hasMore;\n errors.push(\n ...result.results\n .filter((row) => !row.success)\n .map((row) => row.error ?? \"Enrollment failed.\"),\n );\n }\n if (errors.length)\n throw new Error(\n `${errors.length} enrollments need attention: ${errors.slice(0, 3).join(\" \")}`,\n );\n }, \"Cohort learners enrolled.\");\n return (\n <PageFrame\n title=\"Cohorts\"\n description=\"Approve cohort membership and manage shared learning schedules.\"\n >\n <Notice\n error={list.error || action.error || courses.error || users.error}\n message={action.message}\n />\n <Button\n onClick={() =>\n setEdit({\n revision: null,\n title: \"New cohort\",\n courseIds: [],\n memberIds: [],\n startsAt: null,\n endsAt: null,\n })\n }\n >\n Create cohort\n </Button>\n {edit && (\n <Panel title=\"Cohort details\">\n <form onSubmit={save}>\n <Field label=\"Cohort name\">\n <input\n required\n value={edit.title}\n onChange={(event) => setEdit({ ...edit, title: event.target.value })}\n />\n </Field>\n <div className=\"lms-grid\">\n <div>\n <ChoicesField\n label=\"Courses\"\n value={edit.courseIds}\n choices={courses.items.map((course) => ({ id: course.id, label: course.title }))}\n onChange={(courseIds) => setEdit({ ...edit, courseIds })}\n />\n {courses.data?.hasMore && <Button onClick={courses.more}>Load more courses</Button>}\n </div>\n <div>\n <ChoicesField\n label=\"Learners for manual enrollment\"\n value={edit.memberIds}\n choices={users.items.map((account) => ({\n id: account.id,\n label: `${account.name || account.email} · ${account.email}`,\n }))}\n onChange={(memberIds) => setEdit({ ...edit, memberIds })}\n />\n {users.data?.hasMore && <Button onClick={users.more}>Load more learners</Button>}\n </div>\n <Field label=\"Access starts\">\n <input\n type=\"datetime-local\"\n value={localDate(edit.startsAt)}\n onChange={(event) => setEdit({ ...edit, startsAt: isoDate(event.target.value) })}\n />\n </Field>\n <Field label=\"Access ends\">\n <input\n type=\"datetime-local\"\n value={localDate(edit.endsAt)}\n onChange={(event) => setEdit({ ...edit, endsAt: isoDate(event.target.value) })}\n />\n </Field>\n </div>\n <div className=\"lms-actions\">\n <Button type=\"submit\" busy={action.busy}>\n Save cohort\n </Button>\n <Button onClick={() => setEdit(undefined)}>Close</Button>\n </div>\n </form>\n </Panel>\n )}\n {list.data?.items.map((cohort) => (\n <Panel key={cohort.id}>\n <h2>{cohort.title}</h2>\n <p>\n {cohort.memberIds.length} learners · {cohort.courseIds.length} courses\n </p>\n <div className=\"lms-actions\">\n <Button onClick={() => setEdit({ ...cohort })}>Edit</Button>\n <a\n href={`${academy.data?.basePath ?? \"/academy\"}/cohorts/${cohort.id}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Open enrollment page ↗\n </a>\n <Button busy={action.busy} onClick={() => enroll(cohort)}>\n Enroll members\n </Button>\n </div>\n </Panel>\n ))}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n <CohortMembershipQueue />\n </PageFrame>\n );\n}\n\nexport function ReportsPage() {\n const [courseId, setCourseId] = useState(\"\");\n const report = useLoad<Report>(\"admin/report\", { courseId });\n const action = useAction();\n const exportCsv = () =>\n void action.run(async () => {\n const rows: EnrollmentRow[] = [];\n let cursor: string | undefined;\n do {\n const page = await api<Page<EnrollmentRow>>(\"admin/enrollments\", {\n courseId,\n cursor,\n limit: 100,\n });\n rows.push(...page.items);\n if (rows.length > 10_000)\n throw new Error(\"Choose a course to export fewer than 10,000 enrollments.\");\n cursor = page.hasMore ? page.cursor : undefined;\n } while (cursor);\n download(\n \"lms-enrollments.csv\",\n \"\\uFEFF\" + [enrollmentCsvHeader, ...enrollmentCsvLines(rows)].join(\"\\r\\n\"),\n \"text/csv;charset=utf-8\",\n );\n }, \"Report exported.\");\n return (\n <PageFrame\n title=\"Learning reports\"\n description=\"Enrollment and completion counts cover all records in the selected scope.\"\n >\n <Notice error={report.error || action.error} message={action.message} />\n <CoursePicker value={courseId} allowAll onChange={setCourseId} />\n <Metrics report={report.data} />\n <Panel title=\"Enrollment status\">\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Status</th>\n <th>Enrollments</th>\n </tr>\n </thead>\n <tbody>\n {[\"pending\", \"active\", \"completed\", \"rejected\", \"suspended\", \"cancelled\"].map(\n (status) => (\n <tr key={status}>\n <td>{status}</td>\n <td>\n {report.data\n ? (report.data as unknown as Record<string, number>)[status]\n : \"—\"}\n </td>\n </tr>\n ),\n )}\n </tbody>\n </table>\n </div>\n </Panel>\n <Button busy={action.busy} onClick={exportCsv}>\n Export enrollments as CSV\n </Button>\n <Panel title=\"Access sources\">\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Initial grant source</th>\n <th>Enrollments</th>\n </tr>\n </thead>\n <tbody>\n {[\"free\", \"manual\", \"cohort\", \"purchase\"].map((source) => (\n <tr key={source}>\n <td>{source}</td>\n <td>{report.data?.accessSources[source] ?? \"—\"}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <p>\n An enrollment can have several access grants. The source records its first approved\n acquisition; each learner's current access is shown in the CSV export.\n </p>\n </Panel>\n <Panel title=\"Access decisions\">\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Decision</th>\n <th>Enrollments</th>\n </tr>\n </thead>\n <tbody>\n {[\"pending\", \"granted\", \"suspended\", \"revoked\"].map((decision) => (\n <tr key={decision}>\n <td>{decision}</td>\n <td>{report.data?.accessDecisions[decision] ?? \"—\"}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <p>\n Access decisions are separate from date windows and cohort membership. Use the enrollment\n export to review current access.\n </p>\n </Panel>\n </PageFrame>\n );\n}\n\nexport function NotificationsPage() {\n const [cursor, setCursor] = useState<string>();\n const [status, setStatus] = useState(\"failed\");\n const list = useLoad<Page<Notification>>(\"admin/notifications\", { cursor, status });\n const action = useAction();\n return (\n <PageFrame\n title=\"Learning notifications\"\n description=\"Review delivery status and retry failed emails.\"\n >\n <Notice error={list.error || action.error} message={action.message} />\n <div className=\"lms-actions\">\n <Field label=\"Email status\">\n <select\n value={status}\n onChange={(event) => {\n setStatus(event.target.value);\n setCursor(undefined);\n }}\n >\n <option value=\"\">All notifications</option>\n {[\"failed\", \"pending\", \"sending\", \"sent\", \"disabled\"].map((value) => (\n <option key={value} value={value}>\n {value}\n </option>\n ))}\n </select>\n </Field>\n <Button onClick={list.reload} busy={list.loading}>\n Refresh\n </Button>\n </div>\n <Panel>\n <p>\n Retries run during scheduled maintenance, with up to three attempts per email. Review\n delivery before retrying: an interrupted confirmation can mean the email was already sent.\n </p>\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Created</th>\n <th>Learner</th>\n <th>Notification</th>\n <th>Email</th>\n <th>Attempts</th>\n <th>Action</th>\n </tr>\n </thead>\n <tbody>\n {list.data?.items.map((item) => (\n <tr key={item.id}>\n <td>{new Date(item.createdAt).toLocaleString()}</td>\n <td>{item.email}</td>\n <td>\n <strong>{item.title}</strong>\n <p>{item.message}</p>\n </td>\n <td>{item.emailStatus}</td>\n <td>{item.emailAttempts} / 3</td>\n <td>\n {item.emailStatus === \"failed\" && item.emailAttempts < 3 && (\n <Button\n busy={action.busy}\n onClick={() =>\n void action.run(async () => {\n await api(\"admin/notification/retry\", { id: item.id }, \"POST\");\n list.reload();\n }, \"Email queued for retry.\")\n }\n >\n Retry email\n </Button>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {list.loading && <p role=\"status\">Loading notifications…</p>}\n {!list.loading && list.data?.items.length === 0 && (\n <p>No notifications match this status.</p>\n )}\n </Panel>\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nexport function AuditPage() {\n const [cursor, setCursor] = useState<string>();\n const list = useLoad<Page<AuditRecord>>(\"admin/audit\", { cursor });\n return (\n <PageFrame\n title=\"Learning audit history\"\n description=\"Inspect course changes, enrollment decisions, grades, moderation, and delivery retries.\"\n >\n <Notice error={list.error} />\n <Button onClick={list.reload} busy={list.loading}>\n Refresh\n </Button>\n <Panel>\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Time</th>\n <th>Action</th>\n <th>Actor</th>\n <th>Resource</th>\n <th>Details</th>\n </tr>\n </thead>\n <tbody>\n {list.data?.items.map((item) => (\n <tr key={item.id}>\n <td>{new Date(item.createdAt).toLocaleString()}</td>\n <td>{item.action}</td>\n <td>{item.actorId}</td>\n <td>{item.resourceId}</td>\n <td>{JSON.stringify(item.details)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {list.loading && <p role=\"status\">Loading audit history…</p>}\n {!list.loading && list.data?.items.length === 0 && (\n <p>No learning administration actions recorded yet.</p>\n )}\n </Panel>\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nexport function SettingsPage() {\n const load = useLoad<LmsSettings>(\"admin/settings\");\n const [settings, setSettings] = useState<LmsSettings>(settingsSchema.parse({}));\n const action = useAction();\n useEffect(() => {\n if (load.data) setSettings(load.data);\n }, [load.data]);\n const save = (event: FormEvent) => {\n event.preventDefault();\n void action.run(async () => {\n await api(\"admin/settings/save\", settings, \"POST\");\n load.reload();\n }, \"LMS settings saved.\");\n };\n return (\n <PageFrame\n title=\"LMS settings\"\n description=\"Configure your academy, certificates, moderation, and reminders.\"\n >\n <Notice error={load.error || action.error} message={action.message} />\n <Panel>\n <form onSubmit={save}>\n <Field label=\"Academy title\">\n <input\n value={settings.academyTitle}\n onChange={(event) => setSettings({ ...settings, academyTitle: event.target.value })}\n />\n </Field>\n <Field label=\"Academy introduction\">\n <textarea\n rows={3}\n value={settings.academyDescription}\n onChange={(event) =>\n setSettings({ ...settings, academyDescription: event.target.value })\n }\n />\n </Field>\n <Field label=\"Certificate issuer\">\n <input\n value={settings.issuerName}\n onChange={(event) => setSettings({ ...settings, issuerName: event.target.value })}\n />\n </Field>\n <Field\n label=\"Remind inactive learners after days\"\n help=\"0 disables reminders. Scheduled maintenance must be enabled in the host.\"\n >\n <input\n type=\"number\"\n min={0}\n max={90}\n value={settings.reminderDays}\n onChange={(event) =>\n setSettings({ ...settings, reminderDays: Number(event.target.value) })\n }\n />\n </Field>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={settings.moderateDiscussions}\n onChange={(event) =>\n setSettings({ ...settings, moderateDiscussions: event.target.checked })\n }\n />\n Review discussions before publishing\n </label>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={settings.moderateReviews}\n onChange={(event) =>\n setSettings({ ...settings, moderateReviews: event.target.checked })\n }\n />\n Review course reviews before publishing\n </label>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={settings.emailNotifications}\n onChange={(event) =>\n setSettings({ ...settings, emailNotifications: event.target.checked })\n }\n />\n Send notifications through the site's EmDash email transport\n </label>\n <Button type=\"submit\" busy={action.busy}>\n Save settings\n </Button>\n </form>\n </Panel>\n </PageFrame>\n );\n}\n\nexport function LearningWidget() {\n const report = useLoad<Report>(\"admin/report\");\n return (\n <div className=\"ag-lms-admin\">\n <style>{css}</style>\n <Notice error={report.error} />\n <p>\n <strong>{report.data?.active ?? \"—\"}</strong> active ·{\" \"}\n <strong>{report.data?.completedEver ?? \"—\"}</strong> completed ·{\" \"}\n <strong>{report.data?.pending ?? \"—\"}</strong> awaiting approval\n </p>\n <a href={ADMIN_BASE}>Open learning overview →</a>\n </div>\n );\n}\nexport const pages = {\n \"/\": OverviewPage,\n \"/courses\": CoursesPage,\n \"/learners\": LearnersPage,\n \"/assignments\": AssignmentsPage,\n \"/community\": CommunityPage,\n \"/cohorts\": CohortsPage,\n \"/reports\": ReportsPage,\n \"/notifications\": NotificationsPage,\n \"/audit\": AuditPage,\n \"/settings\": SettingsPage,\n};\nexport const widgets = { learning: LearningWidget };\n\nconst css = `\n.ag-lms-admin{color:var(--text-color-kumo-default,#1f2937);font-family:var(--font-emdash,ui-sans-serif,system-ui,sans-serif);padding:clamp(1rem,3vw,2.5rem);max-width:1400px;margin-inline:auto;line-height:1.55;direction:inherit}\n.ag-lms-admin *{box-sizing:border-box}.ag-lms-admin h1{font-size:clamp(1.6rem,3vw,2.15rem);margin:0}.ag-lms-admin h2{font-size:1.15rem;margin-block:0 .8rem}.ag-lms-admin h3{font-size:1rem}.ag-lms-admin p{margin-block:.5rem 1rem}.lms-page-header{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-block-end:1.5rem}.lms-page-header>div>p{max-width:65ch;color:var(--text-color-kumo-subtle,#64748b)}.lms-eyebrow{font-size:.7rem;letter-spacing:.15em;font-weight:700}.lms-tabs{display:flex;gap:.3rem;flex-wrap:wrap;margin-block:1rem 1.5rem}.lms-tabs a{padding:.4rem .7rem;border-radius:.4rem;text-decoration:none;color:inherit;background:var(--color-kumo-control,#f1f5f9)}.lms-panel{background:var(--color-kumo-base,#fff);border:1px solid var(--color-kumo-line,#d1d5db);border-radius:.65rem;padding:1.3rem;margin-block-end:1rem;min-width:0}.lms-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1rem}.lms-course-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(270px,1fr));gap:1rem}.lms-course-grid .lms-panel{display:flex;flex-direction:column;align-items:flex-start}.lms-course-grid .lms-actions{margin-block-start:auto}.lms-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:1rem}.lms-metrics strong{display:block;font-size:2rem;margin-block-start:.5rem}.lms-metrics span,.lms-muted{font-size:.85rem;color:var(--text-color-kumo-subtle,#64748b)}.lms-actions,.lms-toolbar{display:flex;gap:.5rem;align-items:center;flex-wrap:wrap;margin-block:.6rem 1rem}.lms-toolbar>.lms-field{min-width:160px;margin:0}.lms-button{display:inline-flex;justify-content:center;align-items:center;gap:.4rem;min-height:38px;padding:.5rem .8rem;border:1px solid var(--color-kumo-line,#cbd5e1);border-radius:.4rem;background:var(--color-kumo-control,#f8fafc);color:var(--text-color-kumo-default,#1e293b);font:inherit;font-size:.875rem;font-weight:600;text-decoration:none;cursor:pointer}.lms-button:hover{background:var(--color-kumo-interact,#e2e8f0)}.lms-button:disabled{opacity:.55;cursor:default}.lms-danger{color:var(--text-color-kumo-danger,#b91c1c)}.lms-field{display:grid;gap:.35rem;margin-block-end:1rem;min-width:0;font-size:.875rem;font-weight:600}.lms-field small{font-weight:400;color:var(--text-color-kumo-subtle,#64748b)}.ag-lms-admin input:not([type=checkbox]):not([type=radio]),.ag-lms-admin textarea,.ag-lms-admin select{width:100%;border:1px solid var(--color-kumo-line,#cbd5e1);border-radius:.35rem;background:var(--color-kumo-control,#fff);color:inherit;padding:.6rem;font:inherit;font-size:.875rem;font-weight:400}.ag-lms-admin input[type=checkbox],.ag-lms-admin input[type=radio]{width:1rem;height:1rem;accent-color:var(--color-kumo-brand,#2563eb)}.ag-lms-admin :focus-visible{outline:2px solid var(--color-kumo-focus,#2563eb);outline-offset:3px}.lms-check{display:flex;gap:.6rem;align-items:center;font-size:.9rem;margin-block:.7rem}.lms-notice{padding:.8rem 1rem;border:1px solid var(--color-kumo-line,#cbd5e1);border-radius:.4rem;background:var(--color-kumo-tint,#f1f5f9)}.lms-error{color:var(--text-color-kumo-danger,#b91c1c);border-color:currentColor}.lms-badge{font-size:.7rem;text-transform:uppercase;font-weight:700;border:1px solid var(--color-kumo-line,#cbd5e1);border-radius:1rem;padding:.2rem .6rem;margin-block-end:.6rem}.lms-studio{display:grid;grid-template-columns:330px minmax(0,1fr);gap:1.3rem;align-items:start}.lms-module{border-block-end:1px solid var(--color-kumo-line,#cbd5e1);padding-block:1rem}.lms-lesson-list{list-style:none;padding:0;margin:0}.lms-lesson-list li{display:flex;align-items:center;gap:.3rem}.lms-select-lesson{background:transparent;color:inherit;border:0;border-radius:.35rem;cursor:pointer;text-align:start;padding:.6rem;flex:1;font:inherit;font-size:.9rem}.lms-select-lesson[aria-current=true]{background:var(--color-kumo-control,#eff6ff);font-weight:600}.lms-select-lesson small{display:block;font-weight:400;opacity:.75}.lms-lesson-list .lms-actions{margin:0}.lms-option{display:flex;align-items:center;gap:.5rem;margin-block:.5rem}.lms-question{border-block-start:1px solid var(--color-kumo-line,#cbd5e1);padding-block:1rem}.lms-question fieldset{border:1px solid var(--color-kumo-line,#cbd5e1);border-radius:.4rem;margin-block:1rem;padding:1rem}.lms-resource{border-block-end:1px solid var(--color-kumo-line,#cbd5e1);padding-block:1rem}.lms-file{position:absolute;width:1px!important;height:1px;opacity:0}.lms-table-wrap{overflow:auto}.lms-table{width:100%;border-collapse:collapse;font-size:.875rem}.lms-table th,.lms-table td{padding:.7rem;text-align:start;border-block-end:1px solid var(--color-kumo-line,#e5e7eb);vertical-align:top}.lms-table th{font-weight:600}.lms-table small{display:block;color:var(--text-color-kumo-subtle,#64748b)}.lms-table .lms-actions{margin:0}.lms-body{white-space:pre-wrap;overflow-wrap:anywhere}.ag-lms-admin details{padding:.7rem;border:1px solid var(--color-kumo-line,#d1d5db);border-radius:.4rem;margin-block:1rem}.ag-lms-admin summary{cursor:pointer;font-weight:600}.lms-notice:empty{display:none}@media(max-width:900px){.lms-studio{grid-template-columns:1fr}.lms-page-header{align-items:start;flex-direction:column}}@media(max-width:600px){.lms-grid{grid-template-columns:1fr}.lms-toolbar{align-items:stretch}.lms-toolbar>.lms-field{width:100%}.lms-panel{padding:1rem}}`;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin.js","names":[],"sources":["../src/admin.tsx"],"sourcesContent":["import { useCallback, useEffect, useState, type FormEvent, type ReactNode } from \"react\";\nimport { apiFetch } from \"emdash/plugin-utils\";\nimport { API_BASE, PLUGIN_ID } from \"./constants.js\";\nimport { enrollmentCsvHeader, enrollmentCsvLines } from \"./csv.js\";\nimport {\n courseDataSchema,\n lessonSchema,\n moduleSchema,\n questionSchema,\n settingsSchema,\n quizSchema,\n assignmentSchema,\n} from \"./schemas.js\";\nimport type {\n Course,\n RevisionSummary,\n MigrationState,\n CourseData,\n Lesson,\n QuizQuestion,\n Page,\n LmsSettings,\n Cohort,\n PublicEnrollment,\n AssignmentSubmission,\n Discussion,\n Review,\n CohortMembership,\n CourseCard,\n Notification,\n AuditRecord,\n LearningPath,\n LmsHealth,\n} from \"./types.js\";\n\nconst ADMIN_BASE = `/_emdash/admin/plugins/${PLUGIN_ID}`;\ntype UserChoice = { id: string; email: string; name: string | null };\ntype EnrollmentRow = PublicEnrollment & {\n learnerEmail: string;\n courseTitle: string;\n progressSummary: { percent: number } | null;\n lessonTitles: Record<string, string>;\n};\ntype Report = {\n total: number;\n courseCount: number;\n pending: number;\n active: number;\n completed: number;\n completedEver: number;\n suspended: number;\n cancelled: number;\n rejected: number;\n accessSources: Record<string, number>;\n accessDecisions: Record<string, number>;\n completionRate: number;\n};\n\nasync function api<T>(\n route: string,\n input: Record<string, unknown> = {},\n method = \"GET\",\n signal?: AbortSignal,\n): Promise<T> {\n let url = `${API_BASE}/${route}`;\n if (method === \"GET\") {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(input))\n if (value !== undefined && value !== \"\" && value !== null) params.set(key, String(value));\n url += `?${params}`;\n }\n const response = await apiFetch(url, {\n method,\n signal,\n credentials: \"same-origin\",\n ...(method !== \"GET\"\n ? { headers: { \"Content-Type\": \"application/json\" }, body: JSON.stringify(input) }\n : {}),\n });\n const result = (await response.json()) as {\n success: boolean;\n data?: T;\n error?: { message?: string };\n };\n if (!response.ok || !result.success)\n throw new Error(result.error?.message ?? \"The request could not be completed.\");\n return result.data as T;\n}\n\nfunction useLoad<T>(route: string, input: Record<string, unknown> = {}, enabled = true) {\n const key = JSON.stringify(input);\n const [generation, setGeneration] = useState(0);\n const [state, setState] = useState<{ data?: T; loading: boolean; error?: string }>({\n loading: enabled,\n });\n useEffect(() => {\n if (!enabled) {\n setState({ loading: false });\n return;\n }\n const controller = new AbortController();\n setState((old) => ({ ...old, loading: true, error: undefined }));\n void api<T>(route, JSON.parse(key), \"GET\", controller.signal)\n .then((data) => {\n if (!controller.signal.aborted) setState({ loading: false, data });\n })\n .catch((error: Error) => {\n if (!controller.signal.aborted) setState({ loading: false, error: error.message });\n });\n return () => controller.abort();\n }, [route, key, enabled, generation]);\n return { ...state, reload: () => setGeneration((value) => value + 1) };\n}\nfunction useAction() {\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState(\"\");\n const [message, setMessage] = useState(\"\");\n const run = async (action: () => Promise<void>, success = \"Saved.\") => {\n if (busy) return;\n setBusy(true);\n setError(\"\");\n setMessage(\"\");\n try {\n await action();\n setMessage(success);\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : \"The request failed.\");\n } finally {\n setBusy(false);\n }\n };\n return { busy, error, message, run };\n}\nfunction useChoices<T extends { id: string }>(route: string) {\n const [cursor, setCursor] = useState<string>();\n const [items, setItems] = useState<T[]>([]);\n const list = useLoad<Page<T>>(route, { cursor, limit: 100 });\n useEffect(() => {\n if (list.data)\n setItems((old) => [\n ...new Map([...old, ...list.data!.items].map((item) => [item.id, item])).values(),\n ]);\n }, [list.data]);\n return { ...list, items, more: () => setCursor(list.data?.cursor) };\n}\n\nfunction ChoicesField({\n label,\n value,\n choices,\n onChange,\n}: {\n label: string;\n value: string[];\n choices: { id: string; label: string }[];\n onChange: (ids: string[]) => void;\n}) {\n const all = [\n ...choices,\n ...value\n .filter((id) => !choices.some((choice) => choice.id === id))\n .map((id) => ({ id, label: `Saved selection · ${id.slice(0, 8)}` })),\n ];\n return (\n <fieldset className=\"lms-choices\">\n <legend>{label}</legend>\n {all.map((choice) => (\n <label className=\"lms-check\" key={choice.id}>\n <input\n type=\"checkbox\"\n checked={value.includes(choice.id)}\n onChange={(event) =>\n onChange(\n event.target.checked\n ? [...value, choice.id]\n : value.filter((id) => id !== choice.id),\n )\n }\n />\n {choice.label}\n </label>\n ))}\n {!all.length && <p>No choices loaded yet.</p>}\n </fieldset>\n );\n}\n\nfunction Notice({ error, message }: { error?: string; message?: string }) {\n return (\n <>\n {error && (\n <p role=\"alert\" className=\"lms-notice lms-error\">\n {error}\n </p>\n )}\n {message && (\n <p role=\"status\" className=\"lms-notice\">\n {message}\n </p>\n )}\n </>\n );\n}\nfunction Field({ label, children, help }: { label: string; children: ReactNode; help?: string }) {\n return (\n <label className=\"lms-field\">\n <span>{label}</span>\n {children}\n {help && <small>{help}</small>}\n </label>\n );\n}\nfunction Button({\n children,\n busy,\n danger,\n ...props\n}: React.ButtonHTMLAttributes<HTMLButtonElement> & { busy?: boolean; danger?: boolean }) {\n return (\n <button\n type=\"button\"\n {...props}\n className={`lms-button${danger ? \" lms-danger\" : \"\"}`}\n disabled={props.disabled || busy}\n >\n {busy ? \"Working…\" : children}\n </button>\n );\n}\nfunction Panel({ title, children }: { title?: string; children: ReactNode }) {\n return (\n <section className=\"lms-panel\">\n {title && <h2>{title}</h2>}\n {children}\n </section>\n );\n}\nfunction Pager({\n page,\n next,\n reset,\n}: {\n page?: { hasMore: boolean; cursor?: string };\n next: (cursor: string) => void;\n reset: () => void;\n}) {\n return (\n <div className=\"lms-actions\">\n <Button onClick={reset}>First page</Button>\n {page?.hasMore && page.cursor && (\n <Button onClick={() => next(page.cursor!)}>Next page</Button>\n )}\n </div>\n );\n}\nfunction PageFrame({\n title,\n description,\n children,\n}: {\n title: string;\n description?: string;\n children: ReactNode;\n}) {\n const academy = useLoad<{ basePath: string }>(\"academy\");\n return (\n <main className=\"ag-lms-admin\">\n <style>{css}</style>\n <header className=\"lms-page-header\">\n <div>\n <p className=\"lms-eyebrow\">ANANTA GNANAM · LEARNING</p>\n <h1>{title}</h1>\n {description && <p>{description}</p>}\n </div>\n <a\n href={academy.data?.basePath ?? \"/academy\"}\n className=\"lms-button\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Open academy ↗\n </a>\n </header>\n <nav className=\"lms-tabs\" aria-label=\"Learning administration\">\n {[\n [\"/\", \"Overview\"],\n [\"/courses\", \"Courses\"],\n [\"/learners\", \"Enrollments\"],\n [\"/assignments\", \"Assignments\"],\n [\"/community\", \"Community\"],\n [\"/cohorts\", \"Cohorts\"],\n [\"/paths\", \"Learning paths\"],\n [\"/reports\", \"Reports\"],\n [\"/notifications\", \"Notifications\"],\n [\"/audit\", \"Audit history\"],\n [\"/settings\", \"Settings\"],\n ].map(([path, label]) => (\n <a key={path} href={`${ADMIN_BASE}${path === \"/\" ? \"\" : path}`}>\n {label}\n </a>\n ))}\n </nav>\n {children}\n </main>\n );\n}\nfunction Metrics({ report }: { report?: Report }) {\n return (\n <div className=\"lms-metrics\">\n {[\n [\"Courses\", report?.courseCount],\n [\"Active enrollments\", report?.active],\n [\"Course completions\", report?.completedEver],\n [\"Awaiting approval\", report?.pending],\n [\"Completion rate\", report ? `${report.completionRate}%` : undefined],\n ].map(([label, value]) => (\n <div className=\"lms-panel\" key={label}>\n <span>{label}</span>\n <strong>{value ?? \"—\"}</strong>\n </div>\n ))}\n </div>\n );\n}\nfunction CoursePicker({\n value,\n onChange,\n allowAll = false,\n}: {\n value: string;\n onChange: (id: string) => void;\n allowAll?: boolean;\n}) {\n const [cursor, setCursor] = useState<string>();\n const [choices, setChoices] = useState<Course[]>([]);\n const list = useLoad<Page<Course>>(\"admin/courses\", { limit: 100, cursor });\n useEffect(() => {\n if (list.data)\n setChoices((old) => [\n ...new Map([...old, ...list.data!.items].map((course) => [course.id, course])).values(),\n ]);\n }, [list.data]);\n return (\n <div>\n <Field label=\"Course\">\n <select value={value} onChange={(event) => onChange(event.target.value)}>\n <option value=\"\">{allowAll ? \"All courses\" : \"Choose a course\"}</option>\n {choices.map((course) => (\n <option key={course.id} value={course.id}>\n {course.title} · {course.status}\n </option>\n ))}\n </select>\n </Field>\n {list.data?.hasMore && (\n <Button onClick={() => setCursor(list.data?.cursor)}>Load more courses</Button>\n )}\n <Notice error={list.error} />\n </div>\n );\n}\n\nexport function OverviewPage() {\n const report = useLoad<Report>(\"admin/report\");\n return (\n <PageFrame\n title=\"Learning overview\"\n description=\"Create learning paths, support your learners, and see their progress.\"\n >\n <Notice error={report.error} />\n <Metrics report={report.data} />\n <div className=\"lms-grid\">\n <Panel title=\"Course studio\">\n <p>Build modules with reading, video, audio, quizzes, assignments, and live sessions.</p>\n <a className=\"lms-button\" href={`${ADMIN_BASE}/courses`}>\n Manage courses\n </a>\n </Panel>\n <Panel title=\"Support learners\">\n <p>Review enrollment requests and give feedback on submitted work.</p>\n <div className=\"lms-actions\">\n <a className=\"lms-button\" href={`${ADMIN_BASE}/learners`}>\n Enrollments\n </a>\n <a className=\"lms-button\" href={`${ADMIN_BASE}/assignments`}>\n Grade assignments\n </a>\n </div>\n </Panel>\n </div>\n </PageFrame>\n );\n}\n\nexport function CoursesPage() {\n const [cursor, setCursor] = useState<string>();\n const [status, setStatus] = useState(\"\");\n const [edit, setEdit] = useState<{\n course: CourseData & { id?: string };\n revision: string | null;\n }>();\n const list = useLoad<Page<Course>>(\"admin/courses\", { cursor, status });\n const action = useAction();\n const open = (id: string) =>\n void action.run(async () => {\n const result = await api<{ course: Course; revision: string }>(\"admin/course\", { id });\n setEdit({ course: result.course, revision: result.revision });\n }, \"\");\n const importFile = async (file: File) => {\n if (file.size > 950_000) throw new Error(\"This course file is too large.\");\n const bundle = JSON.parse(await file.text()) as {\n format?: string;\n version?: number;\n course?: CourseData;\n };\n if (bundle.format !== \"anantagnanam-lms-course\" || bundle.version !== 1 || !bundle.course)\n throw new Error(\"Choose an Ananta Gnanam course export.\");\n setEdit({\n course: courseDataSchema.parse({ ...bundle.course, status: \"draft\" }),\n revision: null,\n });\n };\n if (edit)\n return (\n <CourseEditor\n initial={edit.course}\n initialRevision={edit.revision}\n onClose={() => {\n setEdit(undefined);\n list.reload();\n }}\n />\n );\n return (\n <PageFrame title=\"Courses\" description=\"Author, publish, and update your courses.\">\n <Notice error={list.error || action.error} message={action.message} />\n <div className=\"lms-toolbar\">\n <Button\n onClick={() =>\n setEdit({\n course: courseDataSchema.parse({ title: \"New course\", slug: \"new-course\" }),\n revision: null,\n })\n }\n >\n Create course\n </Button>\n <label className=\"lms-button\">\n Import course\n <input\n className=\"lms-file\"\n type=\"file\"\n accept=\"application/json,.json\"\n onChange={(event) => {\n const file = event.target.files?.[0];\n if (file) void action.run(() => importFile(file), \"\");\n event.target.value = \"\";\n }}\n />\n </label>\n <Field label=\"Status\">\n <select\n value={status}\n onChange={(event) => {\n setStatus(event.target.value);\n setCursor(undefined);\n }}\n >\n <option value=\"\">All statuses</option>\n {[\"draft\", \"published\", \"archived\"].map((value) => (\n <option key={value}>{value}</option>\n ))}\n </select>\n </Field>\n </div>\n {list.loading && <p role=\"status\">Loading courses…</p>}\n <div className=\"lms-course-grid\">\n {list.data?.items.map((course) => (\n <Panel key={course.id}>\n <span className=\"lms-badge\">{course.status}</span>\n <h2>{course.title}</h2>\n <p>{course.summary || \"Add a summary to introduce this course.\"}</p>\n <p className=\"lms-muted\">\n {course.modules.length} modules ·{\" \"}\n {course.modules.reduce((sum, module) => sum + module.lessons.length, 0)} lessons\n </p>\n <div className=\"lms-actions\">\n <Button busy={action.busy} onClick={() => open(course.id)}>\n Edit course\n </Button>\n <Button\n onClick={() =>\n void action.run(\n async () =>\n download(\n `${course.slug}.json`,\n JSON.stringify(\n await api(\"admin/course/export\", { id: course.id }),\n null,\n 2,\n ),\n \"application/json\",\n ),\n \"Course exported.\",\n )\n }\n >\n Export\n </Button>\n </div>\n </Panel>\n ))}\n </div>\n {list.data && !list.data.items.length && (\n <Panel>\n <p>No courses yet. Create your first course above.</p>\n </Panel>\n )}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nfunction CourseHistory({\n courseId,\n disabled,\n restore,\n}: {\n courseId: string;\n disabled: boolean;\n restore: (id: string) => void;\n}) {\n const [cursor, setCursor] = useState<string>();\n const load = useLoad<Page<RevisionSummary>>(\"admin/course/history\", { id: courseId, cursor });\n return (\n <details className=\"lms-panel\">\n <summary>Saved revision history</summary>\n <Notice error={load.error} />\n <p>\n Restore a revision into a draft, then review and publish it. Save current edits before\n restoring.\n </p>\n {load.data?.items.map((item) => (\n <div className=\"lms-toolbar\" key={item.id}>\n <span>\n {new Date(item.createdAt).toLocaleString()} · {item.kind} · {item.title}\n </span>\n <Button disabled={disabled || load.loading} onClick={() => restore(item.id)}>\n Restore as draft\n </Button>\n </div>\n ))}\n {!load.data?.items.length && (\n <p>No saved history yet. Legacy courses gain history on their next save or migration.</p>\n )}\n {cursor && <Button onClick={() => setCursor(undefined)}>Latest revisions</Button>}\n {load.data?.hasMore && (\n <Button disabled={load.loading} onClick={() => setCursor(load.data?.cursor)}>\n Older revisions\n </Button>\n )}\n </details>\n );\n}\n\nfunction CourseEditor({\n initial,\n initialRevision,\n onClose,\n}: {\n initial: CourseData & Partial<Course>;\n initialRevision: string | null;\n onClose: () => void;\n}) {\n const [course, setCourse] = useState(initial);\n const academy = useLoad<{ basePath: string }>(\"academy\");\n const [revision, setRevision] = useState(initialRevision);\n const [saved, setSaved] = useState(JSON.stringify(initial));\n const [selected, setSelected] = useState<string | null>(\n initial.modules[0]?.lessons[0]?.id ?? null,\n );\n const [tab, setTab] = useState<\"details\" | \"curriculum\" | \"access\">(\"details\");\n const action = useAction();\n const dirty = !course.id || JSON.stringify(course) !== saved;\n const prerequisiteChoices = useChoices<CourseCard>(\"catalog\");\n const instructorChoices = useChoices<UserChoice>(\"admin/instructors\");\n useEffect(() => {\n if (!dirty) return;\n const handler = (event: BeforeUnloadEvent) => {\n event.preventDefault();\n };\n window.addEventListener(\"beforeunload\", handler);\n return () => window.removeEventListener(\"beforeunload\", handler);\n }, [dirty]);\n const patch = (data: Partial<CourseData>) => setCourse((old) => ({ ...old, ...data }));\n const updateModule = (index: number, data: Partial<CourseData[\"modules\"][number]>) =>\n setCourse((old) => ({\n ...old,\n modules: old.modules.map((module, i) => (i === index ? { ...module, ...data } : module)),\n }));\n const updateLesson = (id: string, data: Partial<Lesson>) =>\n setCourse((old) => ({\n ...old,\n modules: old.modules.map((module) => ({\n ...module,\n lessons: module.lessons.map((lesson) =>\n lesson.id === id ? { ...lesson, ...data } : lesson,\n ),\n })),\n }));\n const selectedLesson = course.modules\n .flatMap((module) => module.lessons)\n .find((lesson) => lesson.id === selected);\n const acceptSaved = (result: { course: Course; revision: string }) => {\n setCourse(result.course);\n setRevision(result.revision);\n setSaved(JSON.stringify(result.course));\n };\n const publishOrArchive = (operation: \"publish\" | \"archive\") =>\n void action.run(\n async () => {\n acceptSaved(\n await api<{ course: Course; revision: string }>(\n `admin/course/${operation}`,\n { id: course.id, expectedRevision: revision },\n \"POST\",\n ),\n );\n },\n operation === \"publish\"\n ? \"Saved draft published. Existing learners keep their enrolled edition.\"\n : \"Course archived.\",\n );\n const save = () =>\n void action.run(async () => {\n const parsed = courseDataSchema.safeParse({ ...course, status: \"draft\" });\n if (!parsed.success)\n throw new Error(\n parsed.error.issues\n .slice(0, 5)\n .map((issue) => `${issue.path.join(\".\")}: ${issue.message}`)\n .join(\" \"),\n );\n const result = await api<{ course: Course; revision: string }>(\n \"admin/course/save\",\n { id: course.id, expectedRevision: revision, data: parsed.data },\n \"POST\",\n );\n acceptSaved(result);\n }, \"Draft saved. Publish it when it is ready for new learners.\");\n const reorderLesson = (moduleIndex: number, index: number, delta: number) => {\n const items = [...course.modules[moduleIndex]!.lessons];\n const to = index + delta;\n if (to < 0 || to >= items.length) return;\n [items[index], items[to]] = [items[to]!, items[index]!];\n updateModule(moduleIndex, { lessons: items });\n };\n return (\n <PageFrame\n title={course.title}\n description={dirty ? \"You have unsaved changes.\" : \"All changes saved.\"}\n >\n <Notice error={action.error} message={action.message} />\n <div className=\"lms-toolbar\">\n <Button\n onClick={() => {\n if (!dirty || window.confirm(\"Discard unsaved changes?\")) onClose();\n }}\n >\n Back to courses\n </Button>\n <Button busy={action.busy} onClick={() => save()}>\n Save draft\n </Button>\n {course.id && (\n <Button\n busy={action.busy}\n disabled={dirty}\n onClick={() =>\n void action.run(async () => {\n const exported = await api<{ format: string; version: number; course: CourseData }>(\n \"admin/course/export\",\n { id: course.id },\n );\n const result = await api<{ course: Course; revision: string }>(\n \"admin/course/import\",\n {\n ...exported,\n course: {\n ...exported.course,\n title: `Copy of ${course.title}`.slice(0, 200),\n slug: `${course.slug.slice(0, 65)}-copy-${crypto.randomUUID().slice(0, 8)}`,\n },\n },\n \"POST\",\n );\n acceptSaved(result);\n }, \"Course duplicated as a new draft. Review its dates and access settings before publishing.\")\n }\n >\n Duplicate as draft\n </Button>\n )}\n <Button busy={action.busy} disabled={dirty} onClick={() => publishOrArchive(\"publish\")}>\n Publish saved draft\n </Button>\n {course.status === \"published\" && (\n <Button busy={action.busy} disabled={dirty} onClick={() => publishOrArchive(\"archive\")}>\n Archive\n </Button>\n )}\n {course.id && course.status === \"draft\" && (\n <Button\n danger\n busy={action.busy}\n onClick={() => {\n if (window.confirm(`Delete the draft “${course.title}”?`))\n void action.run(async () => {\n await api(\n \"admin/course/delete\",\n { id: course.id, expectedRevision: revision },\n \"POST\",\n );\n onClose();\n }, \"\");\n }}\n >\n Delete draft\n </Button>\n )}\n </div>\n <p role=\"status\">\n Course visibility: {course.status}.\n {dirty\n ? \" Save changes before publishing.\"\n : course.publishedEditionId && course.draftRevisionId !== course.publishedDraftRevisionId\n ? \" Saved draft changes are awaiting publication.\"\n : \"\"}\n {course.publishedEditionId\n ? \" Publishing creates a new edition for new enrollments; existing learners keep their course material and progress.\"\n : \"\"}\n </p>\n {course.id && (\n <CourseHistory\n key={revision}\n courseId={course.id}\n disabled={dirty || action.busy}\n restore={(revisionId) =>\n void action.run(async () => {\n const result = await api<{ course: Course; revision: string }>(\n \"admin/course/restore\",\n { id: course.id, expectedRevision: revision, revisionId },\n \"POST\",\n );\n acceptSaved(result);\n setSelected(result.course.modules[0]?.lessons[0]?.id ?? null);\n }, \"Revision restored into a saved draft. Review it before publishing.\")\n }\n />\n )}\n <div className=\"lms-tabs\" role=\"tablist\" aria-label=\"Course editor\">\n {([\"details\", \"curriculum\", \"access\"] as const).map((value) => (\n <Button\n key={value}\n role=\"tab\"\n aria-selected={tab === value}\n onClick={() => setTab(value)}\n >\n {value === \"access\"\n ? \"Enrollment & completion\"\n : value === \"details\"\n ? \"Course details\"\n : \"Curriculum\"}\n </Button>\n ))}\n </div>\n {tab === \"details\" && (\n <Panel>\n <div className=\"lms-grid\">\n <Field label=\"Course title\">\n <input\n value={course.title}\n maxLength={200}\n onChange={(event) => patch({ title: event.target.value })}\n />\n </Field>\n <Field label=\"Course URL\">\n <input\n value={course.slug}\n onChange={(event) => patch({ slug: event.target.value })}\n pattern=\"[a-z0-9]+(-[a-z0-9]+)*\"\n />\n </Field>\n <Field label=\"Category\">\n <input\n value={course.category}\n onChange={(event) => patch({ category: event.target.value })}\n />\n </Field>\n <Field label=\"Level\">\n <select\n value={course.level}\n onChange={(event) => patch({ level: event.target.value as CourseData[\"level\"] })}\n >\n {[\"all\", \"beginner\", \"intermediate\", \"advanced\"].map((level) => (\n <option key={level}>{level}</option>\n ))}\n </select>\n </Field>\n <Field label=\"Language\">\n <input\n value={course.language}\n onChange={(event) => patch({ language: event.target.value })}\n placeholder=\"en, ta, hi…\"\n />\n </Field>\n <Field label=\"Instructor name\">\n <input\n value={course.instructorName}\n onChange={(event) => patch({ instructorName: event.target.value })}\n />\n </Field>\n </div>\n <Field label=\"Summary\">\n <textarea\n rows={3}\n value={course.summary}\n onChange={(event) => patch({ summary: event.target.value })}\n maxLength={1000}\n />\n </Field>\n <Field label=\"Course description\">\n <textarea\n rows={7}\n value={course.description}\n onChange={(event) => patch({ description: event.target.value })}\n />\n </Field>\n <div className=\"lms-grid\">\n <Field label=\"Learning outcomes\" help=\"One outcome per line.\">\n <textarea\n rows={5}\n value={course.outcomes.join(\"\\n\")}\n onChange={(event) =>\n patch({ outcomes: event.target.value.split(\"\\n\").filter(Boolean) })\n }\n />\n </Field>\n <Field label=\"Requirements\" help=\"One requirement per line.\">\n <textarea\n rows={5}\n value={course.requirements.join(\"\\n\")}\n onChange={(event) =>\n patch({ requirements: event.target.value.split(\"\\n\").filter(Boolean) })\n }\n />\n </Field>\n <Field label=\"Tags\" help=\"Separate tags with commas.\">\n <input\n value={course.tags.join(\", \")}\n onChange={(event) =>\n patch({\n tags: event.target.value\n .split(\",\")\n .map((tag) => tag.trim())\n .filter(Boolean),\n })\n }\n />\n </Field>\n <Field label=\"Course image URL\">\n <input\n type=\"url\"\n value={course.featuredImage?.src ?? \"\"}\n onChange={(event) =>\n patch({\n featuredImage: event.target.value\n ? {\n id: course.featuredImage?.id ?? \"\",\n src: event.target.value,\n alt: course.featuredImage?.alt ?? \"\",\n }\n : null,\n })\n }\n />\n </Field>\n <Field label=\"Image description\">\n <input\n value={course.featuredImage?.alt ?? \"\"}\n onChange={(event) =>\n course.featuredImage &&\n patch({ featuredImage: { ...course.featuredImage, alt: event.target.value } })\n }\n />\n </Field>\n <div>\n <ChoicesField\n label=\"Additional instructors\"\n value={course.instructorIds}\n choices={instructorChoices.items.map((account) => ({\n id: account.id,\n label: account.name || account.email,\n }))}\n onChange={(instructorIds) => patch({ instructorIds })}\n />\n {instructorChoices.data?.hasMore && (\n <Button onClick={instructorChoices.more}>Load more instructors</Button>\n )}\n <Notice error={instructorChoices.error} />\n </div>\n </div>\n </Panel>\n )}\n {tab === \"access\" && (\n <Panel>\n <div className=\"lms-grid\">\n <Field label=\"Enrollment\">\n <select\n value={course.enrollmentMode}\n onChange={(event) =>\n patch({ enrollmentMode: event.target.value as CourseData[\"enrollmentMode\"] })\n }\n >\n <option value=\"open\">Free · open enrollment</option>\n <option value=\"approval\">Administrator approval</option>\n <option value=\"invite\">Invitation only</option>\n </select>\n </Field>\n <Field label=\"Access duration in days\" help=\"0 gives unlimited access.\">\n <input\n type=\"number\"\n min={0}\n max={3650}\n value={course.accessDays}\n onChange={(event) => patch({ accessDays: Number(event.target.value) })}\n />\n </Field>\n <Field label=\"Enrollment closes\">\n <input\n type=\"datetime-local\"\n value={localDate(course.enrollmentClosesAt)}\n onChange={(event) => patch({ enrollmentClosesAt: isoDate(event.target.value) })}\n />\n </Field>\n <div>\n <ChoicesField\n label=\"Prerequisite courses\"\n value={course.prerequisiteCourseIds}\n choices={prerequisiteChoices.items\n .filter((value) => value.id !== course.id)\n .map((value) => ({ id: value.id, label: value.title }))}\n onChange={(prerequisiteCourseIds) => patch({ prerequisiteCourseIds })}\n />\n {prerequisiteChoices.data?.hasMore && (\n <Button onClick={prerequisiteChoices.more}>Load more courses</Button>\n )}\n <Notice error={prerequisiteChoices.error} />\n </div>\n </div>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={course.sequential}\n onChange={(event) => patch({ sequential: event.target.checked })}\n />\n Require lessons in order\n </label>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={course.certificateEnabled}\n onChange={(event) => patch({ certificateEnabled: event.target.checked })}\n />\n Issue a certificate after all required lessons are passed\n </label>\n </Panel>\n )}\n {tab === \"curriculum\" && (\n <div className=\"lms-studio\">\n <aside className=\"lms-panel\">\n <h2>Modules & lessons</h2>\n {course.modules.map((module, moduleIndex) => (\n <section className=\"lms-module\" key={module.id}>\n <Field label={`Module ${moduleIndex + 1}`}>\n <input\n value={module.title}\n onChange={(event) => updateModule(moduleIndex, { title: event.target.value })}\n />\n </Field>\n <div className=\"lms-grid\">\n <Field label=\"Release after days\">\n <input\n type=\"number\"\n min={0}\n value={module.releaseDays}\n onChange={(event) =>\n updateModule(moduleIndex, { releaseDays: Number(event.target.value) })\n }\n />\n </Field>\n <Field label=\"Release date\">\n <input\n type=\"datetime-local\"\n value={localDate(module.unlockAt)}\n onChange={(event) =>\n updateModule(moduleIndex, { unlockAt: isoDate(event.target.value) })\n }\n />\n </Field>\n </div>\n <ol className=\"lms-lesson-list\">\n {module.lessons.map((lesson, lessonIndex) => (\n <li key={lesson.id}>\n <button\n className=\"lms-select-lesson\"\n aria-current={selected === lesson.id}\n onClick={() => setSelected(lesson.id)}\n >\n {lesson.title}\n <small>\n {lesson.kind}\n {lesson.required ? \" · required\" : \" · optional\"}\n </small>\n </button>\n <div className=\"lms-actions\">\n <Button\n aria-label={`Move ${lesson.title} up`}\n disabled={lessonIndex === 0}\n onClick={() => reorderLesson(moduleIndex, lessonIndex, -1)}\n >\n ↑\n </Button>\n <Button\n aria-label={`Move ${lesson.title} down`}\n disabled={lessonIndex === module.lessons.length - 1}\n onClick={() => reorderLesson(moduleIndex, lessonIndex, 1)}\n >\n ↓\n </Button>\n </div>\n </li>\n ))}\n </ol>\n <Button\n onClick={() => {\n const lesson = lessonSchema.parse({\n id: crypto.randomUUID(),\n title: \"New lesson\",\n });\n updateModule(moduleIndex, { lessons: [...module.lessons, lesson] });\n setSelected(lesson.id);\n }}\n >\n Add lesson\n </Button>\n {module.lessons.length === 0 && (\n <Button\n danger\n onClick={() =>\n patch({ modules: course.modules.filter((item) => item.id !== module.id) })\n }\n >\n Remove empty module\n </Button>\n )}\n <div className=\"lms-actions\">\n <Button\n disabled={moduleIndex === 0}\n aria-label={`Move module ${module.title} up`}\n onClick={() => {\n const next = [...course.modules];\n [next[moduleIndex], next[moduleIndex - 1]] = [\n next[moduleIndex - 1]!,\n next[moduleIndex]!,\n ];\n patch({ modules: next });\n }}\n >\n Move module up\n </Button>\n </div>\n </section>\n ))}\n <Button\n onClick={() =>\n patch({\n modules: [\n ...course.modules,\n moduleSchema.parse({\n id: crypto.randomUUID(),\n title: `Module ${course.modules.length + 1}`,\n }),\n ],\n })\n }\n >\n Add module\n </Button>\n </aside>\n <Panel title={selectedLesson?.title ?? \"Choose a lesson\"}>\n {selectedLesson && (\n <div className=\"lms-actions\">\n <Button\n onClick={() => {\n const copy = {\n ...structuredClone(selectedLesson),\n id: crypto.randomUUID(),\n title: `Copy of ${selectedLesson.title}`.slice(0, 200),\n };\n patch({\n modules: course.modules.map((module) => ({\n ...module,\n lessons: module.lessons.flatMap((lesson) =>\n lesson.id === selectedLesson.id ? [lesson, copy] : [lesson],\n ),\n })),\n });\n setSelected(copy.id);\n }}\n >\n Duplicate lesson\n </Button>\n <Field label=\"Move lesson to module\">\n <select\n value={\n course.modules.find((m) => m.lessons.some((l) => l.id === selectedLesson.id))\n ?.id\n }\n onChange={(event) => {\n const target = event.target.value;\n patch({\n modules: course.modules.map((module) => ({\n ...module,\n lessons:\n module.id === target\n ? [...module.lessons, selectedLesson]\n : module.lessons.filter((lesson) => lesson.id !== selectedLesson.id),\n })),\n });\n }}\n >\n {course.modules.map((module) => (\n <option key={module.id} value={module.id}>\n {module.title}\n </option>\n ))}\n </select>\n </Field>\n </div>\n )}\n {selectedLesson ? (\n <LessonEditor\n key={selectedLesson.id}\n lesson={selectedLesson}\n previewUrl={\n course.id &&\n academy.data &&\n JSON.parse(saved).modules.some((module: CourseData[\"modules\"][number]) =>\n module.lessons.some((lesson) => lesson.id === selectedLesson.id),\n )\n ? `${academy.data.basePath}/teach/courses/${encodeURIComponent(course.id)}/lessons/${encodeURIComponent(selectedLesson.id)}`\n : undefined\n }\n update={(data) => updateLesson(selectedLesson.id, data)}\n remove={() => {\n if (window.confirm(`Remove “${selectedLesson.title}” from the draft?`)) {\n patch({\n modules: course.modules.map((module) => ({\n ...module,\n lessons: module.lessons.filter((lesson) => lesson.id !== selectedLesson.id),\n })),\n });\n setSelected(null);\n }\n }}\n />\n ) : (\n <p>Add a module and a lesson to begin.</p>\n )}\n </Panel>\n </div>\n )}\n </PageFrame>\n );\n}\n\nfunction ContentPicker({\n value,\n onChange,\n}: {\n value: Lesson[\"contentSource\"];\n onChange: (value: Lesson[\"contentSource\"]) => void;\n}) {\n type CollectionChoice = {\n slug: string;\n label: string;\n fields: { slug: string; label: string; type: string }[];\n };\n type EntryChoice = { id: string; title: string };\n const schema = useLoad<CollectionChoice[]>(\"admin/content/collections\");\n const [collection, setCollection] = useState(value?.collection ?? \"\");\n const [cursor, setCursor] = useState<string>();\n const [entries, setEntries] = useState<EntryChoice[]>([]);\n const list = useLoad<Page<EntryChoice>>(\n \"admin/content/entries\",\n { collection, cursor, limit: 100 },\n !!collection,\n );\n useEffect(() => {\n if (list.data)\n setEntries((old) => [\n ...new Map([...old, ...list.data!.items].map((entry) => [entry.id, entry])).values(),\n ]);\n }, [list.data]);\n const fields = schema.data?.find((entry) => entry.slug === collection)?.fields ?? [];\n return (\n <details>\n <summary>Use published EmDash content</summary>\n <p>Choose a published entry and its text field to reuse formatted lesson content.</p>\n <Notice error={schema.error || list.error} />\n <div className=\"lms-grid\">\n <Field label=\"Collection\">\n <select\n value={collection}\n onChange={(event) => {\n setCollection(event.target.value);\n setCursor(undefined);\n setEntries([]);\n }}\n >\n <option value=\"\">Choose a collection</option>\n {schema.data?.map((entry) => (\n <option key={entry.slug} value={entry.slug}>\n {entry.label}\n </option>\n ))}\n </select>\n </Field>\n {collection && (\n <>\n <Field label=\"Published entry\">\n <select\n value={value?.collection === collection ? value.id : \"\"}\n onChange={(event) =>\n event.target.value &&\n onChange(\n event.target.value\n ? {\n collection,\n id: event.target.value,\n field:\n (value?.collection === collection ? value.field : undefined) ??\n fields.find((field) => field.type === \"portableText\")?.slug ??\n fields[0]?.slug ??\n \"content\",\n }\n : null,\n )\n }\n >\n <option value=\"\">Choose an entry</option>\n {value?.collection === collection &&\n !entries.some((entry) => entry.id === value.id) && (\n <option value={value.id}>Current linked entry</option>\n )}\n {entries.map((entry) => (\n <option key={entry.id} value={entry.id}>\n {entry.title}\n </option>\n ))}\n </select>\n </Field>\n <Field label=\"Content field\">\n <select\n value={value?.collection === collection ? value.field : \"\"}\n disabled={!value || value.collection !== collection}\n onChange={(event) => value && onChange({ ...value, field: event.target.value })}\n >\n <option value=\"\">Choose a field</option>\n {fields.map((field) => (\n <option key={field.slug} value={field.slug}>\n {field.label}\n </option>\n ))}\n </select>\n </Field>\n </>\n )}\n </div>\n {list.data?.hasMore && (\n <Button onClick={() => setCursor(list.data?.cursor)}>Load more entries</Button>\n )}\n </details>\n );\n}\n\nfunction LessonEditor({\n lesson,\n previewUrl,\n update,\n remove,\n}: {\n lesson: Lesson;\n previewUrl?: string;\n update: (data: Partial<Lesson>) => void;\n remove: () => void;\n}) {\n return (\n <>\n <div className=\"lms-grid\">\n <Field label=\"Lesson title\">\n <input value={lesson.title} onChange={(event) => update({ title: event.target.value })} />\n </Field>\n <Field label=\"Lesson type\">\n <select\n value={lesson.kind}\n onChange={(event) => {\n const kind = event.target.value as Lesson[\"kind\"];\n update({\n kind,\n preview: [\"quiz\", \"assignment\", \"live\"].includes(kind) ? false : lesson.preview,\n quiz:\n kind === \"quiz\"\n ? (lesson.quiz ?? quizSchema.parse({ questions: [defaultQuestion()] }))\n : null,\n assignment:\n kind === \"assignment\"\n ? (lesson.assignment ??\n assignmentSchema.parse({ instructions: \"Submit your work here.\" }))\n : null,\n });\n }}\n >\n {[\"text\", \"video\", \"audio\", \"quiz\", \"assignment\", \"live\"].map((kind) => (\n <option key={kind}>{kind}</option>\n ))}\n </select>\n </Field>\n <Field label=\"Estimated minutes\">\n <input\n type=\"number\"\n min={0}\n value={lesson.durationMinutes}\n onChange={(event) => update({ durationMinutes: Number(event.target.value) })}\n />\n </Field>\n <Field label=\"Minimum study seconds\">\n <input\n type=\"number\"\n min={0}\n value={lesson.minStudySeconds}\n onChange={(event) => update({ minStudySeconds: Number(event.target.value) })}\n />\n </Field>\n </div>\n <Field label=\"Summary\">\n <textarea\n rows={2}\n value={lesson.summary}\n onChange={(event) => update({ summary: event.target.value })}\n />\n </Field>\n <section className=\"lms-notice\">\n <strong>\n Content source:{\" \"}\n {lesson.contentSource\n ? \"Published CMS content\"\n : lesson.portableText.length\n ? \"Imported rich content\"\n : \"Inline text\"}\n </strong>\n {previewUrl ? (\n <p>\n <a href={previewUrl} target=\"_blank\" rel=\"noopener noreferrer\">\n Preview saved lesson ↗\n </a>{\" \"}\n · Save changes first to include them in this preview.\n </p>\n ) : (\n <p>Save this lesson to enable its preview.</p>\n )}\n {lesson.contentSource ? (\n <>\n <p>\n This lesson displays the published “{lesson.contentSource.field}” field from{\" \"}\n {lesson.contentSource.collection}. Local content is retained while linked.\n </p>\n <p>\n <a\n href={`/_emdash/admin/content/${encodeURIComponent(lesson.contentSource.collection)}/${encodeURIComponent(lesson.contentSource.id)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Edit linked entry in EmDash ↗\n </a>{\" \"}\n · Publish entry changes, then publish the saved course draft to create a new learner\n edition.\n </p>\n <Button\n onClick={() => {\n if (\n window.confirm(\n \"Unlink the CMS entry and use this lesson's retained local content? Save the course to apply.\",\n )\n )\n update({ contentSource: null });\n }}\n >\n Use retained local content\n </Button>\n </>\n ) : lesson.portableText.length > 0 ? (\n <>\n <p>\n Imported rich content is read-only here. Use the saved preview to inspect it, or link\n a published CMS entry below to edit rich content in EmDash.\n </p>\n <Button\n onClick={() => {\n if (\n window.confirm(\n \"Remove this lesson's imported rich content and use its retained plain text instead? This removes formatting when you save.\",\n )\n )\n update({ portableText: [] });\n }}\n >\n Replace rich content with inline text\n </Button>\n </>\n ) : (\n <p>Edit the inline text below, or select a published CMS entry.</p>\n )}\n </section>\n {!lesson.contentSource && lesson.portableText.length === 0 && (\n <Field label=\"Lesson text\">\n <textarea\n rows={12}\n value={lesson.body}\n onChange={(event) => update({ body: event.target.value })}\n />\n </Field>\n )}\n {[\"video\", \"audio\", \"live\"].includes(lesson.kind) && (\n <Field\n label={lesson.kind === \"live\" ? \"Meeting link\" : \"Media URL\"}\n help=\"Use a direct media file, YouTube link, or Vimeo link.\"\n >\n <input\n type=\"url\"\n value={lesson.mediaUrl ?? \"\"}\n onChange={(event) => update({ mediaUrl: event.target.value || null })}\n />\n </Field>\n )}\n {lesson.kind === \"live\" && (\n <Field label=\"Session starts\">\n <input\n type=\"datetime-local\"\n value={localDate(lesson.liveStartsAt)}\n onChange={(event) => update({ liveStartsAt: isoDate(event.target.value) })}\n />\n </Field>\n )}\n {[\"video\", \"audio\"].includes(lesson.kind) && (\n <section>\n <Field label=\"Transcript\" help=\"Readable text shown alongside native and embedded media.\">\n <textarea\n rows={6}\n maxLength={50_000}\n value={lesson.transcript ?? \"\"}\n onChange={(event) => update({ transcript: event.target.value })}\n />\n </Field>\n <h3>Caption tracks</h3>\n <p>\n WebVTT tracks apply to native media. Use same-origin files or configure CORS on both\n media and caption hosts. Embedded players manage their own captions.\n </p>\n {(lesson.captions ?? []).map((track, index) => (\n <div key={index}>\n <Field label={`Track ${index + 1} URL`}>\n <input\n value={track.src}\n onChange={(event) =>\n update({\n captions: lesson.captions.map((item, i) =>\n i === index ? { ...item, src: event.target.value } : item,\n ),\n })\n }\n />\n </Field>\n <Field label=\"Language code\">\n <input\n value={track.language}\n onChange={(event) =>\n update({\n captions: lesson.captions.map((item, i) =>\n i === index ? { ...item, language: event.target.value } : item,\n ),\n })\n }\n />\n </Field>\n <Field label=\"Caption label\">\n <input\n value={track.label}\n onChange={(event) =>\n update({\n captions: lesson.captions.map((item, i) =>\n i === index ? { ...item, label: event.target.value } : item,\n ),\n })\n }\n />\n </Field>\n <Button\n onClick={() => update({ captions: lesson.captions.filter((_, i) => i !== index) })}\n >\n Remove track\n </Button>\n </div>\n ))}\n <Button\n disabled={(lesson.captions?.length ?? 0) >= 20}\n onClick={() =>\n update({\n captions: [\n ...(lesson.captions ?? []),\n { src: \"\", language: \"en\", label: \"English\" },\n ],\n })\n }\n >\n Add captions\n </Button>\n </section>\n )}\n <div className=\"lms-actions\">\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={lesson.required}\n onChange={(event) => update({ required: event.target.checked })}\n />\n Required for completion\n </label>\n {![\"quiz\", \"assignment\", \"live\"].includes(lesson.kind) && (\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={lesson.preview}\n onChange={(event) => update({ preview: event.target.checked })}\n />\n Free preview\n </label>\n )}\n </div>\n <ContentPicker\n key={lesson.id}\n value={lesson.contentSource}\n onChange={(contentSource) => {\n if (\n contentSource &&\n window.confirm(\n \"Use this published CMS field as the lesson content? Local content will be retained. Save the course to apply.\",\n )\n )\n update({ contentSource });\n }}\n />\n {lesson.kind === \"quiz\" && lesson.quiz && (\n <QuizEditor quiz={lesson.quiz} update={(quiz) => update({ quiz })} />\n )}\n {lesson.kind === \"assignment\" && lesson.assignment && (\n <Panel title=\"Assignment\">\n <Field label=\"Instructions\">\n <textarea\n rows={6}\n value={lesson.assignment.instructions}\n onChange={(event) =>\n update({ assignment: { ...lesson.assignment!, instructions: event.target.value } })\n }\n />\n </Field>\n <div className=\"lms-grid\">\n <Field label=\"Maximum points\">\n <input\n type=\"number\"\n min={1}\n value={lesson.assignment.maxPoints}\n onChange={(event) =>\n update({\n assignment: { ...lesson.assignment!, maxPoints: Number(event.target.value) },\n })\n }\n />\n </Field>\n <Field label=\"Passing points\">\n <input\n type=\"number\"\n min={1}\n value={lesson.assignment.passingPoints}\n onChange={(event) =>\n update({\n assignment: {\n ...lesson.assignment!,\n passingPoints: Number(event.target.value),\n },\n })\n }\n />\n </Field>\n <Field label=\"Due date\">\n <input\n type=\"datetime-local\"\n value={localDate(lesson.assignment.dueAt)}\n onChange={(event) =>\n update({\n assignment: { ...lesson.assignment!, dueAt: isoDate(event.target.value) },\n })\n }\n />\n </Field>\n </div>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={lesson.assignment.allowResubmission}\n onChange={(event) =>\n update({\n assignment: { ...lesson.assignment!, allowResubmission: event.target.checked },\n })\n }\n />\n Allow another submission after a failing grade\n </label>\n </Panel>\n )}\n <Panel title=\"Lesson resources\">\n {lesson.resources.map((resource, index) => (\n <div className=\"lms-resource\" key={resource.id}>\n <Field label={`Resource ${index + 1}`}>\n <input\n value={resource.title}\n onChange={(event) =>\n update({\n resources: lesson.resources.map((item) =>\n item.id === resource.id ? { ...item, title: event.target.value } : item,\n ),\n })\n }\n />\n </Field>\n <Field label=\"URL\">\n <input\n value={resource.url}\n onChange={(event) =>\n update({\n resources: lesson.resources.map((item) =>\n item.id === resource.id ? { ...item, url: event.target.value } : item,\n ),\n })\n }\n />\n </Field>\n <Button\n danger\n onClick={() =>\n update({ resources: lesson.resources.filter((item) => item.id !== resource.id) })\n }\n >\n Remove resource\n </Button>\n </div>\n ))}\n <Button\n onClick={() =>\n update({\n resources: [\n ...lesson.resources,\n { id: crypto.randomUUID(), title: \"New resource\", url: \"/\", description: \"\" },\n ],\n })\n }\n >\n Add resource\n </Button>\n </Panel>\n <Button danger onClick={remove}>\n Remove lesson\n </Button>\n </>\n );\n}\n\nfunction defaultQuestion(): QuizQuestion {\n return questionSchema.parse({\n id: crypto.randomUUID(),\n type: \"single\",\n prompt: \"New question\",\n options: [\n { id: \"a\", text: \"First option\" },\n { id: \"b\", text: \"Second option\" },\n ],\n correctAnswers: [\"a\"],\n });\n}\nfunction QuizEditor({\n quiz,\n update,\n}: {\n quiz: NonNullable<Lesson[\"quiz\"]>;\n update: (quiz: NonNullable<Lesson[\"quiz\"]>) => void;\n}) {\n const patchQuestion = (id: string, data: Partial<QuizQuestion>) =>\n update({\n ...quiz,\n questions: quiz.questions.map((question) =>\n question.id === id ? { ...question, ...data } : question,\n ),\n });\n return (\n <Panel title=\"Quiz\">\n <div className=\"lms-grid\">\n <Field label=\"Passing percentage\">\n <input\n type=\"number\"\n min={1}\n max={100}\n value={quiz.passingPercent}\n onChange={(event) => update({ ...quiz, passingPercent: Number(event.target.value) })}\n />\n </Field>\n <Field label=\"Maximum attempts\">\n <input\n type=\"number\"\n min={1}\n max={20}\n value={quiz.maxAttempts}\n onChange={(event) => update({ ...quiz, maxAttempts: Number(event.target.value) })}\n />\n </Field>\n <Field label=\"Time limit in minutes\" help=\"0 gives an untimed quiz.\">\n <input\n type=\"number\"\n min={0}\n max={180}\n value={quiz.timeLimitMinutes}\n onChange={(event) => update({ ...quiz, timeLimitMinutes: Number(event.target.value) })}\n />\n </Field>\n <Field label=\"Show explanations\">\n <select\n value={quiz.showFeedback}\n onChange={(event) =>\n update({ ...quiz, showFeedback: event.target.value as typeof quiz.showFeedback })\n }\n >\n <option value=\"after_pass\">After passing</option>\n <option value=\"after_submit\">After each submission</option>\n <option value=\"never\">Never</option>\n </select>\n </Field>\n </div>\n <div className=\"lms-actions\">\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={quiz.randomizeQuestions}\n onChange={(event) => update({ ...quiz, randomizeQuestions: event.target.checked })}\n />\n Shuffle questions\n </label>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={quiz.randomizeOptions}\n onChange={(event) => update({ ...quiz, randomizeOptions: event.target.checked })}\n />\n Shuffle choices\n </label>\n </div>\n {quiz.questions.map((question, index) => (\n <section className=\"lms-question\" key={question.id}>\n <h3>Question {index + 1}</h3>\n <div className=\"lms-grid\">\n <Field label=\"Type\">\n <select\n value={question.type}\n onChange={(event) => {\n const type = event.target.value as QuizQuestion[\"type\"];\n const options =\n type === \"true_false\"\n ? [\n { id: \"true\", text: \"True\" },\n { id: \"false\", text: \"False\" },\n ]\n : type === \"short\"\n ? []\n : question.options.length\n ? question.options\n : [\n { id: \"a\", text: \"First option\" },\n { id: \"b\", text: \"Second option\" },\n ];\n patchQuestion(question.id, {\n type,\n options,\n correctAnswers: type === \"short\" ? [\"Accepted answer\"] : [options[0]!.id],\n });\n }}\n >\n {[\n [\"single\", \"Single choice\"],\n [\"multiple\", \"Multiple choices\"],\n [\"true_false\", \"True or false\"],\n [\"short\", \"Short answer\"],\n ].map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </select>\n </Field>\n <Field label=\"Points\">\n <input\n type=\"number\"\n min={1}\n max={100}\n value={question.points}\n onChange={(event) =>\n patchQuestion(question.id, { points: Number(event.target.value) })\n }\n />\n </Field>\n </div>\n <Field label=\"Question\">\n <textarea\n rows={3}\n value={question.prompt}\n onChange={(event) => patchQuestion(question.id, { prompt: event.target.value })}\n />\n </Field>\n {question.type === \"short\" ? (\n <Field\n label=\"Accepted answers\"\n help=\"One answer per line. Matching ignores case and extra spaces.\"\n >\n <textarea\n value={question.correctAnswers.join(\"\\n\")}\n onChange={(event) =>\n patchQuestion(question.id, {\n correctAnswers: event.target.value.split(\"\\n\").filter(Boolean),\n })\n }\n />\n </Field>\n ) : (\n <fieldset>\n <legend>Answer choices · select the correct answers</legend>\n {question.options.map((option) => (\n <div className=\"lms-option\" key={option.id}>\n <input\n aria-label={`Mark ${option.text} correct`}\n type={question.type === \"multiple\" ? \"checkbox\" : \"radio\"}\n name={`correct-${question.id}`}\n checked={question.correctAnswers.includes(option.id)}\n onChange={(event) =>\n patchQuestion(question.id, {\n correctAnswers:\n question.type === \"multiple\"\n ? event.target.checked\n ? [...question.correctAnswers, option.id]\n : question.correctAnswers.filter((id) => id !== option.id)\n : [option.id],\n })\n }\n />\n <input\n aria-label=\"Answer text\"\n value={option.text}\n onChange={(event) =>\n patchQuestion(question.id, {\n options: question.options.map((item) =>\n item.id === option.id ? { ...item, text: event.target.value } : item,\n ),\n })\n }\n />\n {question.type !== \"true_false\" && question.options.length > 2 && (\n <Button\n aria-label={`Remove answer ${option.text}`}\n onClick={() =>\n patchQuestion(question.id, {\n options: question.options.filter((item) => item.id !== option.id),\n correctAnswers: question.correctAnswers.filter((id) => id !== option.id),\n })\n }\n >\n ×\n </Button>\n )}\n </div>\n ))}\n {question.type !== \"true_false\" && question.options.length < 10 && (\n <Button\n onClick={() =>\n patchQuestion(question.id, {\n options: [\n ...question.options,\n { id: crypto.randomUUID(), text: \"New option\" },\n ],\n })\n }\n >\n Add answer choice\n </Button>\n )}\n </fieldset>\n )}\n <Field label=\"Explanation\">\n <textarea\n rows={2}\n value={question.explanation}\n onChange={(event) => patchQuestion(question.id, { explanation: event.target.value })}\n />\n </Field>\n <div className=\"lms-actions\">\n <Button\n disabled={index === 0}\n aria-label={`Move question ${index + 1} up`}\n onClick={() => {\n const next = [...quiz.questions];\n [next[index], next[index - 1]] = [next[index - 1]!, next[index]!];\n update({ ...quiz, questions: next });\n }}\n >\n Move up\n </Button>\n <Button\n danger\n disabled={quiz.questions.length < 2}\n onClick={() =>\n update({\n ...quiz,\n questions: quiz.questions.filter((item) => item.id !== question.id),\n })\n }\n >\n Remove question\n </Button>\n </div>\n </section>\n ))}\n {quiz.questions.length < 50 && (\n <Button\n onClick={() => update({ ...quiz, questions: [...quiz.questions, defaultQuestion()] })}\n >\n Add question\n </Button>\n )}\n </Panel>\n );\n}\n\nfunction localDate(value: string | null): string {\n if (!value) return \"\";\n const date = new Date(value);\n const offset = date.getTimezoneOffset() * 60_000;\n return new Date(date.getTime() - offset).toISOString().slice(0, 16);\n}\nfunction isoDate(value: string): string | null {\n return value ? new Date(value).toISOString() : null;\n}\nfunction download(name: string, body: string, type: string) {\n const url = URL.createObjectURL(new Blob([body], { type }));\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = name;\n anchor.click();\n setTimeout(() => URL.revokeObjectURL(url), 1000);\n}\n\nfunction EnrollmentAccessEditor({\n row,\n close,\n saved,\n}: {\n row: EnrollmentRow;\n close: () => void;\n saved: () => void;\n}) {\n const [status, setStatus] = useState(\n row.status === \"pending\" || row.status === \"completed\" ? \"active\" : row.status,\n );\n const [reason, setReason] = useState(row.decisionReason ?? \"\");\n const [startsAt, setStartsAt] = useState(row.accessStartsAt);\n const [expiresAt, setExpiresAt] = useState(row.accessExpiresAt);\n const action = useAction();\n return (\n <Panel title={`Manage ${row.learnerName}'s access`}>\n <p>{row.courseTitle}</p>\n <Notice error={action.error} />\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void action.run(async () => {\n await api(\n \"admin/enrollment/save\",\n {\n courseId: row.courseId,\n userId: row.userId,\n status,\n reason,\n accessStartsAt: startsAt,\n accessExpiresAt: expiresAt,\n },\n \"POST\",\n );\n saved();\n });\n }}\n >\n <div className=\"lms-grid\">\n <Field label=\"Enrollment decision\">\n <select\n value={status}\n onChange={(event) => setStatus(event.target.value as typeof status)}\n >\n {[\"active\", \"rejected\", \"suspended\", \"cancelled\"].map((value) => (\n <option key={value} value={value}>\n {value === \"active\" ? \"Approve / restore access\" : value}\n </option>\n ))}\n </select>\n </Field>\n <Field label=\"Access starts\">\n <input\n type=\"datetime-local\"\n value={localDate(startsAt)}\n onChange={(event) => setStartsAt(isoDate(event.target.value))}\n />\n </Field>\n <Field label=\"Access expires\">\n <input\n type=\"datetime-local\"\n value={localDate(expiresAt)}\n onChange={(event) => setExpiresAt(isoDate(event.target.value))}\n />\n </Field>\n <Field label=\"Decision note\">\n <textarea\n maxLength={1000}\n value={reason}\n onChange={(event) => setReason(event.target.value)}\n />\n </Field>\n </div>\n <p>\n These access dates apply to this learner's course enrollment. Leave blank for no\n additional date restriction.\n </p>\n <div className=\"lms-actions\">\n <Button type=\"submit\" busy={action.busy}>\n Save access\n </Button>\n <Button onClick={close}>Close</Button>\n </div>\n </form>\n </Panel>\n );\n}\n\nexport function LearnersPage() {\n const [courseId, setCourseId] = useState(\"\");\n const [status, setStatus] = useState(\"\");\n const [cursor, setCursor] = useState<string>();\n const [email, setEmail] = useState(\"\");\n const [managing, setManaging] = useState<EnrollmentRow>();\n const list = useLoad<Page<EnrollmentRow>>(\"admin/enrollments\", { courseId, status, cursor });\n const action = useAction();\n const update = (row: EnrollmentRow, next: string) =>\n void action.run(async () => {\n await api(\n \"admin/enrollment/save\",\n { courseId: row.courseId, userId: row.userId, status: next },\n \"POST\",\n );\n list.reload();\n }, \"Enrollment updated.\");\n const add = (event: FormEvent) => {\n event.preventDefault();\n void action.run(async () => {\n if (!courseId) throw new Error(\"Choose a course first.\");\n const target = await api<UserChoice>(\"admin/learner/find\", { courseId, email }, \"POST\");\n await api(\"admin/enrollment/save\", { courseId, userId: target.id, status: \"active\" }, \"POST\");\n setEmail(\"\");\n list.reload();\n }, \"Learner enrolled.\");\n };\n return (\n <PageFrame\n title=\"Enrollments\"\n description=\"Approve requests, enroll learners, and manage access.\"\n >\n <Notice error={list.error || action.error} message={action.message} />\n {managing && (\n <EnrollmentAccessEditor\n key={managing.id}\n row={managing}\n close={() => setManaging(undefined)}\n saved={() => {\n setManaging(undefined);\n list.reload();\n }}\n />\n )}\n <div className=\"lms-grid\">\n <CoursePicker\n value={courseId}\n allowAll\n onChange={(id) => {\n setCourseId(id);\n setCursor(undefined);\n }}\n />\n <Field label=\"Status\">\n <select\n value={status}\n onChange={(event) => {\n setStatus(event.target.value);\n setCursor(undefined);\n }}\n >\n <option value=\"\">All statuses</option>\n {[\"pending\", \"active\", \"completed\", \"rejected\", \"suspended\", \"cancelled\"].map(\n (value) => (\n <option key={value}>{value}</option>\n ),\n )}\n </select>\n </Field>\n </div>\n {courseId && (\n <Panel title=\"Enroll an existing account\">\n <form onSubmit={add} className=\"lms-toolbar\">\n <Field label=\"Learner email\">\n <input\n type=\"email\"\n required\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n />\n </Field>\n <Button type=\"submit\" busy={action.busy}>\n Enroll learner\n </Button>\n </form>\n </Panel>\n )}\n <Panel>\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Learner</th>\n <th>Course</th>\n <th>Progress</th>\n <th>Status</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n {list.data?.items.map((row) => (\n <tr key={row.id}>\n <td>\n {row.learnerName}\n <small>{row.learnerEmail}</small>\n </td>\n <td>{row.courseTitle}</td>\n <td>\n {row.progressSummary?.percent ?? 0}%\n <small>\n {row.completedAt\n ? new Date(row.completedAt).toLocaleDateString()\n : \"In progress\"}\n </small>\n </td>\n <td>\n {row.status}\n <small>Access: {row.effectiveAccess}</small>\n <small>Source: {row.accessSource}</small>\n </td>\n <td>\n <div className=\"lms-actions\">\n <Button onClick={() => setManaging(row)}>Manage access</Button>\n {row.status === \"pending\" && (\n <Button danger busy={action.busy} onClick={() => update(row, \"rejected\")}>\n Reject\n </Button>\n )}\n {[\"pending\", \"rejected\", \"suspended\", \"cancelled\"].includes(row.status) && (\n <Button busy={action.busy} onClick={() => update(row, \"active\")}>\n {row.status === \"pending\" ? \"Approve\" : \"Restore\"}\n </Button>\n )}\n {[\"active\", \"completed\"].includes(row.status) && (\n <Button busy={action.busy} onClick={() => update(row, \"suspended\")}>\n Suspend\n </Button>\n )}\n {row.status !== \"cancelled\" && (\n <Button\n danger\n busy={action.busy}\n onClick={() => {\n if (\n window.confirm(`Cancel ${row.learnerName}'s access to this course?`)\n )\n update(row, \"cancelled\");\n }}\n >\n Cancel\n </Button>\n )}\n {row.certificate && !row.certificate.revokedAt && (\n <Button\n danger\n busy={action.busy}\n onClick={() => {\n const reason = window.prompt(\"Reason for revoking this certificate:\");\n if (reason?.trim())\n void action.run(async () => {\n await api(\n \"admin/certificate/revoke\",\n { courseId: row.courseId, userId: row.userId, reason },\n \"POST\",\n );\n list.reload();\n }, \"Certificate revoked.\");\n }}\n >\n Revoke certificate\n </Button>\n )}\n </div>\n <details>\n <summary>Learning record</summary>\n {Object.entries(row.progress).map(([id, progress]) => (\n <p key={id}>\n {row.lessonTitles[id] ?? \"Lesson\"} ·{\" \"}\n {progress.completedAt ? \"Complete\" : \"Started\"} ·{\" \"}\n {progress.quizAttempts.length} quiz attempts ·{\" \"}\n {progress.assignments.length} submissions\n </p>\n ))}\n </details>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {list.data && !list.data.items.length && <p>No enrollments match this filter.</p>}\n </Panel>\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nexport function AssignmentsPage() {\n const [courseId, setCourseId] = useState(\"\");\n const [cursor, setCursor] = useState<string>();\n const list = useLoad<\n Page<\n AssignmentSubmission & {\n userId: string;\n learnerName: string;\n courseId: string;\n lessonId: string;\n }\n >\n >(\"admin/assignments\", { courseId, cursor }, !!courseId);\n const [selected, setSelected] = useState<\n AssignmentSubmission & {\n userId: string;\n learnerName: string;\n courseId: string;\n lessonId: string;\n }\n >();\n const [points, setPoints] = useState(0);\n const [feedback, setFeedback] = useState(\"\");\n const action = useAction();\n const grade = (event: FormEvent) => {\n event.preventDefault();\n if (!selected) return;\n void action.run(async () => {\n await api(\n \"admin/assignment/grade\",\n {\n courseId: selected.courseId,\n lessonId: selected.lessonId,\n userId: selected.userId,\n submissionId: selected.id,\n points,\n feedback,\n },\n \"POST\",\n );\n setSelected(undefined);\n list.reload();\n }, \"Grade saved and learner notified.\");\n };\n return (\n <PageFrame\n title=\"Assignments\"\n description=\"Read submissions and provide clear, useful feedback.\"\n >\n <Notice error={list.error || action.error} message={action.message} />\n <CoursePicker\n value={courseId}\n onChange={(id) => {\n setCourseId(id);\n setCursor(undefined);\n setSelected(undefined);\n }}\n />\n {!courseId && (\n <Panel>\n <p>Choose a course to view its submissions.</p>\n </Panel>\n )}\n {selected && (\n <Panel title={`Grade ${selected.learnerName}'s submission`}>\n <p className=\"lms-body\">{selected.body}</p>\n {selected.attachmentUrl && (\n <a href={selected.attachmentUrl} target=\"_blank\" rel=\"noopener noreferrer\">\n Open attachment ↗\n </a>\n )}\n <form onSubmit={grade}>\n <Field\n label={`Points out of ${selected.maxPoints}`}\n help={`Passing grade: ${selected.passingPoints}`}\n >\n <input\n type=\"number\"\n required\n min={0}\n max={selected.maxPoints}\n value={points}\n onChange={(event) => setPoints(Number(event.target.value))}\n />\n </Field>\n <Field label=\"Feedback\">\n <textarea\n rows={6}\n value={feedback}\n onChange={(event) => setFeedback(event.target.value)}\n />\n </Field>\n <div className=\"lms-actions\">\n <Button type=\"submit\" busy={action.busy}>\n Save grade\n </Button>\n <Button onClick={() => setSelected(undefined)}>Close</Button>\n </div>\n </form>\n </Panel>\n )}\n {list.data?.items.map((item) => (\n <Panel key={item.id}>\n <div className=\"lms-toolbar\">\n <h2>{item.learnerName}</h2>\n <span className=\"lms-badge\">{item.status}</span>\n <small>{new Date(item.submittedAt).toLocaleString()}</small>\n </div>\n <p className=\"lms-body\">{item.body}</p>\n {item.attachmentUrl && (\n <p>\n <a href={item.attachmentUrl} target=\"_blank\" rel=\"noopener noreferrer\">\n Open attachment ↗\n </a>\n </p>\n )}\n {item.status === \"graded\" ? (\n <>\n <p>\n {item.points}/{item.maxPoints} points\n </p>\n <p className=\"lms-body\">{item.feedback}</p>\n </>\n ) : (\n <Button\n onClick={() => {\n setSelected(item);\n setPoints(0);\n setFeedback(\"\");\n }}\n >\n Review & grade\n </Button>\n )}\n </Panel>\n ))}\n {list.data && !list.data.items.length && (\n <Panel>\n <p>No submissions on this page.</p>\n </Panel>\n )}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nexport function CommunityPage() {\n const [courseId, setCourseId] = useState(\"\");\n const [kind, setKind] = useState<\"discussions\" | \"reviews\">(\"discussions\");\n const [status, setStatus] = useState(\"pending\");\n const [cursor, setCursor] = useState<string>();\n const list = useLoad<Page<(Discussion | Review) & { revision: string }>>(`admin/${kind}`, {\n courseId,\n status,\n cursor,\n });\n const action = useAction();\n const moderate = (item: (Discussion | Review) & { revision: string }, next: string) =>\n void action.run(async () => {\n await api(\n `admin/${kind === \"reviews\" ? \"review\" : \"discussion\"}/moderate`,\n { id: item.id, expectedRevision: item.revision, status: next },\n \"POST\",\n );\n list.reload();\n }, \"Moderation saved.\");\n return (\n <PageFrame\n title=\"Learning community\"\n description=\"Moderate lesson discussions and course reviews.\"\n >\n <Notice error={list.error || action.error} message={action.message} />\n <div className=\"lms-grid\">\n <CoursePicker\n value={courseId}\n allowAll\n onChange={(id) => {\n setCourseId(id);\n setCursor(undefined);\n }}\n />\n <Field label=\"Content\">\n <select\n value={kind}\n onChange={(event) => {\n setKind(event.target.value as typeof kind);\n setCursor(undefined);\n }}\n >\n <option value=\"discussions\">Discussions</option>\n <option value=\"reviews\">Reviews</option>\n </select>\n </Field>\n <Field label=\"Status\">\n <select\n value={status}\n onChange={(event) => {\n setStatus(event.target.value);\n setCursor(undefined);\n }}\n >\n {[\"pending\", \"published\", \"hidden\"].map((value) => (\n <option key={value}>{value}</option>\n ))}\n </select>\n </Field>\n </div>\n {list.data?.items.map((item) => (\n <Panel key={item.id}>\n <h2>\n {item.authorName}\n {\"rating\" in item ? ` · ${item.rating}/5` : \"\"}\n </h2>\n <p className=\"lms-body\">{item.body}</p>\n <p className=\"lms-muted\">\n {new Date(item.createdAt).toLocaleString()} · {item.status}\n </p>\n <div className=\"lms-actions\">\n {item.status !== \"published\" && (\n <Button busy={action.busy} onClick={() => moderate(item, \"published\")}>\n Publish\n </Button>\n )}\n {item.status !== \"hidden\" && (\n <Button danger busy={action.busy} onClick={() => moderate(item, \"hidden\")}>\n Hide\n </Button>\n )}\n </div>\n </Panel>\n ))}\n {list.data && !list.data.items.length && (\n <Panel>\n <p>No community posts match this filter.</p>\n </Panel>\n )}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nfunction CohortMembershipQueue() {\n const cohorts = useChoices<Cohort>(\"admin/cohorts\");\n const [cohortId, setCohortId] = useState(\"\");\n const [status, setStatus] = useState(\"pending\");\n const [cursor, setCursor] = useState<string>();\n const [reason, setReason] = useState(\"\");\n const list = useLoad<Page<CohortMembership>>(\"admin/cohort/memberships\", {\n cohortId,\n status,\n cursor,\n });\n const action = useAction();\n const decide = (membership: CohortMembership, next: string) =>\n void action.run(async () => {\n const result = await api<{\n results: { courseId: string; success: boolean; error?: string }[];\n }>(\n \"admin/cohort/decision\",\n { cohortId: membership.cohortId, userId: membership.userId, status: next, reason },\n \"POST\",\n );\n list.reload();\n const failures = result.results.filter((item) => !item.success);\n if (failures.length)\n throw new Error(\n `Membership saved; ${failures.length} course access updates need attention. ${failures.map((item) => item.error).join(\" \")} Review the learner's course enrollment and retry access.`,\n );\n }, \"Cohort membership updated.\");\n return (\n <Panel title=\"Cohort membership requests\">\n <Notice error={list.error || action.error} message={action.message} />\n <div className=\"lms-grid\">\n <Field label=\"Cohort\">\n <select\n value={cohortId}\n onChange={(event) => {\n setCohortId(event.target.value);\n setCursor(undefined);\n }}\n >\n <option value=\"\">All cohorts</option>\n {cohorts.items.map((cohort) => (\n <option key={cohort.id} value={cohort.id}>\n {cohort.title}\n </option>\n ))}\n </select>\n {cohorts.data?.hasMore && <Button onClick={cohorts.more}>Load more cohorts</Button>}\n </Field>\n <Field label=\"Membership status\">\n <select\n value={status}\n onChange={(event) => {\n setStatus(event.target.value);\n setCursor(undefined);\n }}\n >\n <option value=\"\">All statuses</option>\n {[\"pending\", \"active\", \"rejected\", \"suspended\", \"cancelled\"].map((value) => (\n <option key={value}>{value}</option>\n ))}\n </select>\n </Field>\n <Field label=\"Decision note (optional)\">\n <input\n value={reason}\n maxLength={1000}\n onChange={(event) => setReason(event.target.value)}\n />\n </Field>\n </div>\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Learner</th>\n <th>Cohort</th>\n <th>Membership</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n {list.data?.items.map((membership) => (\n <tr key={membership.id}>\n <td>\n {membership.learnerName}\n <small>{membership.learnerEmail}</small>\n </td>\n <td>\n {cohorts.items.find((cohort) => cohort.id === membership.cohortId)?.title ??\n \"Cohort\"}\n </td>\n <td>\n {membership.status}\n {membership.reason && <small>{membership.reason}</small>}\n </td>\n <td>\n <div className=\"lms-actions\">\n <Button busy={action.busy} onClick={() => decide(membership, \"active\")}>\n {membership.status === \"pending\"\n ? \"Approve\"\n : membership.status === \"active\"\n ? \"Retry course access\"\n : \"Restore\"}\n </Button>\n {membership.status === \"pending\" && (\n <Button\n danger\n busy={action.busy}\n onClick={() => decide(membership, \"rejected\")}\n >\n Reject\n </Button>\n )}\n {membership.status === \"active\" && (\n <Button busy={action.busy} onClick={() => decide(membership, \"suspended\")}>\n Suspend membership\n </Button>\n )}\n {membership.status !== \"cancelled\" && (\n <Button\n danger\n busy={action.busy}\n onClick={() => decide(membership, \"cancelled\")}\n >\n Cancel membership\n </Button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {list.data && !list.data.items.length && <p>No membership requests match this filter.</p>}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </Panel>\n );\n}\n\nexport function PathsPage() {\n const [cursor, setCursor] = useState<string>();\n const list = useLoad<Page<LearningPath & { revision: string }>>(\"admin/paths\", { cursor });\n const courses = useChoices<Course>(\"admin/courses\");\n const [edit, setEdit] = useState<{\n id?: string;\n revision: string | null;\n title: string;\n description: string;\n status: LearningPath[\"status\"];\n courseIds: string[];\n }>();\n const action = useAction();\n return (\n <PageFrame\n title=\"Learning paths\"\n description=\"Build ordered programs. Learners retain the course list they joined; individual course enrollment still controls access.\"\n >\n <Notice error={list.error || courses.error || action.error} message={action.message} />\n {!edit && (\n <Button\n onClick={() =>\n setEdit({\n revision: null,\n title: \"New learning path\",\n description: \"\",\n status: \"draft\",\n courseIds: [],\n })\n }\n >\n Create learning path\n </Button>\n )}\n {edit && (\n <Panel title={edit.id ? \"Edit path\" : \"Create path\"}>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void action.run(async () => {\n const { id, revision, ...data } = edit;\n await api(\"admin/path/save\", { id, expectedRevision: revision, data }, \"POST\");\n setEdit(undefined);\n list.reload();\n }, \"Path saved. Existing learners retain their joined course lists.\");\n }}\n >\n <Field label=\"Title\">\n <input\n required\n maxLength={200}\n value={edit.title}\n onChange={(event) => setEdit({ ...edit, title: event.target.value })}\n />\n </Field>\n <Field label=\"Description\">\n <textarea\n maxLength={5000}\n rows={4}\n value={edit.description}\n onChange={(event) => setEdit({ ...edit, description: event.target.value })}\n />\n </Field>\n <Field label=\"Visibility\">\n <select\n value={edit.status}\n onChange={(event) =>\n setEdit({ ...edit, status: event.target.value as LearningPath[\"status\"] })\n }\n >\n <option value=\"draft\">Draft</option>\n <option value=\"published\">Published</option>\n <option value=\"archived\">Archived</option>\n </select>\n </Field>\n <ChoicesField\n label=\"Courses\"\n choices={courses.items.map((course) => ({\n id: course.id,\n label: `${course.title} (${course.status})`,\n }))}\n value={edit.courseIds}\n onChange={(courseIds) => setEdit({ ...edit, courseIds })}\n />\n {courses.data?.hasMore && <Button onClick={courses.more}>Load more courses</Button>}\n <ol>\n {edit.courseIds.map((id, index) => (\n <li key={id}>\n {courses.items.find((course) => course.id === id)?.title ?? id}\n <Button\n disabled={index === 0}\n aria-label=\"Move course earlier\"\n onClick={() => {\n const ids = [...edit.courseIds];\n [ids[index], ids[index - 1]] = [ids[index - 1]!, ids[index]!];\n setEdit({ ...edit, courseIds: ids });\n }}\n >\n Move up\n </Button>\n </li>\n ))}\n </ol>\n <Button type=\"submit\" busy={action.busy}>\n Save path\n </Button>\n <Button disabled={action.busy} onClick={() => setEdit(undefined)}>\n Cancel\n </Button>\n </form>\n </Panel>\n )}\n {list.data?.items.map((path) => (\n <Panel key={path.id} title={path.title}>\n <p>\n {path.status} · {path.courseIds.length} courses\n </p>\n <Button\n disabled={Boolean(edit)}\n onClick={() =>\n setEdit({\n id: path.id,\n revision: path.revision,\n title: path.title,\n description: path.description,\n courseIds: path.courseIds,\n status: path.status,\n })\n }\n >\n Edit path\n </Button>\n </Panel>\n ))}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nexport function CohortsPage() {\n const [cursor, setCursor] = useState<string>();\n const list = useLoad<Page<Cohort & { revision: string }>>(\"admin/cohorts\", { cursor });\n const courses = useChoices<Course>(\"admin/courses\");\n const users = useChoices<UserChoice>(\"admin/users\");\n const academy = useLoad<{ basePath: string }>(\"academy\");\n const [edit, setEdit] = useState<{\n id?: string;\n revision: string | null;\n title: string;\n courseIds: string[];\n memberIds: string[];\n startsAt: string | null;\n endsAt: string | null;\n }>();\n const action = useAction();\n const save = (event: FormEvent) => {\n event.preventDefault();\n if (!edit) return;\n void action.run(async () => {\n const { id, revision, ...data } = edit;\n await api(\"admin/cohort/save\", { id, expectedRevision: revision, data }, \"POST\");\n setEdit(undefined);\n list.reload();\n }, \"Cohort saved.\");\n };\n const enroll = (cohort: Cohort & { revision: string }) =>\n void action.run(async () => {\n let offset = 0;\n let hasMore = true;\n const errors: string[] = [];\n while (hasMore) {\n const result = await api<{\n nextOffset: number;\n hasMore: boolean;\n results: { success: boolean; error?: string }[];\n }>(\n \"admin/cohort/enroll\",\n { id: cohort.id, expectedRevision: cohort.revision, offset },\n \"POST\",\n );\n offset = result.nextOffset;\n hasMore = result.hasMore;\n errors.push(\n ...result.results\n .filter((row) => !row.success)\n .map((row) => row.error ?? \"Enrollment failed.\"),\n );\n }\n if (errors.length)\n throw new Error(\n `${errors.length} enrollments need attention: ${errors.slice(0, 3).join(\" \")}`,\n );\n }, \"Cohort learners enrolled.\");\n return (\n <PageFrame\n title=\"Cohorts\"\n description=\"Approve cohort membership and manage shared learning schedules.\"\n >\n <Notice\n error={list.error || action.error || courses.error || users.error}\n message={action.message}\n />\n <Button\n onClick={() =>\n setEdit({\n revision: null,\n title: \"New cohort\",\n courseIds: [],\n memberIds: [],\n startsAt: null,\n endsAt: null,\n })\n }\n >\n Create cohort\n </Button>\n {edit && (\n <Panel title=\"Cohort details\">\n <form onSubmit={save}>\n <Field label=\"Cohort name\">\n <input\n required\n value={edit.title}\n onChange={(event) => setEdit({ ...edit, title: event.target.value })}\n />\n </Field>\n <div className=\"lms-grid\">\n <div>\n <ChoicesField\n label=\"Courses\"\n value={edit.courseIds}\n choices={courses.items.map((course) => ({ id: course.id, label: course.title }))}\n onChange={(courseIds) => setEdit({ ...edit, courseIds })}\n />\n {courses.data?.hasMore && <Button onClick={courses.more}>Load more courses</Button>}\n </div>\n <div>\n <ChoicesField\n label=\"Learners for manual enrollment\"\n value={edit.memberIds}\n choices={users.items.map((account) => ({\n id: account.id,\n label: `${account.name || account.email} · ${account.email}`,\n }))}\n onChange={(memberIds) => setEdit({ ...edit, memberIds })}\n />\n {users.data?.hasMore && <Button onClick={users.more}>Load more learners</Button>}\n </div>\n <Field label=\"Access starts\">\n <input\n type=\"datetime-local\"\n value={localDate(edit.startsAt)}\n onChange={(event) => setEdit({ ...edit, startsAt: isoDate(event.target.value) })}\n />\n </Field>\n <Field label=\"Access ends\">\n <input\n type=\"datetime-local\"\n value={localDate(edit.endsAt)}\n onChange={(event) => setEdit({ ...edit, endsAt: isoDate(event.target.value) })}\n />\n </Field>\n </div>\n <div className=\"lms-actions\">\n <Button type=\"submit\" busy={action.busy}>\n Save cohort\n </Button>\n <Button onClick={() => setEdit(undefined)}>Close</Button>\n </div>\n </form>\n </Panel>\n )}\n {list.data?.items.map((cohort) => (\n <Panel key={cohort.id}>\n <h2>{cohort.title}</h2>\n <p>\n {cohort.memberIds.length} learners · {cohort.courseIds.length} courses\n </p>\n <div className=\"lms-actions\">\n <Button onClick={() => setEdit({ ...cohort })}>Edit</Button>\n <a\n href={`${academy.data?.basePath ?? \"/academy\"}/cohorts/${cohort.id}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Open enrollment page ↗\n </a>\n <Button busy={action.busy} onClick={() => enroll(cohort)}>\n Enroll members\n </Button>\n </div>\n </Panel>\n ))}\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n <CohortMembershipQueue />\n </PageFrame>\n );\n}\n\nexport function ReportsPage() {\n const [courseId, setCourseId] = useState(\"\");\n const report = useLoad<Report>(\"admin/report\", { courseId });\n const action = useAction();\n const exportCsv = () =>\n void action.run(async () => {\n const rows: EnrollmentRow[] = [];\n let cursor: string | undefined;\n do {\n const page = await api<Page<EnrollmentRow>>(\"admin/enrollments\", {\n courseId,\n cursor,\n limit: 100,\n });\n rows.push(...page.items);\n if (rows.length > 10_000)\n throw new Error(\"Choose a course to export fewer than 10,000 enrollments.\");\n cursor = page.hasMore ? page.cursor : undefined;\n } while (cursor);\n download(\n \"lms-enrollments.csv\",\n \"\\uFEFF\" + [enrollmentCsvHeader, ...enrollmentCsvLines(rows)].join(\"\\r\\n\"),\n \"text/csv;charset=utf-8\",\n );\n }, \"Report exported.\");\n return (\n <PageFrame\n title=\"Learning reports\"\n description=\"Enrollment and completion counts cover all records in the selected scope.\"\n >\n <Notice error={report.error || action.error} message={action.message} />\n <CoursePicker value={courseId} allowAll onChange={setCourseId} />\n <Metrics report={report.data} />\n <Panel title=\"Enrollment status\">\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Status</th>\n <th>Enrollments</th>\n </tr>\n </thead>\n <tbody>\n {[\"pending\", \"active\", \"completed\", \"rejected\", \"suspended\", \"cancelled\"].map(\n (status) => (\n <tr key={status}>\n <td>{status}</td>\n <td>\n {report.data\n ? (report.data as unknown as Record<string, number>)[status]\n : \"—\"}\n </td>\n </tr>\n ),\n )}\n </tbody>\n </table>\n </div>\n </Panel>\n <Button busy={action.busy} onClick={exportCsv}>\n Export enrollments as CSV\n </Button>\n <Panel title=\"Access sources\">\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Initial grant source</th>\n <th>Enrollments</th>\n </tr>\n </thead>\n <tbody>\n {[\"free\", \"manual\", \"cohort\", \"purchase\"].map((source) => (\n <tr key={source}>\n <td>{source}</td>\n <td>{report.data?.accessSources[source] ?? \"—\"}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <p>\n An enrollment can have several access grants. The source records its first approved\n acquisition; each learner's current access is shown in the CSV export.\n </p>\n </Panel>\n <Panel title=\"Access decisions\">\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Decision</th>\n <th>Enrollments</th>\n </tr>\n </thead>\n <tbody>\n {[\"pending\", \"granted\", \"suspended\", \"revoked\"].map((decision) => (\n <tr key={decision}>\n <td>{decision}</td>\n <td>{report.data?.accessDecisions[decision] ?? \"—\"}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <p>\n Access decisions are separate from date windows and cohort membership. Use the enrollment\n export to review current access.\n </p>\n </Panel>\n </PageFrame>\n );\n}\n\nexport function NotificationsPage() {\n const [cursor, setCursor] = useState<string>();\n const [status, setStatus] = useState(\"failed\");\n const list = useLoad<Page<Notification>>(\"admin/notifications\", { cursor, status });\n const action = useAction();\n return (\n <PageFrame\n title=\"Learning notifications\"\n description=\"Review delivery status and retry failed emails.\"\n >\n <Notice error={list.error || action.error} message={action.message} />\n <div className=\"lms-actions\">\n <Field label=\"Email status\">\n <select\n value={status}\n onChange={(event) => {\n setStatus(event.target.value);\n setCursor(undefined);\n }}\n >\n <option value=\"\">All notifications</option>\n {[\"failed\", \"pending\", \"sending\", \"sent\", \"disabled\"].map((value) => (\n <option key={value} value={value}>\n {value}\n </option>\n ))}\n </select>\n </Field>\n <Button onClick={list.reload} busy={list.loading}>\n Refresh\n </Button>\n </div>\n <Panel>\n <p>\n Retries run during scheduled maintenance, with up to three attempts per email. Review\n delivery before retrying: an interrupted confirmation can mean the email was already sent.\n </p>\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Created</th>\n <th>Learner</th>\n <th>Notification</th>\n <th>Email</th>\n <th>Attempts</th>\n <th>Action</th>\n </tr>\n </thead>\n <tbody>\n {list.data?.items.map((item) => (\n <tr key={item.id}>\n <td>{new Date(item.createdAt).toLocaleString()}</td>\n <td>{item.email}</td>\n <td>\n <strong>{item.title}</strong>\n <p>{item.message}</p>\n </td>\n <td>{item.emailStatus}</td>\n <td>{item.emailAttempts} / 3</td>\n <td>\n {item.emailStatus === \"failed\" && item.emailAttempts < 3 && (\n <Button\n busy={action.busy}\n onClick={() =>\n void action.run(async () => {\n await api(\"admin/notification/retry\", { id: item.id }, \"POST\");\n list.reload();\n }, \"Email queued for retry.\")\n }\n >\n Retry email\n </Button>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {list.loading && <p role=\"status\">Loading notifications…</p>}\n {!list.loading && list.data?.items.length === 0 && (\n <p>No notifications match this status.</p>\n )}\n </Panel>\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nexport function AuditPage() {\n const [cursor, setCursor] = useState<string>();\n const list = useLoad<Page<AuditRecord>>(\"admin/audit\", { cursor });\n return (\n <PageFrame\n title=\"Learning audit history\"\n description=\"Inspect course changes, enrollment decisions, grades, moderation, and delivery retries.\"\n >\n <Notice error={list.error} />\n <Button onClick={list.reload} busy={list.loading}>\n Refresh\n </Button>\n <Panel>\n <div className=\"lms-table-wrap\">\n <table className=\"lms-table\">\n <thead>\n <tr>\n <th>Time</th>\n <th>Action</th>\n <th>Actor</th>\n <th>Resource</th>\n <th>Details</th>\n </tr>\n </thead>\n <tbody>\n {list.data?.items.map((item) => (\n <tr key={item.id}>\n <td>{new Date(item.createdAt).toLocaleString()}</td>\n <td>{item.action}</td>\n <td>{item.actorId}</td>\n <td>{item.resourceId}</td>\n <td>{JSON.stringify(item.details)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {list.loading && <p role=\"status\">Loading audit history…</p>}\n {!list.loading && list.data?.items.length === 0 && (\n <p>No learning administration actions recorded yet.</p>\n )}\n </Panel>\n <Pager page={list.data} next={setCursor} reset={() => setCursor(undefined)} />\n </PageFrame>\n );\n}\n\nfunction MigrationPanel() {\n const load = useLoad<MigrationState>(\"admin/migrations\");\n const action = useAction();\n return (\n <Panel>\n <h2>Course edition migration</h2>\n <p>\n Upgrade existing courses and pin enrollments to their original curriculum. Progress,\n assessments, grants and certificates are retained. Each batch handles up to 20 records and\n can be resumed after interruption.\n </p>\n <Notice error={action.error || load.error || load.data?.lastError || undefined} />\n {load.data && (\n <p>\n Phase: {load.data.phase} · Courses processed: {load.data.coursesProcessed} · Enrollments\n processed: {load.data.enrollmentsProcessed}\n </p>\n )}\n <Button\n busy={action.busy}\n disabled={load.loading || load.data?.phase === \"complete\"}\n onClick={() =>\n void action.run(async () => {\n try {\n await api(\"admin/migrations/run\", {}, \"POST\");\n } finally {\n load.reload();\n }\n }, \"Migration checkpoint saved.\")\n }\n >\n Run next batch\n </Button>\n <Button onClick={load.reload}>Refresh status</Button>\n <Notice message={action.message} />\n </Panel>\n );\n}\n\nfunction HealthPanel() {\n const load = useLoad<LmsHealth>(\"admin/health\");\n return (\n <Panel title=\"Operational health\">\n <Notice error={load.error} />\n {load.data && (\n <>\n <p>\n Plugin {load.data.version} · Email {load.data.emailEnabled ? \"enabled\" : \"disabled\"}\n </p>\n <p role={load.data.maintenanceStale ? \"alert\" : undefined}>\n {load.data.maintenanceStale\n ? \"Maintenance has not completed successfully in the last 45 minutes. Check the host scheduler and logs.\"\n : \"Scheduled maintenance is reporting successfully.\"}\n </p>\n <p>\n Last completed: {load.data.maintenance?.completedAt ?? \"No successful run reported\"}\n </p>\n <p>\n Pending emails: {load.data.pendingEmails} · Failed emails: {load.data.failedEmails} ·\n Oldest pending: {load.data.oldestPendingAt ?? \"None\"}\n </p>\n <p>Migration phase: {load.data.migration?.phase ?? \"Not started\"}</p>\n </>\n )}\n <Button onClick={load.reload}>Refresh health</Button>\n </Panel>\n );\n}\n\nexport function SettingsPage() {\n const load = useLoad<LmsSettings>(\"admin/settings\");\n const [settings, setSettings] = useState<LmsSettings>(settingsSchema.parse({}));\n const action = useAction();\n useEffect(() => {\n if (load.data) setSettings(load.data);\n }, [load.data]);\n const save = (event: FormEvent) => {\n event.preventDefault();\n void action.run(async () => {\n await api(\"admin/settings/save\", settings, \"POST\");\n load.reload();\n }, \"LMS settings saved.\");\n };\n return (\n <PageFrame\n title=\"LMS settings\"\n description=\"Configure your academy, certificates, moderation, and reminders.\"\n >\n <Notice error={load.error || action.error} message={action.message} />\n <MigrationPanel />\n <HealthPanel />\n <Panel>\n <form onSubmit={save}>\n <Field label=\"Academy title\">\n <input\n value={settings.academyTitle}\n onChange={(event) => setSettings({ ...settings, academyTitle: event.target.value })}\n />\n </Field>\n <Field label=\"Academy introduction\">\n <textarea\n rows={3}\n value={settings.academyDescription}\n onChange={(event) =>\n setSettings({ ...settings, academyDescription: event.target.value })\n }\n />\n </Field>\n <Field label=\"Certificate issuer\">\n <input\n value={settings.issuerName}\n onChange={(event) => setSettings({ ...settings, issuerName: event.target.value })}\n />\n </Field>\n <Field\n label=\"Remind inactive learners after days\"\n help=\"0 disables reminders. Scheduled maintenance must be enabled in the host.\"\n >\n <input\n type=\"number\"\n min={0}\n max={90}\n value={settings.reminderDays}\n onChange={(event) =>\n setSettings({ ...settings, reminderDays: Number(event.target.value) })\n }\n />\n </Field>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={settings.moderateDiscussions}\n onChange={(event) =>\n setSettings({ ...settings, moderateDiscussions: event.target.checked })\n }\n />\n Review discussions before publishing\n </label>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={settings.moderateReviews}\n onChange={(event) =>\n setSettings({ ...settings, moderateReviews: event.target.checked })\n }\n />\n Review course reviews before publishing\n </label>\n <label className=\"lms-check\">\n <input\n type=\"checkbox\"\n checked={settings.emailNotifications}\n onChange={(event) =>\n setSettings({ ...settings, emailNotifications: event.target.checked })\n }\n />\n Send notifications through the site's EmDash email transport\n </label>\n <Button type=\"submit\" busy={action.busy}>\n Save settings\n </Button>\n </form>\n </Panel>\n </PageFrame>\n );\n}\n\nexport function LearningWidget() {\n const report = useLoad<Report>(\"admin/report\");\n return (\n <div className=\"ag-lms-admin\">\n <style>{css}</style>\n <Notice error={report.error} />\n <p>\n <strong>{report.data?.active ?? \"—\"}</strong> active ·{\" \"}\n <strong>{report.data?.completedEver ?? \"—\"}</strong> completed ·{\" \"}\n <strong>{report.data?.pending ?? \"—\"}</strong> awaiting approval\n </p>\n <a href={ADMIN_BASE}>Open learning overview →</a>\n </div>\n );\n}\nexport const pages = {\n \"/\": OverviewPage,\n \"/courses\": CoursesPage,\n \"/learners\": LearnersPage,\n \"/assignments\": AssignmentsPage,\n \"/community\": CommunityPage,\n \"/cohorts\": CohortsPage,\n \"/paths\": PathsPage,\n \"/reports\": ReportsPage,\n \"/notifications\": NotificationsPage,\n \"/audit\": AuditPage,\n \"/settings\": SettingsPage,\n};\nexport const widgets = { learning: LearningWidget };\n\nconst css = `\n.ag-lms-admin{color:var(--text-color-kumo-default,#1f2937);font-family:var(--font-emdash,ui-sans-serif,system-ui,sans-serif);padding:clamp(1rem,3vw,2.5rem);max-width:1400px;margin-inline:auto;line-height:1.55;direction:inherit}\n.ag-lms-admin *{box-sizing:border-box}.ag-lms-admin h1{font-size:clamp(1.6rem,3vw,2.15rem);margin:0}.ag-lms-admin h2{font-size:1.15rem;margin-block:0 .8rem}.ag-lms-admin h3{font-size:1rem}.ag-lms-admin p{margin-block:.5rem 1rem}.lms-page-header{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-block-end:1.5rem}.lms-page-header>div>p{max-width:65ch;color:var(--text-color-kumo-subtle,#64748b)}.lms-eyebrow{font-size:.7rem;letter-spacing:.15em;font-weight:700}.lms-tabs{display:flex;gap:.3rem;flex-wrap:wrap;margin-block:1rem 1.5rem}.lms-tabs a{padding:.4rem .7rem;border-radius:.4rem;text-decoration:none;color:inherit;background:var(--color-kumo-control,#f1f5f9)}.lms-panel{background:var(--color-kumo-base,#fff);border:1px solid var(--color-kumo-line,#d1d5db);border-radius:.65rem;padding:1.3rem;margin-block-end:1rem;min-width:0}.lms-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1rem}.lms-course-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(270px,1fr));gap:1rem}.lms-course-grid .lms-panel{display:flex;flex-direction:column;align-items:flex-start}.lms-course-grid .lms-actions{margin-block-start:auto}.lms-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:1rem}.lms-metrics strong{display:block;font-size:2rem;margin-block-start:.5rem}.lms-metrics span,.lms-muted{font-size:.85rem;color:var(--text-color-kumo-subtle,#64748b)}.lms-actions,.lms-toolbar{display:flex;gap:.5rem;align-items:center;flex-wrap:wrap;margin-block:.6rem 1rem}.lms-toolbar>.lms-field{min-width:160px;margin:0}.lms-button{display:inline-flex;justify-content:center;align-items:center;gap:.4rem;min-height:38px;padding:.5rem .8rem;border:1px solid var(--color-kumo-line,#cbd5e1);border-radius:.4rem;background:var(--color-kumo-control,#f8fafc);color:var(--text-color-kumo-default,#1e293b);font:inherit;font-size:.875rem;font-weight:600;text-decoration:none;cursor:pointer}.lms-button:hover{background:var(--color-kumo-interact,#e2e8f0)}.lms-button:disabled{opacity:.55;cursor:default}.lms-danger{color:var(--text-color-kumo-danger,#b91c1c)}.lms-field{display:grid;gap:.35rem;margin-block-end:1rem;min-width:0;font-size:.875rem;font-weight:600}.lms-field small{font-weight:400;color:var(--text-color-kumo-subtle,#64748b)}.ag-lms-admin input:not([type=checkbox]):not([type=radio]),.ag-lms-admin textarea,.ag-lms-admin select{width:100%;border:1px solid var(--color-kumo-line,#cbd5e1);border-radius:.35rem;background:var(--color-kumo-control,#fff);color:inherit;padding:.6rem;font:inherit;font-size:.875rem;font-weight:400}.ag-lms-admin input[type=checkbox],.ag-lms-admin input[type=radio]{width:1rem;height:1rem;accent-color:var(--color-kumo-brand,#2563eb)}.ag-lms-admin :focus-visible{outline:2px solid var(--color-kumo-focus,#2563eb);outline-offset:3px}.lms-check{display:flex;gap:.6rem;align-items:center;font-size:.9rem;margin-block:.7rem}.lms-notice{padding:.8rem 1rem;border:1px solid var(--color-kumo-line,#cbd5e1);border-radius:.4rem;background:var(--color-kumo-tint,#f1f5f9)}.lms-error{color:var(--text-color-kumo-danger,#b91c1c);border-color:currentColor}.lms-badge{font-size:.7rem;text-transform:uppercase;font-weight:700;border:1px solid var(--color-kumo-line,#cbd5e1);border-radius:1rem;padding:.2rem .6rem;margin-block-end:.6rem}.lms-studio{display:grid;grid-template-columns:330px minmax(0,1fr);gap:1.3rem;align-items:start}.lms-module{border-block-end:1px solid var(--color-kumo-line,#cbd5e1);padding-block:1rem}.lms-lesson-list{list-style:none;padding:0;margin:0}.lms-lesson-list li{display:flex;align-items:center;gap:.3rem}.lms-select-lesson{background:transparent;color:inherit;border:0;border-radius:.35rem;cursor:pointer;text-align:start;padding:.6rem;flex:1;font:inherit;font-size:.9rem}.lms-select-lesson[aria-current=true]{background:var(--color-kumo-control,#eff6ff);font-weight:600}.lms-select-lesson small{display:block;font-weight:400;opacity:.75}.lms-lesson-list .lms-actions{margin:0}.lms-option{display:flex;align-items:center;gap:.5rem;margin-block:.5rem}.lms-question{border-block-start:1px solid var(--color-kumo-line,#cbd5e1);padding-block:1rem}.lms-question fieldset{border:1px solid var(--color-kumo-line,#cbd5e1);border-radius:.4rem;margin-block:1rem;padding:1rem}.lms-resource{border-block-end:1px solid var(--color-kumo-line,#cbd5e1);padding-block:1rem}.lms-file{position:absolute;width:1px!important;height:1px;opacity:0}.lms-table-wrap{overflow:auto}.lms-table{width:100%;border-collapse:collapse;font-size:.875rem}.lms-table th,.lms-table td{padding:.7rem;text-align:start;border-block-end:1px solid var(--color-kumo-line,#e5e7eb);vertical-align:top}.lms-table th{font-weight:600}.lms-table small{display:block;color:var(--text-color-kumo-subtle,#64748b)}.lms-table .lms-actions{margin:0}.lms-body{white-space:pre-wrap;overflow-wrap:anywhere}.ag-lms-admin details{padding:.7rem;border:1px solid var(--color-kumo-line,#d1d5db);border-radius:.4rem;margin-block:1rem}.ag-lms-admin summary{cursor:pointer;font-weight:600}.lms-notice:empty{display:none}@media(max-width:900px){.lms-studio{grid-template-columns:1fr}.lms-page-header{align-items:start;flex-direction:column}}@media(max-width:600px){.lms-grid{grid-template-columns:1fr}.lms-toolbar{align-items:stretch}.lms-toolbar>.lms-field{width:100%}.lms-panel{padding:1rem}}`;\n"],"mappings":"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"}
|