feat(cms/studio): agregar plantillas de curso reutilizables

- backend: CRUD básico de course templates y endpoint para crear curso desde plantilla
- migration: tabla course_templates con datos JSON del curso base
- frontend: nueva pantalla /course-templates para guardar y aplicar plantillas
- navegación: acceso desde menú Cursos
This commit is contained in:
2026-04-06 15:34:57 -04:00
parent 5226da644c
commit 92b4e4a3ac
6 changed files with 538 additions and 0 deletions
+24
View File
@@ -908,6 +908,21 @@ export const cmsApi = {
body: JSON.stringify(data)
}),
// Course Templates
listCourseTemplates: (): Promise<CourseTemplateSummary[]> => apiFetch('/course-templates'),
createCourseTemplateFromCourse: (courseId: string, name: string, description?: string): Promise<CourseTemplateSummary> =>
apiFetch(`/course-templates/from-course/${courseId}`, {
method: 'POST',
body: JSON.stringify({ name, description })
}),
applyCourseTemplate: (templateId: string, title?: string): Promise<Course> =>
apiFetch(`/course-templates/${templateId}/apply`, {
method: 'POST',
body: JSON.stringify({ title })
}),
deleteCourseTemplate: (templateId: string): Promise<void> =>
apiFetch(`/course-templates/${templateId}`, { method: 'DELETE' }),
deleteCourse: (id: string): Promise<void> => apiFetch(`/courses/${id}`, { method: 'DELETE' }),
async generateCourse(prompt: string, targetOrgId?: string): Promise<Course> {
@@ -1414,6 +1429,15 @@ export interface LtiDeepLinkingContentItem {
[key: string]: string | number | boolean | object | undefined | null;
}
export interface CourseTemplateSummary {
id: string;
name: string;
description?: string | null;
source_course_id?: string | null;
created_at: string;
updated_at: string;
}
export interface BackgroundTask {
id: string;
title: string;