elearning/frontend_management/services/admin.service.ts
Missez 031ca5c984
All checks were successful
Build and Deploy Frontend Management to Dev Server / Build Frontend Management Docker Image (push) Successful in 46s
Build and Deploy Frontend Management to Dev Server / Deploy E-learning Frontend Management to Dev Server (push) Successful in 6s
Build and Deploy Frontend Management to Dev Server / Notify Deployment Status (push) Successful in 1s
feat: Add initial e-learning frontend setup including admin and instructor services, layouts, and pages.
2026-02-24 09:25:02 +07:00

624 lines
17 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;
};
};
avatar_url?: 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 ApiResponse<T> {
code: number;
message: string;
data: T;
}
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;
}
// 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;
};
}
// Audit Logs Interfaces
export interface AuditLog {
id: number;
user_id: number;
action: string;
entity_type: string;
entity_id: number;
old_value: string | null;
new_value: string | null;
ip_address: string | null;
user_agent: string | null;
metadata: string | null;
created_at: string;
user: {
email: string;
username: string;
id: number;
} | null;
}
export interface AuditLogsListResponse {
data: AuditLog[];
pagination: {
totalPages: number;
total: number;
limit: number;
page: number;
};
}
export interface AuditLogStats {
totalLogs: number;
todayLogs: number;
actionSummary: {
action: string;
count: number;
}[];
recentActivity: AuditLog[];
}
export interface RecommendedCourse {
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;
is_recommended: boolean;
status: string;
created_at: string;
updated_at: string;
category: {
id: number;
name: {
th: string;
en: string;
};
};
instructors: {
user_id: number;
is_primary: boolean;
user: {
id: number;
username: string;
email: string;
};
}[];
creator: {
id: number;
username: string;
email: string;
};
chapters_count: number;
lessons_count: number;
chapters?: {
id: number;
title: { th: string; en: string };
sort_order: number;
lessons: {
id: number;
title: { th: string; en: string };
}[];
}[];
}
export interface RecommendedCoursesListResponse {
code: number;
message: string;
data: RecommendedCourse[];
total: number;
}
// Helper function to get auth token from cookie
const getAuthToken = (): string => {
const tokenCookie = useCookie('token');
return tokenCookie.value || '';
};
export const adminService = {
async getUsers(): Promise<AdminUserResponse[]> {
const config = useRuntimeConfig();
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 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<ApiResponse<void>> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<void>>(`/api/admin/usermanagement/role/${userId}`, {
method: 'PUT',
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
},
body: {
id: userId,
role_id: roleId
}
});
return response;
},
async deleteUser(userId: number): Promise<ApiResponse<void>> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<void>>(`/api/admin/usermanagement/users/${userId}`, {
method: 'DELETE',
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
}
});
return response;
},
// ============ Pending Courses ============
async getPendingCourses(): Promise<PendingCourse[]> {
const config = useRuntimeConfig();
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 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<ApiResponse<void>> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<void>>(`/api/admin/courses/${courseId}/approve`, {
method: 'POST',
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
},
body: { comment: comment || '' }
});
return response;
},
async rejectCourse(courseId: number, comment: string): Promise<ApiResponse<void>> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<void>>(`/api/admin/courses/${courseId}/reject`, {
method: 'POST',
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
},
body: { comment }
});
return response;
},
// ============ Categories ============
async getCategories(): Promise<CategoryResponse[]> {
const config = useRuntimeConfig();
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<ApiResponse<CategoryResponse>> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<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<ApiResponse<CategoryResponse>> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<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<ApiResponse<void>> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<void>>(`/api/admin/categories/${id}`, {
method: 'DELETE',
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
}
});
return response;
},
// ============ Audit Logs ============
async getAuditLogs(
page: number = 1,
limit: number = 20,
filters: {
userId?: number;
action?: string;
entityType?: string;
entityId?: number;
startDate?: string;
endDate?: string;
} = {}
): Promise<AuditLogsListResponse> {
const config = useRuntimeConfig();
const token = getAuthToken();
let query: any = { page, limit };
if (filters.userId) query.userId = filters.userId;
if (filters.action) query.action = filters.action;
if (filters.entityType) query.entityType = filters.entityType;
if (filters.entityId) query.entityId = filters.entityId;
if (filters.startDate) query.startDate = filters.startDate;
if (filters.endDate) query.endDate = filters.endDate;
const response = await $fetch<AuditLogsListResponse>('/api/admin/audit-logs', {
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` },
query
});
return response;
},
async getAuditLogById(id: number): Promise<AuditLog> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<AuditLog>(`/api/admin/audit-logs/${id}`, {
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` }
});
return response;
},
async getAuditLogStats(): Promise<AuditLogStats> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<AuditLogStats>('/api/admin/audit-logs/stats/summary', {
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` }
});
return response;
},
async getAuditLogsByEntity(entityType: string, entityId: number): Promise<AuditLog[]> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<AuditLog[]>(`/api/admin/audit-logs/entity/${entityType}/${entityId}`, {
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` }
});
return response;
},
async getAuditLogsByUser(userId: number, limit: number = 20): Promise<AuditLog[]> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<AuditLog[]>(`/api/admin/audit-logs/user/${userId}/activity`, {
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` },
query: { limit }
});
return response;
},
async cleanupAuditLogs(days: number = 90): Promise<ApiResponse<void>> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<void>>('/api/admin/audit-logs/cleanup', {
method: 'DELETE',
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` },
query: { days }
});
return response;
},
// ============ Recommended Courses ============
async getRecommendedCourses(): Promise<RecommendedCourse[]> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<RecommendedCoursesListResponse>('/api/admin/recommended-courses', {
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
}
});
return response.data;
},
async getRecommendedCourseById(id: number): Promise<RecommendedCourse> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<RecommendedCourse>>(`/api/admin/recommended-courses/${id}`, {
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
}
});
return response.data;
},
async toggleCourseRecommendation(courseId: number, isRecommended: boolean): Promise<ApiResponse<void>> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<void>>(`/api/admin/recommended-courses/${courseId}/toggle`, {
method: 'PUT',
baseURL: config.public.apiBaseUrl as string,
headers: {
Authorization: `Bearer ${token}`
},
query: { is_recommended: isRecommended }
});
return response;
}
};