feat: productionize learning engine and classroom

This commit is contained in:
inman
2026-08-16 21:44:52 +08:00
parent 2d04197f3f
commit ba35adfbfa
124 changed files with 9071 additions and 796 deletions

View File

@@ -33,6 +33,7 @@ import { Progress } from '@/components/ui/progress';
import { useI18n } from '@/lib/hooks/use-i18n';
import type { CourseDetail } from '@/lib/course-framework/types';
import { toast } from 'sonner';
import { opsApiFetch } from '@/lib/ops/api-fetch';
const MODULE_STATUS_STYLES: Record<string, string> = {
pending: 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300',
@@ -66,7 +67,7 @@ export default function CourseBuilderPage() {
const load = useCallback(async () => {
if (!courseId) return;
try {
const response = await fetch(`/api/courses/${courseId}`);
const response = await opsApiFetch(`/api/courses/${courseId}`);
const body = (await response.json()) as { course?: CourseDetail };
if (!response.ok || !body.course) {
throw new Error(`HTTP ${response.status}`);
@@ -110,7 +111,7 @@ export default function CourseBuilderPage() {
const publishCourse = async () => {
await act('publish', () =>
fetch(`/api/courses/${courseId}/publish`, {
opsApiFetch(`/api/courses/${courseId}/publish`, {
method: 'POST',
}),
);
@@ -199,7 +200,7 @@ export default function CourseBuilderPage() {
disabled={acting !== null}
onClick={() =>
void act('cancel', () =>
fetch(`/api/courses/${courseId}/cancel`, { method: 'POST' }),
opsApiFetch(`/api/courses/${courseId}/cancel`, { method: 'POST' }),
)
}
>
@@ -214,7 +215,7 @@ export default function CourseBuilderPage() {
disabled={acting !== null}
onClick={() =>
void act('resume', () =>
fetch(`/api/courses/${courseId}/resume`, { method: 'POST' }),
opsApiFetch(`/api/courses/${courseId}/resume`, { method: 'POST' }),
)
}
>
@@ -415,7 +416,7 @@ export default function CourseBuilderPage() {
disabled={acting !== null}
onClick={() =>
void act('start', () =>
fetch(`/api/courses/${courseId}/start`, { method: 'POST' }),
opsApiFetch(`/api/courses/${courseId}/start`, { method: 'POST' }),
)
}
>
@@ -428,7 +429,7 @@ export default function CourseBuilderPage() {
disabled={acting !== null}
onClick={() =>
void act('frameworkRegenerate', () =>
fetch(`/api/courses/${courseId}/framework/regenerate`, { method: 'POST' }),
opsApiFetch(`/api/courses/${courseId}/framework/regenerate`, { method: 'POST' }),
)
}
>
@@ -635,7 +636,7 @@ export default function CourseBuilderPage() {
onClick={() => {
if (!window.confirm(t('course.regenerateModuleCascadeHint'))) return;
void act('regenerate', () =>
fetch(`/api/courses/${courseId}/modules/${module.index}/regenerate`, {
opsApiFetch(`/api/courses/${courseId}/modules/${module.index}/regenerate`, {
method: 'POST',
}),
);