elearning/Frontend-Learner/composables/useCourse.ts

249 lines
7.7 KiB
TypeScript
Raw Normal View History

import type { H3Event } from 'h3'
// Types based on API responses
export interface Course {
id: number
title: string | { th: string; en: string }
slug: string
description: string | { th: string; en: string }
thumbnail_url: string
price: string
is_free: boolean
have_certificate: boolean
status: string // 'DRAFT' | 'PUBLISHED' | ...
category_id: number
created_at?: string
updated_at?: string
created_by?: number
updated_by?: number
approved_at?: string
approved_by?: number
rejection_reason?: string
// Helper properties for UI (may be computed or mapped)
rating?: string
lessons?: number | string
levelType?: 'neutral' | 'warning' | 'success' // For UI badging
}
interface CourseResponse {
code: number
message: string
data: Course[]
total: number
}
export interface EnrolledCourse {
id: number // enrollment_id
course_id: number
course: Course
status: 'ENROLLED' | 'IN_PROGRESS' | 'COMPLETED' | 'DROPPED'
progress_percentage: number
enrolled_at: string
started_at?: string
completed_at?: string
last_accessed_at?: string
}
interface EnrolledCourseResponse {
code: number
message: string
data: EnrolledCourse[]
total: number
page: number
limit: number
}
export const useCourse = () => {
const config = useRuntimeConfig()
const API_BASE_URL = config.public.apiBase as string
const { token } = useAuth()
const fetchCourses = async () => {
try {
const data = await $fetch<CourseResponse>(`${API_BASE_URL}/courses`, {
method: 'GET',
headers: token.value ? {
Authorization: `Bearer ${token.value}`
} : {}
})
return {
success: true,
data: data.data || [],
total: data.total || 0
}
} catch (err: any) {
console.error('Fetch courses failed:', err)
return {
success: false,
error: err.data?.message || err.message || 'Error fetching courses'
}
}
}
const fetchCourseById = async (id: number) => {
try {
const data = await $fetch<CourseResponse>(`${API_BASE_URL}/courses/${id}`, {
method: 'GET',
headers: token.value ? {
Authorization: `Bearer ${token.value}`
} : {}
})
// API returns data array even for single item based on schema
const courseData = data.data?.[0]
if (!courseData) throw new Error('Course not found')
return {
success: true,
data: courseData
}
} catch (err: any) {
console.error('Fetch course details failed:', err)
return {
success: false,
error: err.data?.message || err.message || 'Error fetching course details'
}
}
}
const enrollCourse = async (courseId: number) => {
try {
const data = await $fetch<{ code: number; message: string; data: any }>(`${API_BASE_URL}/students/courses/${courseId}/enroll`, {
method: 'POST',
headers: token.value ? {
Authorization: `Bearer ${token.value}`
} : {}
})
return {
success: true,
data: data.data,
message: data.message
}
} catch (err: any) {
console.error('Enroll course failed:', err)
return {
success: false,
error: err.data?.message || err.message || 'Error enrolling in course',
code: err.data?.code
}
}
}
const fetchEnrolledCourses = async (params: { page?: number; limit?: number; status?: string } = {}) => {
try {
const queryParams = new URLSearchParams()
if (params.page) queryParams.append('page', params.page.toString())
if (params.limit) queryParams.append('limit', params.limit.toString())
if (params.status && params.status !== 'ALL') queryParams.append('status', params.status)
const data = await $fetch<EnrolledCourseResponse>(`${API_BASE_URL}/students/courses?${queryParams.toString()}`, {
method: 'GET',
headers: token.value ? {
Authorization: `Bearer ${token.value}`
} : {}
})
return {
success: true,
data: data.data || [],
total: data.total || 0,
page: data.page,
limit: data.limit
}
} catch (err: any) {
console.error('Fetch enrolled courses failed:', err)
return {
success: false,
error: err.data?.message || err.message || 'Error fetching enrolled courses'
}
}
}
const fetchCourseLearningInfo = async (courseId: number) => {
try {
const data = await $fetch<{ code: number; message: string; data: any }>(`${API_BASE_URL}/students/courses/${courseId}/learn`, {
method: 'GET',
headers: token.value ? {
Authorization: `Bearer ${token.value}`
} : {}
})
return {
success: true,
data: data.data
}
} catch (err: any) {
console.error('Fetch course learning info failed:', err)
return {
success: false,
error: err.data?.message || err.message || 'Error fetching course learning info',
code: err.data?.code
}
}
}
const fetchLessonContent = async (courseId: number, lessonId: number) => {
try {
const data = await $fetch<{ code: number; message: string; data: any; progress?: any }>(`${API_BASE_URL}/students/courses/${courseId}/lessons/${lessonId}`, {
method: 'GET',
headers: token.value ? {
Authorization: `Bearer ${token.value}`
} : {}
})
return {
success: true,
data: data.data,
progress: data.progress
}
} catch (err: any) {
console.error('Fetch lesson content failed:', err)
return {
success: false,
error: err.data?.message || err.message || 'Error fetching lesson content',
code: err.data?.code,
status: err.status
}
}
}
const checkLessonAccess = async (courseId: number, lessonId: number) => {
try {
const data = await $fetch<{ code: number; message: string; data: any }>(`${API_BASE_URL}/students/courses/${courseId}/lessons/${lessonId}/access-check`, {
method: 'GET',
headers: token.value ? {
Authorization: `Bearer ${token.value}`
} : {}
})
return {
success: true,
data: data.data
}
} catch (err: any) {
console.error('Check lesson access failed:', err)
return {
success: false,
error: err.data?.message || err.message || 'Error checking lesson access',
code: err.data?.code,
status: err.status
}
}
}
return {
fetchCourses,
fetchCourseById,
enrollCourse,
fetchEnrolledCourses,
fetchCourseLearningInfo,
fetchLessonContent,
checkLessonAccess
}
}