2026-01-16 16:37:16 +07:00
// 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 [ ] ;
}
2026-01-28 13:38:54 +07:00
// 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 ;
}
2026-01-16 16:37:16 +07:00
// 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'
}
}
] ;
2026-01-28 13:38:54 +07:00
// 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
}
]
} ;
2026-01-16 16:37:16 +07:00
// 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 } `
}
} ) ;
} ,
2026-01-28 13:38:54 +07:00
// ============ 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 }
} ) ;
} ,
2026-01-16 16:37:16 +07:00
// ============ 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 ( ) ;
2026-01-19 15:03:01 +07:00
const response = await $fetch < CategoriesListResponse > ( '/api/categories' , {
2026-01-16 16:37:16 +07:00
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
}
] ;