feat: Implement student course management functionalities and standardize multi-language text types across course and category definitions.
This commit is contained in:
parent
d97569acbc
commit
4c9ad1cea7
6 changed files with 673 additions and 57 deletions
|
|
@ -1,17 +1,12 @@
|
|||
import { Course, Prisma, User } from '@prisma/client';
|
||||
import { MultiLanguageText } from './index';
|
||||
|
||||
// Custom type for TSOA - avoiding complex Prisma types
|
||||
export interface CreateCourseInput {
|
||||
category_id?: number;
|
||||
title: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
title: MultiLanguageText;
|
||||
slug: string;
|
||||
description: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
description: MultiLanguageText;
|
||||
thumbnail_url?: string;
|
||||
price?: number;
|
||||
is_free?: boolean;
|
||||
|
|
@ -48,15 +43,9 @@ export interface getmyCourse {
|
|||
|
||||
export interface UpdateCourseInput {
|
||||
category_id?: number;
|
||||
title?: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
title?: MultiLanguageText;
|
||||
slug?: string;
|
||||
description?: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
description?: MultiLanguageText;
|
||||
thumbnail_url?: string;
|
||||
price?: number;
|
||||
is_free?: boolean;
|
||||
|
|
@ -151,4 +140,3 @@ export interface sendCourseForReview {
|
|||
token: string;
|
||||
course_id: number;
|
||||
}
|
||||
|
||||
289
Backend/src/types/CoursesStudent.types.ts
Normal file
289
Backend/src/types/CoursesStudent.types.ts
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
import { Course, Lesson, Chapter, LessonAttachment, Quiz, LessonProgress, EnrollmentStatus } from '@prisma/client';
|
||||
import { MultiLanguageText } from './index';
|
||||
|
||||
// Use MultiLanguageText from index.ts for consistency
|
||||
export type MultiLangText = MultiLanguageText;
|
||||
|
||||
// ============================================
|
||||
// Enrollment Types
|
||||
// ============================================
|
||||
|
||||
export interface EnrollCourseInput {
|
||||
token: string;
|
||||
course_id: number;
|
||||
}
|
||||
|
||||
export interface EnrollCourseResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
data?: {
|
||||
enrollment_id: number;
|
||||
course_id: number;
|
||||
user_id: number;
|
||||
status: EnrollmentStatus;
|
||||
enrolled_at: Date;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ListEnrolledCoursesInput {
|
||||
token: string;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
status?: EnrollmentStatus;
|
||||
}
|
||||
|
||||
export interface EnrolledCourseItem {
|
||||
id: number;
|
||||
course_id: number;
|
||||
course: {
|
||||
id: number;
|
||||
title: MultiLangText;
|
||||
slug: string;
|
||||
thumbnail_url: string | null;
|
||||
description: MultiLangText;
|
||||
};
|
||||
status: EnrollmentStatus;
|
||||
progress_percentage: number;
|
||||
enrolled_at: Date;
|
||||
started_at: Date | null;
|
||||
completed_at: Date | null;
|
||||
last_accessed_at: Date | null;
|
||||
}
|
||||
|
||||
export interface ListEnrolledCoursesResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
data: EnrolledCourseItem[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Course Learning Page Types
|
||||
// ============================================
|
||||
|
||||
export interface GetCourseLearningInput {
|
||||
token: string;
|
||||
course_id: number;
|
||||
}
|
||||
|
||||
export interface LessonWithLockStatus {
|
||||
id: number;
|
||||
chapter_id: number;
|
||||
title: MultiLangText;
|
||||
type: 'VIDEO' | 'QUIZ';
|
||||
duration_minutes: number | null;
|
||||
sort_order: number;
|
||||
is_published: boolean;
|
||||
is_sequential: boolean;
|
||||
prerequisite_lesson_ids: number[] | null;
|
||||
require_pass_quiz: boolean;
|
||||
// Lock status
|
||||
is_locked: boolean;
|
||||
lock_reason?: string;
|
||||
// Progress
|
||||
is_completed: boolean;
|
||||
video_progress_percentage?: number;
|
||||
}
|
||||
|
||||
export interface ChapterWithLessons {
|
||||
id: number;
|
||||
title: MultiLangText;
|
||||
description: MultiLangText | null;
|
||||
sort_order: number;
|
||||
is_published: boolean;
|
||||
lessons: LessonWithLockStatus[];
|
||||
}
|
||||
|
||||
export interface GetCourseLearningResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
data: {
|
||||
course: {
|
||||
id: number;
|
||||
title: MultiLangText;
|
||||
slug: string;
|
||||
description: MultiLangText;
|
||||
thumbnail_url: string | null;
|
||||
have_certificate: boolean;
|
||||
};
|
||||
enrollment: {
|
||||
status: EnrollmentStatus;
|
||||
progress_percentage: number;
|
||||
enrolled_at: Date;
|
||||
started_at: Date | null;
|
||||
completed_at: Date | null;
|
||||
};
|
||||
chapters: ChapterWithLessons[];
|
||||
total_lessons: number;
|
||||
completed_lessons: number;
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Lesson Content Types
|
||||
// ============================================
|
||||
|
||||
export interface GetLessonContentInput {
|
||||
token: string;
|
||||
course_id: number;
|
||||
lesson_id: number;
|
||||
}
|
||||
|
||||
export interface LessonContentData {
|
||||
id: number;
|
||||
chapter_id: number;
|
||||
title: MultiLangText;
|
||||
content: MultiLangText | null;
|
||||
type: 'VIDEO' | 'QUIZ';
|
||||
duration_minutes: number | null;
|
||||
is_sequential: boolean;
|
||||
prerequisite_lesson_ids: number[] | null;
|
||||
require_pass_quiz: boolean;
|
||||
attachments: {
|
||||
id: number;
|
||||
file_name: string;
|
||||
file_path: string;
|
||||
file_size: number;
|
||||
mime_type: string;
|
||||
description: MultiLangText | null;
|
||||
}[];
|
||||
quiz?: {
|
||||
id: number;
|
||||
title: MultiLangText;
|
||||
description: MultiLangText | null;
|
||||
passing_score: number;
|
||||
time_limit: number | null;
|
||||
shuffle_questions: boolean;
|
||||
shuffle_choices: boolean;
|
||||
} | null;
|
||||
// Navigation
|
||||
prev_lesson_id: number | null;
|
||||
next_lesson_id: number | null;
|
||||
}
|
||||
|
||||
export interface GetLessonContentResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
data: LessonContentData;
|
||||
progress?: {
|
||||
is_completed: boolean;
|
||||
video_progress_seconds: number;
|
||||
video_duration_seconds: number | null;
|
||||
video_progress_percentage: number | null;
|
||||
last_watched_at: Date | null;
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Lesson Access Check Types
|
||||
// ============================================
|
||||
|
||||
export interface CheckLessonAccessInput {
|
||||
token: string;
|
||||
course_id: number;
|
||||
lesson_id: number;
|
||||
}
|
||||
|
||||
export interface CheckLessonAccessResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
data: {
|
||||
is_accessible: boolean;
|
||||
is_enrolled: boolean;
|
||||
is_locked: boolean;
|
||||
lock_reason?: string;
|
||||
required_lessons?: {
|
||||
id: number;
|
||||
title: MultiLangText;
|
||||
is_completed: boolean;
|
||||
}[];
|
||||
required_quiz_pass?: {
|
||||
lesson_id: number;
|
||||
quiz_id: number;
|
||||
title: MultiLangText;
|
||||
is_passed: boolean;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Video Progress Types
|
||||
// ============================================
|
||||
|
||||
export interface SaveVideoProgressInput {
|
||||
token: string;
|
||||
lesson_id: number;
|
||||
video_progress_seconds: number;
|
||||
video_duration_seconds?: number;
|
||||
}
|
||||
|
||||
export interface SaveVideoProgressResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
data?: {
|
||||
lesson_id: number;
|
||||
video_progress_seconds: number;
|
||||
video_duration_seconds: number | null;
|
||||
video_progress_percentage: number | null;
|
||||
is_completed: boolean;
|
||||
last_watched_at: Date;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GetVideoProgressInput {
|
||||
token: string;
|
||||
lesson_id: number;
|
||||
}
|
||||
|
||||
export interface GetVideoProgressResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
data: {
|
||||
lesson_id: number;
|
||||
video_progress_seconds: number;
|
||||
video_duration_seconds: number | null;
|
||||
video_progress_percentage: number | null;
|
||||
is_completed: boolean;
|
||||
completed_at: Date | null;
|
||||
last_watched_at: Date | null;
|
||||
} | null;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Lesson Completion Types
|
||||
// ============================================
|
||||
|
||||
export interface MarkLessonCompleteInput {
|
||||
token: string;
|
||||
course_id: number;
|
||||
lesson_id: number;
|
||||
}
|
||||
|
||||
export interface MarkLessonCompleteResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
data?: {
|
||||
lesson_id: number;
|
||||
is_completed: boolean;
|
||||
completed_at: Date;
|
||||
course_progress_percentage: number;
|
||||
is_course_completed: boolean;
|
||||
next_lesson_id: number | null;
|
||||
certificate_issued?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Request Body Types (for TSOA)
|
||||
// ============================================
|
||||
|
||||
export interface SaveVideoProgressBody {
|
||||
video_progress_seconds: number;
|
||||
video_duration_seconds?: number;
|
||||
}
|
||||
|
||||
export interface EnrollCourseBody {
|
||||
course_id: number;
|
||||
}
|
||||
|
|
@ -1,14 +1,10 @@
|
|||
import { MultiLanguageText } from './index';
|
||||
|
||||
export interface Category {
|
||||
id: number;
|
||||
name: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
name: MultiLanguageText;
|
||||
slug: string;
|
||||
description: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
description: MultiLanguageText;
|
||||
icon: string | null;
|
||||
sort_order: number;
|
||||
is_active: boolean;
|
||||
|
|
@ -26,15 +22,9 @@ export interface listCategoriesResponse {
|
|||
}
|
||||
|
||||
export interface createCategory {
|
||||
name: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
name: MultiLanguageText;
|
||||
slug: string;
|
||||
description: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
description: MultiLanguageText;
|
||||
created_by: number;
|
||||
}
|
||||
|
||||
|
|
@ -43,43 +33,25 @@ export interface createCategoryResponse {
|
|||
message: string;
|
||||
data: {
|
||||
id: number;
|
||||
name: {
|
||||
en: string;
|
||||
th: string;
|
||||
};
|
||||
name: MultiLanguageText;
|
||||
slug: string;
|
||||
description: {
|
||||
en: string;
|
||||
th: string;
|
||||
};
|
||||
description: MultiLanguageText;
|
||||
created_by: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface updateCategory {
|
||||
id: number;
|
||||
name: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
name: MultiLanguageText;
|
||||
slug: string;
|
||||
description: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
description: MultiLanguageText;
|
||||
}
|
||||
|
||||
export interface updateCategoryResponse {
|
||||
id: number;
|
||||
name: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
name: MultiLanguageText;
|
||||
slug: string;
|
||||
description: {
|
||||
th: string;
|
||||
en: string;
|
||||
};
|
||||
description: MultiLanguageText;
|
||||
updated_by: number;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export interface MultiLanguageText {
|
||||
[key: string]: string;
|
||||
th: string;
|
||||
en: string;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue