feat: Implement course discovery page with API integration, useCourse composable, and CourseCard component.

This commit is contained in:
supalerk-ar66 2026-01-16 10:26:33 +07:00
parent 2ffcc36fe4
commit 1d8acaf7d7
4 changed files with 39 additions and 23 deletions

View file

@ -3,9 +3,9 @@ import type { H3Event } from 'h3'
// Types based on API responses
export interface Course {
id: number
title: string
title: string | { th: string; en: string }
slug: string
description: string
description: string | { th: string; en: string }
thumbnail_url: string
price: string
is_free: boolean
@ -40,19 +40,17 @@ export const useCourse = () => {
const fetchCourses = async () => {
try {
const { data, error } = await useFetch<CourseResponse>(`${API_BASE_URL}/courses`, {
const data = await $fetch<CourseResponse>(`${API_BASE_URL}/courses`, {
method: 'GET',
headers: token.value ? {
Authorization: `Bearer ${token.value}`
} : {}
})
if (error.value) throw error.value
return {
success: true,
data: data.value?.data || [],
total: data.value?.total || 0
data: data.data || [],
total: data.total || 0
}
} catch (err: any) {
console.error('Fetch courses failed:', err)
@ -65,17 +63,15 @@ export const useCourse = () => {
const fetchCourseById = async (id: number) => {
try {
const { data, error } = await useFetch<CourseResponse>(`${API_BASE_URL}/courses/${id}`, {
const data = await $fetch<CourseResponse>(`${API_BASE_URL}/courses/${id}`, {
method: 'GET',
headers: token.value ? {
Authorization: `Bearer ${token.value}`
} : {}
})
if (error.value) throw error.value
// API returns data array even for single item based on schema
const courseData = data.value?.data?.[0]
const courseData = data.data?.[0]
if (!courseData) throw new Error('Course not found')
@ -97,3 +93,4 @@ export const useCourse = () => {
fetchCourseById
}
}