feat: Add course discovery page with search, category filters, and detailed course view, along with a new useCategory composable.

This commit is contained in:
supalerk-ar66 2026-01-20 14:47:46 +07:00
parent 2a461a1e4f
commit e6a73c836c
2 changed files with 90 additions and 35 deletions

View file

@ -20,6 +20,29 @@ const showDetail = ref(false);
const searchQuery = ref("");
const isCategoryOpen = ref(true);
// Helper to get localized text
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
const { fetchCategories } = useCategory();
const categories = ref<any[]>([]);
const showAllCategories = ref(false);
const loadCategories = async () => {
const res = await fetchCategories();
if (res.success) {
categories.value = res.data || [];
}
};
const visibleCategories = computed(() => {
return showAllCategories.value ? categories.value : categories.value.slice(0, 8);
});
// Courses Data
const { fetchCourses, fetchCourseById } = useCourse();
const courses = ref<any[]>([]);
@ -54,42 +77,10 @@ const selectCourse = async (id: number) => {
};
onMounted(() => {
loadCategories();
loadCourses();
});
// Categories Data
const categories = [
"การตลาดออนไลน์",
"ธุรกิจ",
"การเงิน & ลงทุน",
"การพัฒนาตนเอง",
"Office Productivity",
"Data",
"เขียนโปรแกรม",
"การพัฒนาซอฟต์แวร์",
"การออกแบบ",
"Art & Craft",
"การเขียน",
"ถ่ายภาพ & วิดีโอ",
"ภาษา",
"Lifestyles",
];
// Category Visibility State
const showAllCategories = ref(false);
const visibleCategories = computed(() => {
return showAllCategories.value ? categories : categories.slice(0, 8);
});
// Helper to get localized text
const getLocalizedText = (text: string | { th: string; en: string } | undefined) => {
if (!text) return ''
if (typeof text === 'string') return text
return text.th || text.en || ''
}
// Filter Logic based on search query
const filteredCourses = computed(() => {
if (!searchQuery.value) return courses.value;
@ -171,7 +162,7 @@ const filteredCourses = computed(() => {
<div v-show="isCategoryOpen" class="flex flex-col gap-1">
<div
v-for="cat in visibleCategories"
:key="cat"
:key="cat.id"
class="flex items-center justify-between py-3 border-b border-slate-100 dark:border-slate-700/50 group cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-800/50 -mx-4 px-4 transition-colors"
>
<label
@ -181,7 +172,7 @@ const filteredCourses = computed(() => {
type="checkbox"
class="w-4 h-4 rounded border-slate-300 text-primary focus:ring-primary"
/>
{{ cat }}
{{ getLocalizedText(cat.name) }}
</label>
</div>
<button