feat: Implement 'My Courses' page to display enrolled courses with progress tracking, filtering, and certificate download functionality.
This commit is contained in:
parent
dccf808c2b
commit
c8ef372d4e
1 changed files with 18 additions and 18 deletions
|
|
@ -171,17 +171,17 @@ onMounted(() => {
|
|||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div v-for="course in inProgressCourses.slice(0, 2)" :key="course.id" class="border border-slate-100 dark:border-slate-800 rounded-3xl p-4 flex flex-col sm:flex-row gap-5 items-center bg-[#F8FAFC] dark:bg-slate-800/50 hover:border-blue-100 dark:hover:border-blue-900/50 transition-colors">
|
||||
<!-- Image -->
|
||||
<!-- ส่วนรูปภาพหน้าปก (Image) -->
|
||||
<div class="w-full sm:w-[160px] h-[120px] rounded-[1.25rem] overflow-hidden bg-slate-200 shrink-0 relative group">
|
||||
<img :src="course.thumbnail_url" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"/>
|
||||
<!-- Quick play overlay -->
|
||||
<!-- เลเยอร์เล่นวิดีโอด่วน (Quick play overlay) -->
|
||||
<div @click="navigateTo(`/classroom/learning?course_id=${course.id}`)" class="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center cursor-pointer">
|
||||
<div class="bg-white/30 backdrop-blur-md rounded-full w-10 h-10 flex flex-col items-center justify-center">
|
||||
<q-icon name="play_arrow" color="white" size="20px" class="ml-0.5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Info -->
|
||||
<!-- ส่วนข้อมูลเนื้อหา (Info) -->
|
||||
<div class="flex-1 flex flex-col justify-center min-w-0 py-1 w-full">
|
||||
<div class="mb-2" v-if="course.category_name">
|
||||
<span class="bg-[#E9EFFD] dark:bg-blue-900/40 text-[#3B6BE8] dark:text-blue-400 px-3.5 py-1.5 rounded-full text-[10px] font-bold tracking-wide">{{ course.category_name }}</span>
|
||||
|
|
@ -249,19 +249,19 @@ onMounted(() => {
|
|||
|
||||
<div v-else-if="filteredEnrolledCourses.length > 0">
|
||||
|
||||
<!-- GRID VIEW -->
|
||||
<!-- หมวดแสดงสไตล์กริดตาราง (GRID VIEW) -->
|
||||
<div v-if="viewMode === 'grid'" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
<div v-for="course in filteredEnrolledCourses" :key="course.id" class="flex flex-col rounded-[1.5rem] bg-white dark:!bg-slate-900 border border-slate-100 dark:border-slate-800 overflow-hidden shadow-sm hover:shadow-[0_8px_30px_rgb(0,0,0,0.06)] transition-all duration-300 group cursor-pointer" @click="navigateTo(`/classroom/learning?course_id=${course.id}`)">
|
||||
<!-- Thumbnail -->
|
||||
<!-- ส่วนรูปภาพหน้าปก (Thumbnail) -->
|
||||
<div class="relative w-full aspect-[4/3] bg-slate-100 dark:bg-slate-800 overflow-hidden">
|
||||
<img :src="course.thumbnail_url" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500" />
|
||||
<!-- Badge inside Image Map Top Left -->
|
||||
<!-- ป้ายหมวดหมู่บนมุมซ้ายของรูป (Badge inside Image Map Top Left) -->
|
||||
<div v-if="course.category_name" class="absolute top-3 left-3 bg-white/95 dark:bg-slate-900/95 backdrop-blur-md text-[#3B6BE8] dark:text-blue-400 font-bold text-[10px] px-3.5 py-1 rounded-full shadow-sm">
|
||||
{{ course.category_name }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card Body -->
|
||||
<!-- ตัวการ์ด (Card Body) -->
|
||||
<div class="p-5 flex flex-col flex-1">
|
||||
<h3 class="font-bold text-slate-900 dark:text-white text-[14px] leading-snug line-clamp-2 mb-3">{{ getLocalizedText(course.title) }}</h3>
|
||||
|
||||
|
|
@ -275,11 +275,11 @@ onMounted(() => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row items-stretch sm:items-center gap-2 mt-3 sm:mt-0">
|
||||
<!-- Certificate Button -->
|
||||
<!-- ปุ่มดาวน์โหลดใบเซอร์ (Certificate Button) -->
|
||||
<button v-if="course.completed" @click.stop="handleDownloadCertificate(course.id)" class="border border-green-100 bg-green-50 text-green-600 dark:border-green-900/50 dark:bg-green-900/30 dark:text-green-400 rounded-full px-3 py-1.5 text-[11px] font-bold hover:bg-green-100 dark:hover:bg-green-900/50 transition-colors shrink-0 flex items-center justify-center gap-1">
|
||||
<q-icon name="workspace_premium" size="14px" /> {{ $t('course.certificate') }}
|
||||
</button>
|
||||
<!-- Continue/Replay Button -->
|
||||
<!-- ปุ่มเรียนต่อหรือเรียนซ้ำ (Continue/Replay Button) -->
|
||||
<button class="bg-[#3B6BE8] text-white border-transparent hover:bg-blue-700 shadow-sm rounded-full px-5 py-1.5 text-[11px] font-bold transition-colors shrink-0 text-center cursor-pointer">
|
||||
{{ course.completed ? $t('course.studyAgain') : $t('dashboard.continue') }}
|
||||
</button>
|
||||
|
|
@ -289,20 +289,20 @@ onMounted(() => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LIST VIEW -->
|
||||
<!-- หมวดแสดงสไตล์บรรทัดรายการ (LIST VIEW) -->
|
||||
<div v-else class="flex flex-col gap-4">
|
||||
<div v-for="course in filteredEnrolledCourses" :key="course.id" class="flex flex-col sm:flex-row items-center rounded-[1.5rem] bg-white dark:!bg-slate-900 border border-slate-100 dark:border-slate-800 p-4 gap-6 shadow-sm hover:shadow-[0_8px_30px_rgb(0,0,0,0.06)] transition-all duration-300 cursor-pointer group" @click="navigateTo(`/classroom/learning?course_id=${course.id}`)">
|
||||
|
||||
<!-- Thumbnail Left -->
|
||||
<!-- ส่วนภาพหน้าปกด้านซ้าย (Thumbnail Left) -->
|
||||
<div class="relative w-full sm:w-[240px] aspect-[16/10] sm:aspect-auto sm:h-[130px] rounded-2xl bg-slate-100 dark:bg-slate-800 overflow-hidden shrink-0">
|
||||
<img :src="course.thumbnail_url" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500" />
|
||||
<!-- Badge inside Image -->
|
||||
<!-- ป้ายหมวดหมู่ในรูปภาพ (Badge inside Image) -->
|
||||
<div v-if="course.category_name" class="absolute top-2.5 left-2.5 bg-white/95 dark:bg-slate-900/95 backdrop-blur-md text-[#3B6BE8] dark:text-blue-400 font-bold text-[10px] px-3.5 py-1 rounded-full shadow-sm">
|
||||
{{ course.category_name }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content Right -->
|
||||
<!-- เนื้อหาอยู่ทางขวา (Content Right) -->
|
||||
<div class="flex-1 w-full flex flex-col md:flex-row gap-6 md:items-center">
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
|
|
@ -310,7 +310,7 @@ onMounted(() => {
|
|||
|
||||
</div>
|
||||
|
||||
<!-- Progress and Button Zone -->
|
||||
<!-- โซนความคืบหน้าและปุ่มกด (Progress and Button Zone) -->
|
||||
<div class="flex md:flex-col items-center md:items-end justify-between md:justify-center gap-4 shrink-0 md:w-[200px]">
|
||||
<div class="w-full max-w-[140px] md:max-w-full">
|
||||
<div class="flex justify-between items-center text-[11px] font-bold text-slate-700 dark:text-slate-300 mb-2 tracking-wide">
|
||||
|
|
@ -323,11 +323,11 @@ onMounted(() => {
|
|||
</div>
|
||||
|
||||
<div class="flex flex-col items-stretch md:items-end gap-2 mt-3 sm:mt-0 w-full sm:w-auto">
|
||||
<!-- Certificate Button -->
|
||||
<!-- ปุ่มดาวน์โหลดใบเซอร์ (Certificate Button) -->
|
||||
<button v-if="course.completed" @click.stop="handleDownloadCertificate(course.id)" class="border border-green-100 bg-green-50 text-green-600 dark:border-green-900/50 dark:bg-green-900/30 dark:text-green-400 rounded-full px-4 py-2 text-[12px] font-bold hover:bg-green-100 dark:hover:bg-green-900/50 transition-colors shrink-0 flex items-center justify-center gap-1 w-full sm:w-auto">
|
||||
<q-icon name="workspace_premium" size="16px" /> {{ $t('course.downloadCertificate') }}
|
||||
</button>
|
||||
<!-- Continue/Replay Button -->
|
||||
<!-- ปุ่มเรียนต่อหรือเรียนซ้ำ (Continue/Replay Button) -->
|
||||
<button class="bg-[#3B6BE8] text-white border-transparent hover:bg-blue-700 shadow-sm rounded-full px-6 py-2 text-[12px] font-bold transition-colors shrink-0 text-center w-full sm:w-auto cursor-pointer">
|
||||
{{ course.completed ? $t('course.studyAgain') : $t('dashboard.continue') }}
|
||||
</button>
|
||||
|
|
@ -340,7 +340,7 @@ onMounted(() => {
|
|||
|
||||
</div>
|
||||
|
||||
<!-- Empty filter state -->
|
||||
<!-- กรณีที่ค้นหา/กรองแล้วไม่พบข้อมูล (Empty filter state) -->
|
||||
<div v-else class="flex flex-col items-center justify-center py-20">
|
||||
<q-icon name="search_off" size="48px" class="text-slate-300 dark:text-slate-600 mb-4" />
|
||||
<h3 class="text-lg font-bold text-slate-900 dark:text-white mb-2">{{ $t('myCourses.searchNoResult') }}</h3>
|
||||
|
|
@ -350,7 +350,7 @@ onMounted(() => {
|
|||
|
||||
</div>
|
||||
|
||||
<!-- MODAL: Enrollment Success -->
|
||||
<!-- หน้าต่างแจ้งเตือน: ลงทะเบียนสำเร็จ (MODAL: Enrollment Success) -->
|
||||
<q-dialog v-model="showEnrollModal" backdrop-filter="blur(4px)">
|
||||
<q-card class="rounded-[1.5rem] shadow-2xl p-8 max-w-sm w-full text-center relative overflow-hidden bg-white dark:bg-slate-800">
|
||||
<div class="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-green-400 to-emerald-600"></div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue