feat: Implement i18n for English and Thai, and add core e-learning pages for course discovery, classroom learning, and quizzes.

This commit is contained in:
supalerk-ar66 2026-01-27 10:05:01 +07:00
parent f1a83f479e
commit b8547f83b3
5 changed files with 24 additions and 22 deletions

View file

@ -172,8 +172,8 @@
"backToLesson": "Back to Lesson",
"reviewAnswers": "Review Answers",
"timeLeft": "Time Left",
"placeholderAPI": "This part is currently being connected to the real quiz system.",
"placeholderDesc": "The quiz system will be available once the API integration is complete.",
"skipToResult": "Skip to Result (Simulated)"
"noQuizData": "Sorry, no quiz data found",
"noQuizDesc": "This lesson might not have a quiz yet or it is being updated.",
"underDevelopment": "System is loading questions..."
}
}

View file

@ -172,8 +172,8 @@
"backToLesson": "กลับไปหน้าบทเรียน",
"reviewAnswers": "ตรวจดูคำตอบ",
"timeLeft": "เวลาที่เหลือ",
"placeholderAPI": "ส่วนนี้อยู่ระหว่างการเชื่อมต่อกับระบบข้อสอบจริง",
"placeholderDesc": "ระบบข้อสอบจะสามารถใช้งานได้เมื่อมีการเชื่อมต่อ API สมบูรณ์",
"skipToResult": "ข้ามไปหน้าผลลัพธ์ (จำลอง)"
"noQuizData": "ขออภัย ไม่พบข้อมูลแบบทดสอบ",
"noQuizDesc": "บทเรียนนี้อาจยังไม่มีแบบทดสอบ หรือกำลังอยู่ระหว่างการปรับปรุงเนื้อหา",
"underDevelopment": "ระบบกำลังโหลดโจทย์คำถาม..."
}
}

View file

@ -249,14 +249,13 @@ onMounted(() => {
<!-- COURSE DETAIL VIEW: Detailed information about a specific course -->
<div v-else>
<q-btn
flat
icon="arrow_back"
:label="$t('discovery.backToCatalog')"
color="grey-7"
class="mb-6 font-medium"
@click="showDetail = false"
/>
<button
@click="showDetail = false"
class="inline-flex items-center gap-2 text-slate-600 dark:text-white hover:text-blue-600 dark:hover:text-blue-300 mb-6 transition-all font-black text-lg md:text-xl group"
>
<q-icon name="arrow_back" size="28px" class="transition-transform group-hover:-translate-x-2" />
{{ $t('discovery.backToCatalog') }}
</button>
<div v-if="isLoadingDetail" class="flex justify-center py-20">
<q-spinner size="3rem" color="primary" />

View file

@ -351,7 +351,7 @@ onBeforeUnmount(() => {
<!-- Lesson Info -->
<div v-if="currentLesson" class="bg-white dark:bg-slate-800 p-6 rounded-2xl shadow-sm border border-slate-100 dark:border-white/5">
<h1 class="text-2xl font-bold mb-2">{{ getLocalizedText(currentLesson.title) }}</h1>
<p class="text-slate-500 dark:text-slate-400" v-if="currentLesson.description">{{ currentLesson.description }}</p>
<p class="text-slate-500 dark:text-slate-400" v-if="currentLesson.description">{{ getLocalizedText(currentLesson.description) }}</p>
<!-- Lesson Content Area -->
<div v-if="!videoSrc && currentLesson.content" class="mt-6 prose dark:prose-invert max-w-none p-6 bg-slate-50 dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/5">

View file

@ -18,7 +18,7 @@ const { fetchCourseLearningInfo, fetchLessonContent } = useCourse()
// State Management
const currentScreen = ref<'start' | 'taking' | 'result' | 'review'>('start')
const timeLeft = ref(30 * 60) // 30 minutes in seconds
const timeLeft = ref(0)
let timerInterval: ReturnType<typeof setInterval> | null = null
const courseId = Number(route.query.course_id)
@ -183,15 +183,18 @@ onUnmounted(() => {
<!-- 2. TAKING SCREEN -->
<div v-if="currentScreen === 'taking'" class="w-full max-w-[840px] animate-fade-in py-12 text-center">
<div class="bg-white dark:bg-[#1e293b] border border-slate-200 dark:border-white/5 rounded-[32px] p-10 shadow-xl">
<div class="mb-10">
<q-icon name="construction" size="4rem" class="text-blue-500 mb-4 opacity-50" />
<h2 class="text-xl font-bold mb-2 text-slate-900 dark:text-white">{{ $t('quiz.placeholderAPI') }}</h2>
<p class="text-slate-500 dark:text-slate-400">{{ $t('quiz.placeholderDesc') }}</p>
<div v-if="quizData?.questions && quizData.questions.length > 0">
<!-- Questions iterate here if available -->
<div class="text-slate-500">{{ $t('quiz.underDevelopment') }}</div>
</div>
<div v-else class="mb-10">
<h2 class="text-xl font-bold mb-2 text-slate-900 dark:text-white">{{ $t('quiz.noQuizData') }}</h2>
<p class="text-slate-500 dark:text-slate-400">{{ $t('quiz.noQuizDesc') }}</p>
</div>
<div class="pt-8 border-t border-slate-100 dark:border-white/5">
<button @click="submitQuiz(false)" class="px-8 py-4 bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 rounded-2xl font-bold hover:bg-slate-200 dark:hover:bg-slate-700 transition-colors">
{{ $t('quiz.skipToResult') }}
<button @click="confirmExit" class="px-8 py-4 bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 rounded-2xl font-bold hover:bg-slate-200 dark:hover:bg-slate-700 transition-colors">
{{ $t('quiz.backToLesson') }}
</button>
</div>
</div>