feat: Introduce core e-learning features with new pages for course details, dashboard, authentication, browsing, and learning, supported by a useCourse composable.

This commit is contained in:
supalerk-ar66 2026-01-23 09:47:32 +07:00
parent c982ab2c05
commit 0eb9b522f6
6 changed files with 109 additions and 38 deletions

View file

@ -15,23 +15,36 @@ useHead({
title: "รายการคอร์ส - e-Learning",
});
// UI State
// ==========================================
// 1. State ( UI)
// ==========================================
// showDetail: (true = , false = )
const showDetail = ref(false);
// searchQuery:
const searchQuery = ref("");
// isCategoryOpen: /
const isCategoryOpen = ref(true);
// Helper to get localized text
// ==========================================
// 2. (Helpers)
// ==========================================
// getLocalizedText:
// object {th, en} th , en
const getLocalizedText = (text: string | { th: string; en: string } | undefined) => {
if (!text) return ''
if (typeof text === 'string') return text
return text.th || text.en || ''
}
// Categories Data
// ==========================================
// 3. (Categories)
// ==========================================
// useCategory composable API
const { fetchCategories } = useCategory();
const categories = ref<any[]>([]);
const showAllCategories = ref(false);
const showAllCategories = ref(false); // (Show More/Less)
//
const loadCategories = async () => {
const res = await fetchCategories();
if (res.success) {
@ -39,22 +52,28 @@ const loadCategories = async () => {
}
};
// ( Show More , 8 )
const visibleCategories = computed(() => {
return showAllCategories.value ? categories.value : categories.value.slice(0, 8);
});
// Courses Data
// ==========================================
// 4. (Courses)
// ==========================================
// useCourse composable (, )
const { fetchCourses, fetchCourseById, enrollCourse } = useCourse();
const courses = ref<any[]>([]);
const isLoading = ref(false);
const selectedCourse = ref<any>(null);
const isLoadingDetail = ref(false);
const isEnrolling = ref(false);
const isLoading = ref(false); //
const selectedCourse = ref<any>(null); //
const isLoadingDetail = ref(false); //
const isEnrolling = ref(false); //
//
const loadCourses = async () => {
isLoading.value = true;
const res = await fetchCourses();
if (res.success) {
//
courses.value = (res.data || []).map((c: any) => ({
...c,
rating: "0.0",
@ -65,11 +84,13 @@ const loadCourses = async () => {
isLoading.value = false;
};
//
const selectCourse = async (id: number) => {
isLoadingDetail.value = true;
selectedCourse.value = null;
showDetail.value = true;
showDetail.value = true; // Detail View
// API ID
const res = await fetchCourseById(id);
if (res.success) {
selectedCourse.value = res.data;
@ -77,14 +98,15 @@ const selectCourse = async (id: number) => {
isLoadingDetail.value = false;
};
// (Enroll)
const handleEnroll = async (id: number) => {
if (isEnrolling.value) return;
if (isEnrolling.value) return; //
isEnrolling.value = true;
const res = await enrollCourse(id);
if (res.success) {
// Navigate to my-courses where the success modal will be shown
// "" parameter enrolled=true popup
return navigateTo('/dashboard/my-courses?enrolled=true');
} else {
alert(res.error || 'Failed to enroll');
@ -94,23 +116,28 @@ const handleEnroll = async (id: number) => {
};
onMounted(() => {
//
loadCategories();
loadCourses();
});
// Filter Logic based on search query
// Filter Logic based on search query and category
// ==========================================
// 5. (Filter & Search)
// ==========================================
// selectedCategoryIds: ID
const selectedCategoryIds = ref<number[]>([]);
// (Filter Logic)
const filteredCourses = computed(() => {
let result = courses.value;
// Filter by Category
// 1. (Category Filter)
if (selectedCategoryIds.value.length > 0) {
result = result.filter(c => selectedCategoryIds.value.includes(c.category_id));
}
// Filter by Search Query
// 2. (Search Query) -
if (searchQuery.value) {
const query = searchQuery.value.toLowerCase();
result = result.filter(