// API Response structure for user list export interface AdminUserResponse { id: number; username: string; email: string; created_at: string; updated_at: string; role: { code: string; name: { en: string; th: string; }; }; profile: { prefix: { en: string; th: string; }; first_name: string; last_name: string; avatar_url: string | null; birth_date: string | null; phone: string | null; }; } export interface UsersListResponse { code: number; message: string; data: AdminUserResponse[]; } // Pending Course interfaces export interface PendingCourseUser { id: number; email: string; username: string; } export interface PendingCourseInstructor { user_id: number; is_primary: boolean; user: PendingCourseUser; } export interface PendingCourseSubmission { id: number; submitted_by: number; created_at: string; submitter: PendingCourseUser; } export interface PendingCourse { id: number; title: { th: string; en: string; }; slug: string; description: { th: string; en: string; }; thumbnail_url: string | null; status: string; created_at: string; updated_at: string; created_by: number; creator: PendingCourseUser; instructors: PendingCourseInstructor[]; chapters_count: number; lessons_count: number; latest_submission: PendingCourseSubmission | null; } export interface PendingCoursesListResponse { code: number; message: string; data: PendingCourse[]; total: number; } // Course Detail interfaces for admin review export interface CourseCategory { id: number; name: { th: string; en: string; }; } export interface CourseLesson { id: number; title: { th: string; en: string; }; type: string; sort_order: number; is_published: boolean; } export interface CourseChapter { id: number; title: { th: string; en: string; }; sort_order: number; is_published: boolean; lessons: CourseLesson[]; } export interface ApprovalHistory { id: number; action: string; comment: string | null; created_at: string; submitter: PendingCourseUser; reviewer: PendingCourseUser | null; } export interface CourseDetailForReview { id: number; title: { th: string; en: string; }; slug: string; description: { th: string; en: string; }; thumbnail_url: string | null; price: number; is_free: boolean; have_certificate: boolean; status: string; created_at: string; updated_at: string; category: CourseCategory; creator: PendingCourseUser; instructors: PendingCourseInstructor[]; chapters: CourseChapter[]; approval_history: ApprovalHistory[]; } export interface CourseDetailForReviewResponse { code: number; message: string; data: CourseDetailForReview; } // Mock data for development const MOCK_USERS: AdminUserResponse[] = [ { id: 1, username: 'admin', email: 'admin@elearning.local', created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', role: { code: 'ADMIN', name: { en: 'Administrator', th: 'ผู้ดูแลระบบ' } }, profile: { prefix: { en: 'Mr.', th: 'นาย' }, first_name: 'Admin', last_name: 'User', avatar_url: null, birth_date: null, phone: '0812345678' } }, { id: 2, username: 'instructor', email: 'instructor@elearning.local', created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', role: { code: 'INSTRUCTOR', name: { en: 'Instructor', th: 'ผู้สอน' } }, profile: { prefix: { en: 'Mr.', th: 'นาย' }, first_name: 'John', last_name: 'Instructor', avatar_url: null, birth_date: null, phone: '0812345679' } }, { id: 3, username: 'student', email: 'student@elearning.local', created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', role: { code: 'STUDENT', name: { en: 'Student', th: 'นักเรียน' } }, profile: { prefix: { en: 'Ms.', th: 'นางสาว' }, first_name: 'Jane', last_name: 'Student', avatar_url: null, birth_date: null, phone: '0812345680' } } ]; // Mock pending courses data const MOCK_PENDING_COURSES: PendingCourse[] = [ { id: 1, title: { th: 'พื้นฐาน JavaScript', en: 'JavaScript Fundamentals' }, slug: 'javascript-fundamentals', description: { th: 'เรียนรู้ JavaScript ตั้งแต่เริ่มต้น', en: 'Learn JavaScript from scratch' }, thumbnail_url: null, status: 'PENDING', created_at: '2024-02-01T00:00:00Z', updated_at: '2024-02-10T00:00:00Z', created_by: 2, creator: { id: 2, email: 'instructor@elearning.local', username: 'instructor' }, instructors: [ { user_id: 2, is_primary: true, user: { id: 2, email: 'instructor@elearning.local', username: 'instructor' } } ], chapters_count: 5, lessons_count: 15, latest_submission: { id: 1, submitted_by: 2, created_at: '2024-02-10T00:00:00Z', submitter: { id: 2, email: 'instructor@elearning.local', username: 'instructor' } } }, { id: 2, title: { th: 'React สำหรับผู้เริ่มต้น', en: 'React for Beginners' }, slug: 'react-for-beginners', description: { th: 'เรียนรู้ React ตั้งแต่พื้นฐาน', en: 'Learn React from basics' }, thumbnail_url: null, status: 'PENDING', created_at: '2024-02-05T00:00:00Z', updated_at: '2024-02-12T00:00:00Z', created_by: 2, creator: { id: 2, email: 'instructor@elearning.local', username: 'instructor' }, instructors: [ { user_id: 2, is_primary: true, user: { id: 2, email: 'instructor@elearning.local', username: 'instructor' } } ], chapters_count: 8, lessons_count: 24, latest_submission: { id: 2, submitted_by: 2, created_at: '2024-02-12T00:00:00Z', submitter: { id: 2, email: 'instructor@elearning.local', username: 'instructor' } } } ]; // Mock course detail for review const MOCK_COURSE_DETAIL: CourseDetailForReview = { id: 1, title: { th: 'พื้นฐาน JavaScript', en: 'JavaScript Fundamentals' }, slug: 'javascript-fundamentals', description: { th: 'เรียนรู้ JavaScript ตั้งแต่เริ่มต้น รวมถึง ES6+ features และ best practices', en: 'Learn JavaScript from scratch including ES6+ features and best practices' }, thumbnail_url: null, price: 990, is_free: false, have_certificate: true, status: 'PENDING', created_at: '2024-02-01T00:00:00Z', updated_at: '2024-02-10T00:00:00Z', category: { id: 1, name: { th: 'การพัฒนาเว็บไซต์', en: 'Web Development' } }, creator: { id: 2, email: 'instructor@elearning.local', username: 'instructor' }, instructors: [ { user_id: 2, is_primary: true, user: { id: 2, email: 'instructor@elearning.local', username: 'instructor' } } ], chapters: [ { id: 1, title: { th: 'แนะนำ JavaScript', en: 'Introduction to JavaScript' }, sort_order: 1, is_published: true, lessons: [ { id: 1, title: { th: 'JavaScript คืออะไร', en: 'What is JavaScript' }, type: 'VIDEO', sort_order: 1, is_published: true }, { id: 2, title: { th: 'ติดตั้ง Development Environment', en: 'Setup Development Environment' }, type: 'VIDEO', sort_order: 2, is_published: true }, { id: 3, title: { th: 'แบบทดสอบบทที่ 1', en: 'Chapter 1 Quiz' }, type: 'QUIZ', sort_order: 3, is_published: true } ] }, { id: 2, title: { th: 'Variables และ Data Types', en: 'Variables and Data Types' }, sort_order: 2, is_published: true, lessons: [ { id: 4, title: { th: 'var, let และ const', en: 'var, let and const' }, type: 'VIDEO', sort_order: 1, is_published: true }, { id: 5, title: { th: 'Primitive Data Types', en: 'Primitive Data Types' }, type: 'VIDEO', sort_order: 2, is_published: true } ] } ], approval_history: [ { id: 1, action: 'SUBMITTED', comment: null, created_at: '2024-02-10T10:00:00Z', submitter: { id: 2, email: 'instructor@elearning.local', username: 'instructor' }, reviewer: null } ] }; // Helper function to get auth token from cookie or localStorage const getAuthToken = (): string => { const tokenCookie = useCookie('token'); return tokenCookie.value || ''; }; export const adminService = { async getUsers(): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return MOCK_USERS; } const token = getAuthToken(); const response = await $fetch('/api/admin/usermanagement/users', { baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` } }); return response.data; }, async getUserById(id: number): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 300)); const user = MOCK_USERS.find(u => u.id === id); if (!user) throw new Error('User not found'); return user; } const token = getAuthToken(); const response = await $fetch(`/api/admin/usermanagement/users/${id}`, { baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` } }); return response; }, async updateUserRole(userId: number, roleId: number): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return; } const token = getAuthToken(); await $fetch(`/api/admin/usermanagement/role/${userId}`, { method: 'PUT', baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` }, body: { id: userId, role_id: roleId } }); }, async deleteUser(userId: number): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return; } const token = getAuthToken(); await $fetch(`/api/admin/usermanagement/users/${userId}`, { method: 'DELETE', baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` } }); }, // ============ Pending Courses ============ async getPendingCourses(): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return MOCK_PENDING_COURSES; } const token = getAuthToken(); const response = await $fetch('/api/admin/courses/pending', { baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` } }); return response.data; }, async getCourseForReview(courseId: number): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return MOCK_COURSE_DETAIL; } const token = getAuthToken(); const response = await $fetch(`/api/admin/courses/${courseId}`, { baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` } }); return response.data; }, async approveCourse(courseId: number, comment?: string): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return; } const token = getAuthToken(); await $fetch(`/api/admin/courses/${courseId}/approve`, { method: 'POST', baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` }, body: { comment: comment || '' } }); }, async rejectCourse(courseId: number, comment: string): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return; } const token = getAuthToken(); await $fetch(`/api/admin/courses/${courseId}/reject`, { method: 'POST', baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` }, body: { comment } }); }, // ============ Categories ============ async getCategories(): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return MOCK_CATEGORIES; } const token = getAuthToken(); const response = await $fetch('/api/categories', { baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` } }); return response.data.categories; }, async createCategory(data: CreateCategoryRequest): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return { ...MOCK_CATEGORIES[0], id: Date.now() }; } const token = getAuthToken(); const response = await $fetch('/api/admin/categories', { method: 'POST', baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` }, body: data }); return response; }, async updateCategory(id: number, data: UpdateCategoryRequest): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return { ...MOCK_CATEGORIES[0], id }; } const token = getAuthToken(); const response = await $fetch(`/api/admin/categories/${id}`, { method: 'PUT', baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` }, body: data }); return response; }, async deleteCategory(id: number): Promise { const config = useRuntimeConfig(); const useMockData = config.public.useMockData as boolean; if (useMockData) { await new Promise(resolve => setTimeout(resolve, 500)); return; } const token = getAuthToken(); await $fetch(`/api/admin/categories/${id}`, { method: 'DELETE', baseURL: config.public.apiBaseUrl as string, headers: { Authorization: `Bearer ${token}` } }); } }; // Category interfaces export interface CategoryResponse { id: number; name: { en: string; th: string; }; slug: string; description: { en: string; th: string; }; icon: string; sort_order: number; is_active: boolean; created_at: string; created_by: number; updated_at: string; updated_by: number | null; } export interface CategoriesListResponse { code: number; message: string; data: { categories: CategoryResponse[]; }; } export interface CreateCategoryRequest { name: { en: string; th: string; }; slug: string; description: { en: string; th: string; }; created_by?: number; } export interface UpdateCategoryRequest { id: number; name: { en: string; th: string; }; slug: string; description: { en: string; th: string; }; } // Mock categories const MOCK_CATEGORIES: CategoryResponse[] = [ { id: 1, name: { en: 'Web Development', th: 'การพัฒนาเว็บไซต์' }, slug: 'web-development', description: { en: 'Learn web development', th: 'หลักสูตรเกี่ยวกับการพัฒนาเว็บไซต์และเว็บแอปพลิเคชัน' }, icon: 'code', sort_order: 1, is_active: true, created_at: '2024-01-15T00:00:00Z', created_by: 1, updated_at: '2024-01-15T00:00:00Z', updated_by: null }, { id: 2, name: { en: 'Mobile Development', th: 'การพัฒนาแอปพลิเคชันมือถือ' }, slug: 'mobile-development', description: { en: 'Learn mobile app development', th: 'หลักสูตรเกี่ยวกับการพัฒนาแอปพลิเคชันบนมือถือ' }, icon: 'smartphone', sort_order: 2, is_active: true, created_at: '2024-01-20T00:00:00Z', created_by: 1, updated_at: '2024-01-20T00:00:00Z', updated_by: null }, { id: 3, name: { en: 'Database', th: 'ฐานข้อมูล' }, slug: 'database', description: { en: 'Learn database management', th: 'หลักสูตรเกี่ยวกับการออกแบบและจัดการฐานข้อมูล' }, icon: 'storage', sort_order: 3, is_active: true, created_at: '2024-02-01T00:00:00Z', created_by: 1, updated_at: '2024-02-01T00:00:00Z', updated_by: null } ];