feat: implement core e-learning classroom functionality including login, lesson viewing, and quiz pages.
This commit is contained in:
parent
0641b2547a
commit
8e57cb124a
3 changed files with 21 additions and 23 deletions
|
|
@ -100,13 +100,14 @@ const handleLogin = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show error on specific fields
|
// Show error on specific fields
|
||||||
if (result.error === 'ไม่พบอีเมลในระบบ') {
|
// Show generic error for security (or specific if role mismatch)
|
||||||
errors.value.email = 'กรุณาเช็ค Email หรือ รหัสผ่านใหม่อีกครั้ง'
|
if (result.error === 'Email ไม่ถูกต้อง') {
|
||||||
errors.value.password = 'กรุณาเช็ค Email หรือ รหัสผ่านใหม่อีกครั้ง'
|
errors.value.email = result.error // Role mismatch case
|
||||||
} else if (result.error === 'Email ไม่ถูกต้อง') {
|
|
||||||
errors.value.email = result.error
|
|
||||||
} else {
|
} else {
|
||||||
errors.value.password = 'กรอกรหัสผ่านไม่ถูกต้อง'
|
// Generic login failure (401, 404, etc.)
|
||||||
|
const msg = 'กรุณาเช็ค Email หรือ รหัสผ่านใหม่อีกครั้ง'
|
||||||
|
errors.value.email = msg
|
||||||
|
errors.value.password = msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -282,8 +282,8 @@ const markLessonAsCompletedLocally = (lessonId: number) => {
|
||||||
for (const chapter of courseData.value.chapters) {
|
for (const chapter of courseData.value.chapters) {
|
||||||
const lesson = chapter.lessons.find((l: any) => l.id === lessonId)
|
const lesson = chapter.lessons.find((l: any) => l.id === lessonId)
|
||||||
if (lesson) {
|
if (lesson) {
|
||||||
if (!lesson.progress) lesson.progress = {}
|
// Compatible with API structure
|
||||||
lesson.progress.is_completed = true
|
lesson.is_completed = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -423,19 +423,9 @@ const onVideoEnded = async () => {
|
||||||
await loadCourseData()
|
await loadCourseData()
|
||||||
alert(t('course.completed') || "ยินดีด้วย! คุณเรียนจบหลักสูตรแล้ว")
|
alert(t('course.completed') || "ยินดีด้วย! คุณเรียนจบหลักสูตรแล้ว")
|
||||||
} else if (res.data.next_lesson_id) {
|
} else if (res.data.next_lesson_id) {
|
||||||
// Suggest next lesson
|
// Auto-advance removed as per request.
|
||||||
if (confirm(t('common.next') + '?')) {
|
// User will manually select the next lesson from the sidebar.
|
||||||
const nextId = res.data.next_lesson_id
|
console.log('Video finished. Next lesson available:', res.data.next_lesson_id)
|
||||||
|
|
||||||
// Update URL without reload if possible, but router.push is standard
|
|
||||||
await router.push({
|
|
||||||
path: '/classroom/learning',
|
|
||||||
query: { ...route.query, lesson_id: nextId }
|
|
||||||
})
|
|
||||||
|
|
||||||
// Manually load the lesson since we don't have a watcher on query
|
|
||||||
handleLessonSelect(nextId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -532,7 +522,7 @@ onBeforeUnmount(() => {
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
<q-item-section side>
|
<q-item-section side>
|
||||||
<q-icon v-if="lesson.progress?.is_completed" name="check_circle" color="positive" size="xs" />
|
<q-icon v-if="lesson.is_completed" name="check_circle" color="positive" size="xs" />
|
||||||
<q-icon v-else-if="currentLesson?.id === lesson.id" name="play_circle" color="primary" size="xs" />
|
<q-icon v-else-if="currentLesson?.id === lesson.id" name="play_circle" color="primary" size="xs" />
|
||||||
<q-icon v-else name="radio_button_unchecked" color="grey-4" size="xs" />
|
<q-icon v-else name="radio_button_unchecked" color="grey-4" size="xs" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const { t } = useI18n()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
const { fetchCourseLearningInfo, fetchLessonContent, submitQuiz: apiSubmitQuiz } = useCourse()
|
const { fetchCourseLearningInfo, fetchLessonContent, submitQuiz: apiSubmitQuiz, markLessonComplete } = useCourse()
|
||||||
|
|
||||||
// State Management
|
// State Management
|
||||||
const currentScreen = ref<'start' | 'taking' | 'result' | 'review'>('start')
|
const currentScreen = ref<'start' | 'taking' | 'result' | 'review'>('start')
|
||||||
|
|
@ -185,6 +185,13 @@ const submitQuiz = async (auto = false) => {
|
||||||
|
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
quizResult.value = res.data
|
quizResult.value = res.data
|
||||||
|
|
||||||
|
// Force mark lesson complete if passed (Fix for checkmark issue)
|
||||||
|
if (res.data.is_passed) {
|
||||||
|
markLessonComplete(courseId, lessonId).then(() => {
|
||||||
|
console.log('Explicitly marked lesson complete')
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fallback error handling
|
// Fallback error handling
|
||||||
alert(res.error || 'Failed to submit quiz')
|
alert(res.error || 'Failed to submit quiz')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue