feat: student page and create email verification page.

This commit is contained in:
Missez 2026-02-03 17:13:30 +07:00
parent 52d86400b3
commit e8a10e5024
6 changed files with 894 additions and 8 deletions

View file

@ -80,6 +80,88 @@ export interface SearchInstructorsResponse {
data: SearchInstructorResult[];
}
export interface EnrolledStudentResponse {
user_id: number;
username: string;
email: string;
first_name: string;
last_name: string;
avatar_url: string | null;
enrolled_at: string;
progress_percentage: number;
status: 'ENROLLED' | 'COMPLETED' | 'DROPPED';
}
export interface EnrolledStudentsListResponse {
code: number;
message: string;
data: EnrolledStudentResponse[];
total: number;
page: number;
limit: number;
}
export interface StudentSearchResult {
user_id: number;
first_name: string;
last_name: string;
email: string;
}
export interface StudentSearchResponse {
code: number;
message: string;
data: StudentSearchResult[];
}
// Student Detail with Progress interfaces
export interface StudentDetailLesson {
lesson_id: number;
lesson_title: { th: string; en: string };
lesson_type: string;
sort_order: number;
is_completed: boolean;
completed_at: string | null;
video_progress_seconds: number;
video_duration_seconds: number;
video_progress_percentage: number;
last_watched_at: string | null;
}
export interface StudentDetailChapter {
chapter_id: number;
chapter_title: { th: string; en: string };
sort_order: number;
lessons: StudentDetailLesson[];
completed_lessons: number;
total_lessons: number;
}
export interface StudentDetailData {
student: {
user_id: number;
username: string;
email: string;
first_name: string;
last_name: string;
avatar_url: string | null;
};
enrollment: {
status: string;
progress_percentage: number;
enrolled_at: string;
};
chapters: StudentDetailChapter[];
total_completed_lessons: number;
total_lessons: number;
}
export interface StudentDetailResponse {
code: number;
message: string;
data: StudentDetailData;
}
// Helper function to get auth token from cookie
const getAuthToken = (): string => {
const tokenCookie = useCookie('token');
@ -212,6 +294,37 @@ export const instructorService = {
return await authRequest<ApiResponse<void>>(`/api/instructors/courses/send-review/${courseId}`, { method: 'POST' });
},
async getEnrolledStudents(
courseId: number,
page: number = 1,
limit: number = 10,
search?: string,
status?: string
): Promise<EnrolledStudentsListResponse> {
let url = `/api/instructors/courses/${courseId}/students?page=${page}&limit=${limit}`;
if (search) {
url += `&search=${encodeURIComponent(search)}`;
}
if (status && status !== 'all') {
url += `&status=${status}`;
}
return await authRequest<EnrolledStudentsListResponse>(url);
},
async searchStudentsInCourse(courseId: number, query: string, limit: number = 5): Promise<StudentSearchResult[]> {
const response = await authRequest<StudentSearchResponse>(
`/api/instructors/courses/${courseId}/students/search?query=${encodeURIComponent(query)}&limit=${limit}`
);
return response.data;
},
async getStudentDetail(courseId: number, studentId: number): Promise<StudentDetailData> {
const response = await authRequest<StudentDetailResponse>(
`/api/instructors/courses/${courseId}/students/${studentId}`
);
return response.data;
},
async getChapters(courseId: number): Promise<ChapterResponse[]> {
// Get chapters from course detail endpoint
const response = await authRequest<{ code: number; data: { chapters: ChapterResponse[] } }>(
@ -515,6 +628,7 @@ export interface QuizResponse {
shuffle_questions: boolean;
shuffle_choices: boolean;
show_answers_after_completion: boolean;
is_skippable: boolean;
created_at?: string;
updated_at?: string;
questions?: QuizQuestionResponse[];
@ -528,6 +642,7 @@ export interface UpdateQuizSettingsRequest {
shuffle_questions: boolean;
shuffle_choices: boolean;
show_answers_after_completion: boolean;
is_skippable: boolean;
}
export interface CreateChapterRequest {
@ -562,6 +677,7 @@ export interface CreateLessonRequest {
export interface UpdateLessonRequest {
title: { th: string; en: string };
content?: { th: string; en: string } | null;
prerequisite_lesson_ids?: number[] | null;
}
export interface AttachmentResponse {