elearning/frontend_management/services/admin.service.ts

675 lines
20 KiB
TypeScript

// 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<AdminUserResponse[]> {
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<UsersListResponse>('/api/admin/usermanagement/users', {
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
}
});
return response.data;
},
async getUserById(id: number): Promise<AdminUserResponse> {
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<AdminUserResponse>(`/api/admin/usermanagement/users/${id}`, {
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
}
});
return response;
},
async updateUserRole(userId: number, roleId: number): Promise<void> {
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<void> {
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<PendingCourse[]> {
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<PendingCoursesListResponse>('/api/admin/courses/pending', {
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
}
});
return response.data;
},
async getCourseForReview(courseId: number): Promise<CourseDetailForReview> {
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<CourseDetailForReviewResponse>(`/api/admin/courses/${courseId}`, {
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
}
});
return response.data;
},
async approveCourse(courseId: number, comment?: string): Promise<void> {
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<void> {
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<CategoryResponse[]> {
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<CategoriesListResponse>('/api/categories', {
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
}
});
return response.data.categories;
},
async createCategory(data: CreateCategoryRequest): Promise<CategoryResponse> {
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<CategoryResponse>('/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<CategoryResponse> {
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<CategoryResponse>(`/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<void> {
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
}
];