1372 lines
30 KiB
TypeScript
1372 lines
30 KiB
TypeScript
export interface CourseCategory {
|
|
id: number
|
|
name: string
|
|
is_active: boolean
|
|
parent_id?: number | null
|
|
created_at: string
|
|
}
|
|
|
|
export interface CreateCourseCategoryRequest {
|
|
name: string
|
|
parent_id?: number | null
|
|
}
|
|
|
|
export interface GetCourseCategoriesResponse {
|
|
message: string
|
|
data: {
|
|
categories: CourseCategory[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface Course {
|
|
id: number
|
|
category_id: number
|
|
sub_category_id?: number | null
|
|
title: string
|
|
description: string
|
|
thumbnail: string
|
|
is_active: boolean
|
|
}
|
|
|
|
export interface GetCoursesResponse {
|
|
message: string
|
|
data: {
|
|
courses: Course[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface CreateCourseRequest {
|
|
category_id: number
|
|
sub_category_id?: number | null
|
|
title: string
|
|
description: string
|
|
}
|
|
|
|
export interface UpdateCourseRequest {
|
|
title?: string
|
|
description?: string
|
|
thumbnail?: string
|
|
is_active?: boolean
|
|
}
|
|
|
|
/** Row from GET /programs (e.g. Beginner / Intermediate program buckets) */
|
|
export interface LearningProgramListItem {
|
|
id: number
|
|
name: string
|
|
description?: string | null
|
|
thumbnail?: string | null
|
|
sort_order: number
|
|
created_at: string
|
|
}
|
|
|
|
export interface UpdateLearningProgramRequest {
|
|
name: string
|
|
description: string
|
|
thumbnail: string
|
|
}
|
|
|
|
export interface CreateLearningProgramRequest {
|
|
name: string
|
|
description: string
|
|
thumbnail: string
|
|
}
|
|
|
|
export interface CreateLearningProgramResponse {
|
|
message: string
|
|
data: LearningProgramListItem
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown | null
|
|
}
|
|
|
|
export interface GetLearningProgramsResponse {
|
|
message: string
|
|
data: {
|
|
programs: LearningProgramListItem[]
|
|
total_count: number
|
|
limit?: number
|
|
offset?: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** Row from GET /programs/:program_id/courses */
|
|
export interface ProgramCourseListItem {
|
|
id: number
|
|
program_id: number
|
|
name: string
|
|
description: string
|
|
sort_order: number
|
|
created_at: string
|
|
thumbnail?: string | null
|
|
/** Some list endpoints may expose the image as `thumbnail_url` instead. */
|
|
thumbnail_url?: string | null
|
|
/** GET /programs/:id/courses aggregates. */
|
|
module_count?: number
|
|
lesson_count?: number
|
|
practice_count?: number
|
|
/** Legacy aggregate field names; prefer module_count, lesson_count, practice_count. */
|
|
modules_count?: number
|
|
videos_count?: number
|
|
practices_count?: number
|
|
}
|
|
|
|
/** Body for PUT /courses/:id (program-linked Learn English courses). */
|
|
export interface UpdateTopLevelCourseRequest {
|
|
name: string
|
|
description: string
|
|
thumbnail: string
|
|
}
|
|
|
|
/** Body for POST /programs/:program_id/courses */
|
|
export interface CreateProgramCourseRequest {
|
|
name: string
|
|
description: string
|
|
thumbnail: string
|
|
}
|
|
|
|
export interface CreateProgramCourseResponse {
|
|
message: string
|
|
data: ProgramCourseListItem
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown | null
|
|
}
|
|
|
|
export interface GetProgramCoursesResponse {
|
|
message: string
|
|
data: {
|
|
total_count: number
|
|
limit: number
|
|
offset: number
|
|
courses: ProgramCourseListItem[]
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown | null
|
|
}
|
|
|
|
/** Row from GET /courses/:courseId/modules (Learn English track). */
|
|
export interface TopLevelCourseModuleItem {
|
|
id: number
|
|
program_id: number
|
|
course_id: number
|
|
name: string
|
|
description: string
|
|
icon?: string | null
|
|
sort_order: number
|
|
created_at: string
|
|
}
|
|
|
|
export interface GetTopLevelCourseModulesResponse {
|
|
message: string
|
|
data: {
|
|
limit: number
|
|
offset: number
|
|
modules: TopLevelCourseModuleItem[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown | null
|
|
}
|
|
|
|
/** Body for PUT /modules/:id (Learn English top-level modules). */
|
|
export interface UpdateTopLevelCourseModuleRequest {
|
|
name: string
|
|
description: string
|
|
icon: string
|
|
}
|
|
|
|
/** Body for POST /courses/:courseId/modules */
|
|
export interface CreateTopLevelCourseModuleRequest {
|
|
name: string
|
|
description: string
|
|
icon: string
|
|
}
|
|
|
|
export interface CreateTopLevelCourseModuleResponse {
|
|
message: string
|
|
data: TopLevelCourseModuleItem
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown | null
|
|
}
|
|
|
|
/** Row from GET /modules/:moduleId/lessons (Learn English top-level module lessons). */
|
|
export interface TopLevelModuleLessonItem {
|
|
id: number
|
|
module_id: number
|
|
title: string
|
|
video_url: string
|
|
thumbnail: string
|
|
description: string
|
|
sort_order: number
|
|
created_at: string
|
|
}
|
|
|
|
export interface GetTopLevelModuleLessonsResponse {
|
|
message: string
|
|
data: {
|
|
total_count: number
|
|
limit: number
|
|
offset: number
|
|
lessons: TopLevelModuleLessonItem[]
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown | null
|
|
}
|
|
|
|
/** Practice returned by GET /courses|modules|lessons/.../practices (Learn English parent-linked practice). */
|
|
export interface ParentContextPractice {
|
|
id: number
|
|
parent_kind: string
|
|
parent_id: number
|
|
title: string
|
|
story_description: string
|
|
story_image: string
|
|
question_set_id: number
|
|
quick_tips: string
|
|
persona_id?: number | null
|
|
created_at: string
|
|
}
|
|
|
|
export interface GetPracticesByParentContextResponse {
|
|
message: string
|
|
data: {
|
|
offset: number
|
|
limit: number
|
|
practices: ParentContextPractice[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown | null
|
|
}
|
|
|
|
export type PracticeParentKind = "COURSE" | "MODULE" | "LESSON"
|
|
|
|
/** POST /practices — create practice linked to a course, module, or lesson (Learn English). */
|
|
export interface CreateParentLinkedPracticeRequest {
|
|
parent_kind: PracticeParentKind
|
|
parent_id: number
|
|
title: string
|
|
story_description: string
|
|
story_image: string
|
|
question_set_id: number
|
|
quick_tips: string
|
|
persona_id?: number
|
|
}
|
|
|
|
export interface CreateParentLinkedPracticeResponse {
|
|
message: string
|
|
data: ParentContextPractice
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown | null
|
|
}
|
|
|
|
/** Body for PUT /practices/:id (Learn English parent-linked practice). */
|
|
export interface UpdateParentLinkedPracticeRequest {
|
|
title: string
|
|
story_description: string
|
|
story_image: string
|
|
question_set_id: number
|
|
quick_tips: string
|
|
persona_id?: number | null
|
|
}
|
|
|
|
export interface UpdateParentLinkedPracticeResponse {
|
|
message: string
|
|
data: ParentContextPractice
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown | null
|
|
}
|
|
|
|
/** Body for PUT /lessons/:id (Learn English top-level module lessons). */
|
|
export interface UpdateTopLevelModuleLessonRequest {
|
|
title: string
|
|
video_url: string
|
|
thumbnail: string
|
|
description: string
|
|
}
|
|
|
|
/** Body for POST /modules/:moduleId/lessons. */
|
|
export interface CreateTopLevelModuleLessonRequest {
|
|
title: string
|
|
video_url: string
|
|
thumbnail: string
|
|
description: string
|
|
}
|
|
|
|
export interface CreateTopLevelModuleLessonResponse {
|
|
message: string
|
|
data: TopLevelModuleLessonItem
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown | null
|
|
}
|
|
|
|
// ============================================
|
|
// Legacy Types (deprecated - using SubCourse hierarchy now)
|
|
// Keeping for backward compatibility with existing API endpoints
|
|
// ============================================
|
|
|
|
/** @deprecated Use SubCourse instead */
|
|
export interface Program {
|
|
id: number
|
|
course_id: number
|
|
title: string
|
|
description: string
|
|
thumbnail: string
|
|
display_order: number
|
|
is_active: boolean
|
|
}
|
|
|
|
/** @deprecated Use GetSubCoursesResponse instead */
|
|
export interface GetProgramsResponse {
|
|
message: string
|
|
data: {
|
|
programs: Program[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** @deprecated Use UpdateSubCourseStatusRequest instead */
|
|
export interface UpdateProgramStatusRequest {
|
|
is_active: boolean
|
|
}
|
|
|
|
/** @deprecated Use CreateSubCourseRequest instead */
|
|
export interface CreateProgramRequest {
|
|
course_id: number
|
|
title: string
|
|
description: string
|
|
}
|
|
|
|
/** @deprecated Use UpdateSubCourseRequest instead */
|
|
export interface UpdateProgramRequest {
|
|
title: string
|
|
description: string
|
|
is_active: boolean
|
|
}
|
|
|
|
/** @deprecated Use SubCourse instead */
|
|
export interface Level {
|
|
id: number
|
|
program_id: number
|
|
title: string
|
|
description: string
|
|
level_index: number
|
|
number_of_modules: number
|
|
number_of_practices: number
|
|
number_of_videos: number
|
|
is_active: boolean
|
|
}
|
|
|
|
/** @deprecated Use GetSubCoursesResponse instead */
|
|
export interface GetLevelsResponse {
|
|
message: string
|
|
data: {
|
|
levels: Level[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** @deprecated Use CreateSubCourseRequest instead */
|
|
export interface CreateLevelRequest {
|
|
program_id: number
|
|
title: string
|
|
description: string
|
|
}
|
|
|
|
/** @deprecated Use UpdateSubCourseRequest instead */
|
|
export interface UpdateLevelRequest {
|
|
title: string
|
|
description: string
|
|
}
|
|
|
|
/** @deprecated Use UpdateSubCourseStatusRequest instead */
|
|
export interface UpdateLevelStatusRequest {
|
|
is_active: boolean
|
|
}
|
|
|
|
/** @deprecated Use SubCourse hierarchy instead */
|
|
export interface Module {
|
|
id: number
|
|
level_id: number
|
|
title: string
|
|
content: string
|
|
display_order: number
|
|
is_active: boolean
|
|
}
|
|
|
|
/** @deprecated Use GetSubCoursesResponse instead */
|
|
export interface GetModulesResponse {
|
|
message: string
|
|
data: {
|
|
modules: Module[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** @deprecated Use CreateSubCourseRequest instead */
|
|
export interface CreateModuleRequest {
|
|
level_id: number
|
|
title: string
|
|
/** Legacy field kept for backward compatibility. */
|
|
content?: string
|
|
/** Preferred field for module detail text. */
|
|
description?: string
|
|
icon_url?: string
|
|
display_order?: number
|
|
is_active?: boolean
|
|
}
|
|
|
|
/** @deprecated Use UpdateSubCourseRequest instead */
|
|
export interface UpdateModuleRequest {
|
|
title: string
|
|
content: string
|
|
}
|
|
|
|
/** @deprecated Use UpdateSubCourseStatusRequest instead */
|
|
export interface UpdateModuleStatusRequest {
|
|
is_active: boolean
|
|
}
|
|
|
|
// ============================================
|
|
// New Hierarchy: SubCourse (replaces Program/Level/Module)
|
|
// ============================================
|
|
export interface SubCourse {
|
|
id: number
|
|
course_id: number
|
|
/** Present when derived from course hierarchy rows (levels → modules → sub-modules). */
|
|
level_id?: number
|
|
module_id?: number
|
|
title: string
|
|
description: string
|
|
level: string
|
|
cefr_level?: string
|
|
thumbnail: string
|
|
display_order: number
|
|
sub_level?: string
|
|
is_active: boolean
|
|
}
|
|
|
|
export interface GetSubCoursesResponse {
|
|
message: string
|
|
data: {
|
|
sub_courses: SubCourse[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** Compatibility request used to create sub-modules */
|
|
export interface CreateSubCourseRequest {
|
|
course_id: number
|
|
title: string
|
|
description: string
|
|
thumbnail: string
|
|
display_order: number
|
|
level: string
|
|
sub_level: string
|
|
}
|
|
|
|
export interface UpdateSubCourseRequest {
|
|
title: string
|
|
description: string
|
|
level: string
|
|
}
|
|
|
|
export interface UpdateSubCourseStatusRequest {
|
|
is_active: boolean
|
|
level: string
|
|
title: string
|
|
}
|
|
|
|
// SubCourse Video
|
|
export interface SubCourseVideo {
|
|
id: number
|
|
sub_course_id?: number
|
|
sub_module_id?: number
|
|
title: string
|
|
description: string
|
|
video_url: string
|
|
duration: number
|
|
thumbnail: string
|
|
is_published: boolean
|
|
is_active: boolean
|
|
}
|
|
|
|
export interface GetSubCourseVideosResponse {
|
|
message: string
|
|
data: {
|
|
videos: SubCourseVideo[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface CreateSubCourseVideoRequest {
|
|
sub_course_id?: number
|
|
sub_module_id?: number
|
|
title: string
|
|
description: string
|
|
video_url: string
|
|
}
|
|
|
|
export type VideoVisibility = "PUBLISHED" | "DRAFT" | "PRIVATE" | "UNLISTED" | string
|
|
export type VideoStatus = "PUBLISHED" | "DRAFT" | "ARCHIVED" | string
|
|
|
|
export interface CreateCourseVideoRequest {
|
|
sub_course_id?: number
|
|
sub_module_id?: number
|
|
title: string
|
|
description: string
|
|
video_url: string
|
|
duration: number
|
|
resolution?: string
|
|
visibility?: VideoVisibility
|
|
display_order?: number
|
|
status?: VideoStatus
|
|
}
|
|
|
|
export interface CreateVimeoVideoRequest {
|
|
sub_course_id?: number
|
|
sub_module_id?: number
|
|
title: string
|
|
description: string
|
|
source_url: string
|
|
file_size: number
|
|
duration: number
|
|
}
|
|
|
|
export interface UpdateSubCourseVideoRequest {
|
|
title: string
|
|
description: string
|
|
video_url: string
|
|
}
|
|
|
|
// Practice now belongs to SubCourse
|
|
export interface Practice {
|
|
id: number
|
|
sub_course_id?: number
|
|
sub_module_id?: number
|
|
title: string
|
|
description: string
|
|
thumbnail?: string
|
|
intro_video_url?: string
|
|
question_set_id?: number
|
|
banner_image: string
|
|
persona: string
|
|
is_active: boolean
|
|
}
|
|
|
|
export interface GetPracticesResponse {
|
|
message: string
|
|
data: {
|
|
practices: Practice[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface CreatePracticeRequest {
|
|
sub_course_id?: number
|
|
sub_module_id?: number
|
|
title: string
|
|
description: string
|
|
thumbnail?: string
|
|
intro_video_url?: string
|
|
persona?: string
|
|
}
|
|
|
|
export interface UpdatePracticeRequest {
|
|
title: string
|
|
description: string
|
|
persona?: string
|
|
}
|
|
|
|
export interface UpdatePracticeStatusRequest {
|
|
is_active: boolean
|
|
}
|
|
|
|
export interface PracticeQuestion {
|
|
id: number
|
|
practice_id: number
|
|
question: string
|
|
points?: number
|
|
difficulty_level?: string
|
|
question_voice_prompt: string
|
|
sample_answer_voice_prompt: string
|
|
sample_answer: string
|
|
tips: string
|
|
type: "MCQ" | "TRUE_FALSE" | "SHORT" | "AUDIO"
|
|
}
|
|
|
|
export interface GetPracticeQuestionsResponse {
|
|
message: string
|
|
data: {
|
|
questions: PracticeQuestion[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface CreatePracticeQuestionRequest {
|
|
practice_id: number
|
|
question: string
|
|
question_voice_prompt?: string
|
|
sample_answer_voice_prompt?: string
|
|
sample_answer: string
|
|
tips?: string
|
|
explanation?: string
|
|
difficulty_level?: string
|
|
points?: number
|
|
options?: QuestionOption[]
|
|
short_answers?: string[]
|
|
type: "MCQ" | "TRUE_FALSE" | "SHORT"
|
|
}
|
|
|
|
export interface UpdatePracticeQuestionRequest {
|
|
question: string
|
|
question_voice_prompt?: string
|
|
sample_answer_voice_prompt?: string
|
|
sample_answer: string
|
|
tips?: string
|
|
explanation?: string
|
|
difficulty_level?: string
|
|
points?: number
|
|
options?: QuestionOption[]
|
|
short_answers?: string[]
|
|
type: "MCQ" | "TRUE_FALSE" | "SHORT"
|
|
}
|
|
|
|
// Question Sets (Practice sets fetched via /question-sets)
|
|
export type QuestionSetType = "PRACTICE" | "EXAM"
|
|
export type QuestionSetStatus = "PUBLISHED" | "DRAFT" | "ARCHIVED"
|
|
export type QuestionSetOwnerType = "SUB_COURSE" | "SUB_MODULE" | "COURSE"
|
|
|
|
export interface QuestionSet {
|
|
id: number
|
|
title: string
|
|
description: string
|
|
set_type: QuestionSetType
|
|
owner_type: QuestionSetOwnerType
|
|
owner_id: number
|
|
persona: string
|
|
shuffle_questions: boolean
|
|
status: QuestionSetStatus
|
|
created_at: string
|
|
}
|
|
|
|
export interface GetQuestionSetsResponse {
|
|
message: string
|
|
data: QuestionSet[] | { question_sets: QuestionSet[]; total_count?: number }
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface GetQuestionSetsParams {
|
|
set_type?: "PRACTICE" | "INITIAL_ASSESSMENT" | "EXAM" | string
|
|
owner_type?: "SUB_COURSE" | "SUB_MODULE" | "COURSE" | string
|
|
owner_id?: number
|
|
status?: "DRAFT" | "PUBLISHED" | "ARCHIVED" | string
|
|
limit?: number
|
|
offset?: number
|
|
}
|
|
|
|
export interface QuestionSetDetail {
|
|
id: number
|
|
title: string
|
|
description: string
|
|
set_type: string
|
|
owner_type: string
|
|
owner_id: number
|
|
banner_image?: string | null
|
|
persona?: string | null
|
|
time_limit_minutes?: number | null
|
|
passing_score?: number | null
|
|
shuffle_questions?: boolean
|
|
status: string
|
|
sub_course_video_id?: number | null
|
|
intro_video_url?: string | null
|
|
created_at: string
|
|
question_count: number
|
|
}
|
|
|
|
export interface GetQuestionSetDetailResponse {
|
|
message: string
|
|
data: QuestionSetDetail
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface QuestionSetQuestion {
|
|
id: number
|
|
set_id: number
|
|
question_id: number
|
|
display_order: number
|
|
question_text: string
|
|
question_type: "MCQ" | "TRUE_FALSE" | "SHORT" | "SHORT_ANSWER" | "AUDIO" | string
|
|
difficulty_level?: string | null
|
|
points?: number
|
|
explanation?: string | null
|
|
tips?: string | null
|
|
voice_prompt?: string | null
|
|
sample_answer_voice_prompt?: string | null
|
|
image_url?: string | null
|
|
audio_correct_answer_text?: string | null
|
|
question_status?: string
|
|
}
|
|
|
|
export interface GetQuestionSetQuestionsResponse {
|
|
message: string
|
|
data: QuestionSetQuestion[]
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface GetPracticeQuestionsByPracticeResponse {
|
|
message: string
|
|
data: {
|
|
questions: QuestionSetQuestion[]
|
|
total_count: number
|
|
limit: number
|
|
offset: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** POST /question-sets — practices use set_type: "PRACTICE", owner_type: "SUB_COURSE", owner_id: sub-course id */
|
|
export interface CreateQuestionSetRequest {
|
|
title: string
|
|
set_type: string
|
|
description?: string | null
|
|
owner_type?: string | null
|
|
owner_id?: number | null
|
|
banner_image?: string | null
|
|
persona?: string | null
|
|
time_limit_minutes?: number | null
|
|
passing_score?: number | null
|
|
shuffle_questions?: boolean | null
|
|
status?: string | null
|
|
sub_course_video_id?: number | null
|
|
intro_video_url?: string | null
|
|
}
|
|
|
|
export interface AddQuestionToSetRequest {
|
|
display_order?: number
|
|
question_id: number
|
|
}
|
|
|
|
export interface QuestionOption {
|
|
option_order: number
|
|
option_text: string
|
|
is_correct: boolean
|
|
}
|
|
|
|
export interface CreateQuestionRequest {
|
|
question_text: string
|
|
question_type: string
|
|
difficulty_level?: string
|
|
points?: number
|
|
tips?: string
|
|
explanation?: string
|
|
status?: string
|
|
image_url?: string
|
|
options?: QuestionOption[]
|
|
voice_prompt?: string
|
|
sample_answer_voice_prompt?: string
|
|
audio_correct_answer_text?: string
|
|
short_answers?: string[] | { acceptable_answer: string; match_type: "EXACT" | "CASE_INSENSITIVE" }[]
|
|
}
|
|
|
|
export interface CreateQuestionResponse {
|
|
message: string
|
|
data: {
|
|
id: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface QuestionShortAnswer {
|
|
acceptable_answer: string
|
|
match_type?: "EXACT" | "CASE_INSENSITIVE" | string
|
|
}
|
|
|
|
export interface QuestionDetail {
|
|
id: number
|
|
question_text: string
|
|
question_type: "MCQ" | "TRUE_FALSE" | "SHORT_ANSWER" | "SHORT" | string
|
|
difficulty_level?: string | null
|
|
points?: number | null
|
|
status?: string
|
|
created_at?: string
|
|
options?: ({ id?: number } & QuestionOption)[]
|
|
short_answers?: string[] | QuestionShortAnswer[]
|
|
tips?: string | null
|
|
explanation?: string | null
|
|
image_url?: string | null
|
|
voice_prompt?: string | null
|
|
sample_answer_voice_prompt?: string | null
|
|
audio_correct_answer_text?: string | null
|
|
}
|
|
|
|
export interface GetQuestionDetailResponse {
|
|
message: string
|
|
data: QuestionDetail
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface GetQuestionsParams {
|
|
question_type?: "MCQ" | "TRUE_FALSE" | "SHORT_ANSWER" | "AUDIO" | string
|
|
difficulty?: "EASY" | "MEDIUM" | "HARD" | string
|
|
status?: "DRAFT" | "PUBLISHED" | "INACTIVE" | string
|
|
limit?: number
|
|
offset?: number
|
|
}
|
|
|
|
export interface GetQuestionsResponse {
|
|
message: string
|
|
data: QuestionDetail[] | { questions: QuestionDetail[]; total_count?: number }
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface CreateQuestionSetResponse {
|
|
message: string
|
|
data: {
|
|
id: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
// Sub-course Prerequisites
|
|
export interface SubCoursePrerequisite {
|
|
id: number
|
|
sub_course_id: number
|
|
prerequisite_sub_course_id: number
|
|
prerequisite_title: string
|
|
prerequisite_level: string
|
|
prerequisite_display_order: number
|
|
}
|
|
|
|
export interface GetSubCoursePrerequisitesResponse {
|
|
message: string
|
|
data: SubCoursePrerequisite[]
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface AddSubCoursePrerequisiteRequest {
|
|
prerequisite_sub_course_id: number
|
|
}
|
|
|
|
// Learning Path (full tree from GET /courses/:courseId/learning-path)
|
|
export interface LearningPathSubCourse {
|
|
id: number
|
|
title: string
|
|
description: string
|
|
thumbnail: string
|
|
display_order: number
|
|
level: string
|
|
sub_level?: string
|
|
prerequisite_count: number
|
|
video_count: number
|
|
practice_count: number
|
|
prerequisites: { sub_course_id: number; title: string; level: string }[]
|
|
videos: LearningPathVideo[]
|
|
practices: LearningPathPractice[]
|
|
}
|
|
|
|
export interface LearningPathVideo {
|
|
id: number
|
|
title: string
|
|
display_order: number
|
|
duration: number
|
|
video_url: string
|
|
}
|
|
|
|
export interface LearningPathPractice {
|
|
id: number
|
|
title: string
|
|
status: string
|
|
question_count: number
|
|
display_order?: number
|
|
}
|
|
|
|
export interface LearningPath {
|
|
course_id: number
|
|
course_title: string
|
|
description: string
|
|
thumbnail: string
|
|
intro_video_url: string
|
|
category_id: number
|
|
category_name: string
|
|
sub_courses: LearningPathSubCourse[]
|
|
}
|
|
|
|
export interface GetLearningPathResponse {
|
|
message: string
|
|
data: LearningPath
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface HumanLanguageLesson {
|
|
id: number
|
|
course_id: number
|
|
title: string
|
|
description?: string | null
|
|
thumbnail?: string | null
|
|
display_order: number
|
|
level: string
|
|
video_count: number
|
|
practice_count: number
|
|
videos: LearningPathVideo[]
|
|
practices: LearningPathPractice[]
|
|
}
|
|
|
|
export interface SubModuleLessonDetail {
|
|
id: number
|
|
sub_module_id: number
|
|
display_order: number
|
|
is_active: boolean
|
|
created_at: string
|
|
title: string
|
|
description?: string | null
|
|
thumbnail?: string | null
|
|
teaching_text?: string | null
|
|
teaching_image_url?: string | null
|
|
teaching_audio_url?: string | null
|
|
teaching_video_url?: string | null
|
|
}
|
|
|
|
export interface SubModuleLesson {
|
|
id: number
|
|
sub_module_id: number
|
|
display_order: number
|
|
is_active: boolean
|
|
created_at: string
|
|
title: string
|
|
description?: string | null
|
|
thumbnail?: string | null
|
|
teaching_text?: string | null
|
|
teaching_image_url?: string | null
|
|
teaching_audio_url?: string | null
|
|
teaching_video_url?: string | null
|
|
}
|
|
|
|
export interface GetSubModuleLessonDetailResponse {
|
|
message: string
|
|
data: SubModuleLessonDetail
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface UpdateSubModuleLessonRequest {
|
|
title: string
|
|
description?: string | null
|
|
thumbnail?: string | null
|
|
teaching_text?: string | null
|
|
teaching_image_url?: string | null
|
|
teaching_audio_url?: string | null
|
|
teaching_video_url?: string | null
|
|
display_order: number
|
|
is_active: boolean
|
|
}
|
|
|
|
export interface UpdateSubModuleLessonResponse {
|
|
message: string
|
|
data: SubModuleLessonDetail
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface GetSubModuleLessonsResponse {
|
|
message: string
|
|
data: SubModuleLesson[]
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface GetHumanLanguageLessonsResponse {
|
|
message: string
|
|
data: {
|
|
course_id: number
|
|
course_title: string
|
|
cefr_level: string
|
|
lessons: HumanLanguageLesson[]
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** Row from GET /course-management/human-language/sub-categories */
|
|
export interface HumanLanguageSubCategoryListItem {
|
|
id: number
|
|
category_id: number
|
|
category_name: string
|
|
name: string
|
|
description?: string | null
|
|
display_order: number
|
|
is_active: boolean
|
|
created_at: string
|
|
/** Present on some payloads; ignore if unused. */
|
|
total_count?: number
|
|
}
|
|
|
|
export interface GetHumanLanguageSubCategoriesResponse {
|
|
message: string
|
|
data: {
|
|
sub_categories: HumanLanguageSubCategoryListItem[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** Row from GET /course-management/categories/:categoryId/sub-categories */
|
|
export interface CategorySubCategoryListItem {
|
|
id: number
|
|
category_id: number
|
|
category_name: string
|
|
name: string
|
|
description?: string | null
|
|
display_order: number
|
|
is_active: boolean
|
|
created_at: string
|
|
/** Sometimes echoed per row by the API; safe to ignore. */
|
|
total_count?: number
|
|
}
|
|
|
|
export interface GetCategorySubCategoriesResponse {
|
|
message: string
|
|
data: {
|
|
sub_categories: CategorySubCategoryListItem[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** Row from GET /course-management/sub-categories/:subCategoryId/courses */
|
|
export interface SubCategoryCourseListItem {
|
|
id: number
|
|
category_id: number
|
|
sub_category_id: number
|
|
title: string
|
|
description?: string | null
|
|
thumbnail?: string | null
|
|
intro_video_url?: string | null
|
|
is_active: boolean
|
|
total_count?: number
|
|
}
|
|
|
|
export interface GetSubCategoryCoursesResponse {
|
|
message: string
|
|
data: {
|
|
courses: SubCategoryCourseListItem[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** Row from GET /course-management/courses/:courseId/levels or GET /course-management/levels */
|
|
export interface CourseLevelRow {
|
|
id: number
|
|
course_id: number
|
|
cefr_level: string
|
|
display_order: number
|
|
is_active: boolean
|
|
created_at: string
|
|
title: string
|
|
description?: string | null
|
|
thumbnail?: string | null
|
|
total_count?: number
|
|
}
|
|
|
|
export interface GetCourseLevelsForCourseResponse {
|
|
message: string
|
|
data: {
|
|
levels: CourseLevelRow[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface GetCourseLevelsAllResponse {
|
|
message: string
|
|
data: {
|
|
levels: CourseLevelRow[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface GetCourseLevelByIdResponse {
|
|
message: string
|
|
data: CourseLevelRow
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** Row from GET /course-management/modules/:moduleId/sub-modules */
|
|
export interface CourseSubModuleListItem {
|
|
id: number
|
|
module_id: number
|
|
title: string
|
|
description?: string | null
|
|
display_order: number
|
|
is_active: boolean
|
|
created_at: string
|
|
legacy_sub_course_id?: number | null
|
|
thumbnail?: string | null
|
|
tips?: string | null
|
|
total_count?: number
|
|
}
|
|
|
|
export interface GetSubModulesByModuleResponse {
|
|
message: string
|
|
data: {
|
|
sub_modules: CourseSubModuleListItem[]
|
|
total_count: number
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** Row from GET /course-management/human-language/hierarchy */
|
|
export interface HumanLanguageHierarchyFlatRow {
|
|
category_id: number
|
|
category_name: string
|
|
sub_category_id?: number | null
|
|
sub_category_name?: string | null
|
|
course_id?: number | null
|
|
course_title?: string | null
|
|
}
|
|
|
|
export interface GetHumanLanguageHierarchyFlatResponse {
|
|
message: string
|
|
data: HumanLanguageHierarchyFlatRow[]
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
/** Row from GET /course-management/courses/:courseId/hierarchy */
|
|
export interface CourseHierarchyRow {
|
|
course_id: number
|
|
course_title: string
|
|
level_id?: number | null
|
|
cefr_level?: string | null
|
|
level_title?: string | null
|
|
level_description?: string | null
|
|
level_thumbnail?: string | null
|
|
module_id?: number | null
|
|
module_title?: string | null
|
|
module_icon_url?: string | null
|
|
sub_module_id?: number | null
|
|
sub_module_title?: string | null
|
|
sub_module_description?: string | null
|
|
sub_module_thumbnail?: string | null
|
|
sub_module_tips?: string | null
|
|
sub_module_display_order?: number | null
|
|
}
|
|
|
|
export interface GetCourseHierarchyResponse {
|
|
message: string
|
|
data: CourseHierarchyRow[]
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface HumanLanguageSubModule {
|
|
id: number
|
|
title: string
|
|
videos: LearningPathVideo[]
|
|
lessons?: {
|
|
id: number
|
|
question_set_id: number
|
|
title: string
|
|
status: string
|
|
question_count: number
|
|
display_order: number
|
|
intro_video_url?: string | null
|
|
}[]
|
|
practices: LearningPathPractice[]
|
|
}
|
|
|
|
export interface HumanLanguageModule {
|
|
id: number
|
|
title: string
|
|
sub_modules: HumanLanguageSubModule[]
|
|
}
|
|
|
|
export interface HumanLanguageLevelTree {
|
|
level_id?: number
|
|
level: string
|
|
modules: HumanLanguageModule[]
|
|
}
|
|
|
|
export interface HumanLanguageCourseTree {
|
|
course_id: number
|
|
course_name: string
|
|
levels: HumanLanguageLevelTree[]
|
|
}
|
|
|
|
export interface HumanLanguageSubCategoryTree {
|
|
sub_category_id: number
|
|
sub_category_name: string
|
|
courses: HumanLanguageCourseTree[]
|
|
}
|
|
|
|
export interface GetHumanLanguageHierarchyResponse {
|
|
message: string
|
|
data: {
|
|
category_id: number
|
|
category_name: string
|
|
sub_categories: HumanLanguageSubCategoryTree[]
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface CreateHumanLanguageLessonRequest {
|
|
course_id: number
|
|
title: string
|
|
description?: string
|
|
thumbnail?: string
|
|
display_order?: number
|
|
cefr_level: string
|
|
}
|
|
|
|
export interface GetSubCourseEntryAssessmentResponse {
|
|
message: string
|
|
data: QuestionSet | null
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
export interface ReorderItem {
|
|
id: number
|
|
position: number
|
|
}
|
|
|
|
// Ratings
|
|
export interface Rating {
|
|
id: number
|
|
user_id: number
|
|
target_type: string
|
|
target_id: number
|
|
stars: number
|
|
review: string
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export interface GetRatingsParams {
|
|
target_type: string
|
|
target_id: number
|
|
limit?: number
|
|
offset?: number
|
|
}
|
|
|
|
export interface GetRatingsResponse {
|
|
message: string
|
|
data: Rating[]
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|
|
|
|
// Vimeo Sample Video
|
|
export interface VimeoSampleVideo {
|
|
vimeo_id: string
|
|
uri: string
|
|
name: string
|
|
description: string
|
|
duration: number
|
|
width: number
|
|
height: number
|
|
link: string
|
|
embed_url: string
|
|
embed_html: string
|
|
thumbnail_url: string
|
|
status: string
|
|
transcode_status: string
|
|
}
|
|
|
|
export interface GetVimeoSampleResponse {
|
|
message: string
|
|
data: {
|
|
video: VimeoSampleVideo
|
|
iframe: string
|
|
}
|
|
success: boolean
|
|
status_code: number
|
|
metadata: unknown
|
|
}
|