elearning/Frontend-Learner/pages/dashboard/index.vue

117 lines
4 KiB
Vue
Raw Normal View History

2026-01-13 10:46:40 +07:00
<script setup lang="ts">
/**
* @file home.vue
* @description หนาแดชบอรดหล (Dashboard)
* แสดงขอความตอนร และคอรสแนะนำสำหรบผเรยน
2026-01-13 10:46:40 +07:00
*/
definePageMeta({
layout: 'default',
middleware: 'auth'
})
useHead({
title: 'Dashboard - e-Learning'
})
const { currentUser } = useAuth()
const { fetchCourses, getLocalizedText } = useCourse() // Import useCourse
const { fetchCategories } = useCategory() // Import useCategory
const { t } = useI18n()
// Recommended Courses State
// เก็บข้อมูลคอร์สแนะนำ (สุ่มมา 3 คอร์ส)
const recommendedCourses = ref<any[]>([])
onMounted(async () => {
// 1. Fetch Categories for mapping
const catRes = await fetchCategories()
const catMap = new Map()
if (catRes.success) {
catRes.data?.forEach((c: any) => catMap.set(c.id, c.name))
}
// 2. Fetch 3 Random Courses from Server
// ดึงคอร์สแบบสุ่มจาก Server โดยตรง (ผ่าน API ใหม่ที่เพิ่ม parameter random และ limit)
const res = await fetchCourses({ random: true, limit: 3, forceRefresh: true, is_recommended: true })
if (res.success && res.data?.length) {
recommendedCourses.value = res.data.map((c: any) => ({
id: c.id,
title: c.title,
category: catMap.get(c.category_id),
lessons: c.lessons,
image: c.thumbnail_url || '',
badge: '',
badgeType: ''
}))
2026-01-13 10:46:40 +07:00
}
})
2026-01-13 10:46:40 +07:00
</script>
<template>
<div class="page-container !pt-4">
<!-- Welcome Header Section (Minimalist) -->
<div class="flex items-center gap-6 mb-10 py-2 animate-fade-in">
<!-- Avatar with premium shadow -->
<div class="relative group cursor-pointer" @click="$router.push('/dashboard/profile')">
<div class="absolute -inset-1 bg-gradient-to-r from-blue-600 to-indigo-600 rounded-full blur opacity-25 group-hover:opacity-50 transition duration-1000 group-hover:duration-200"></div>
<q-avatar size="84px" class="relative shadow-2xl ring-4 ring-white dark:ring-slate-900 transition-all duration-500 overflow-hidden">
<img
:src="currentUser?.photoURL || 'https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mp&f=y'"
class="object-cover"
/>
</q-avatar>
</div>
<div class="flex flex-col">
<h1 class="text-2xl md:text-4xl font-black text-slate-900 dark:text-white tracking-tight leading-tight mb-1">
{{ $t('dashboard.welcomeTitle') }}, {{ currentUser?.firstName }}!
</h1>
<div class="flex items-center gap-2">
<span class="text-slate-500 dark:text-slate-400 text-sm font-medium">{{ $t('dashboard.welcomeSubtitle') }}</span>
</div>
2026-01-13 10:46:40 +07:00
</div>
</div>
<!-- Main Content Area -->
<div>
<!-- Section: Recommended Courses -->
<div class="mb-6">
<h2 class="text-xl font-black flex items-center gap-3 tracking-tight text-slate-900 dark:text-white">
<span class="w-1 h-6 bg-emerald-500 rounded-full shadow-sm shadow-emerald-500/50"/>
{{ $t('menu.recommendedCourses') }}
</h2>
</div>
<!-- Recommended Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 pb-20">
<CourseCard
v-for="course in recommendedCourses"
:key="course.id"
v-bind="course"
/>
</div>
<!-- Loading State for Recommended -->
<div v-if="recommendedCourses.length === 0" class="flex justify-center py-10 opacity-50">
<div class="animate-pulse">Loading recommendations...</div>
2026-01-13 10:46:40 +07:00
</div>
</div>
</div>
</template>
<style scoped>
@keyframes fade-in {
from { opacity: 0; transform: translateX(-20px); }
to { opacity: 1; transform: translateX(0); }
2026-01-13 10:46:40 +07:00
}
.animate-fade-in {
animation: fade-in 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
2026-01-13 10:46:40 +07:00
}
</style>