Files
english/src/pages/ToeicPractice.tsx
2026-04-12 18:54:59 +07:00

110 lines
5.0 KiB
TypeScript

import { useState } from 'react'
import { useNavigate } from '@tanstack/react-router'
import { CircularProgress } from '@/components/CircularProgress'
import { useTestStore } from '@/store/test-store'
import { TOEIC_PARTS } from '@/data/mock-data'
import { fetchQuestions } from '@/hooks/use-questions'
import { useRequireAuth } from '@/hooks/use-require-auth'
export function ToeicPractice() {
const navigate = useNavigate()
const { startExam } = useTestStore()
const [loadingPartId, setLoadingPartId] = useState<number | null>(null)
const { requireAuth } = useRequireAuth()
async function handleSelectPart(partId: number, partName: string) {
if (!requireAuth()) return
setLoadingPartId(partId)
try {
const questions = await fetchQuestions(partId, 10)
startExam(partId, partName, questions)
navigate({ to: '/toeic/session' })
} catch (err) {
console.error('Failed to load questions:', err)
} finally {
setLoadingPartId(null)
}
}
return (
<div className="px-6 py-8 max-w-6xl mx-auto page-enter">
<div className="mb-8">
<h1 className="text-3xl font-extrabold text-slate-800 mb-2">Chọn Part TOEIC</h1>
<p className="text-slate-500">
Hệ thống ôn luyện theo cấu trúc bài thi TOEIC thực tế. Chọn phần cụ thể đ bắt đu.
</p>
</div>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-5">
{TOEIC_PARTS.map((part) => (
<button
key={part.id}
onClick={() => handleSelectPart(part.id, part.nameVi)}
disabled={loadingPartId !== null}
className="bg-white rounded-2xl p-5 border border-slate-200 text-left hover:-translate-y-1 hover:shadow-md transition-all duration-200 group disabled:opacity-70 disabled:cursor-wait"
>
<div className="flex justify-between items-start mb-5">
<div className="w-10 h-10 bg-blue-50 rounded-xl flex items-center justify-center group-hover:bg-blue-600 transition-colors">
{loadingPartId === part.id ? (
<span className="w-4 h-4 border-2 border-blue-300 border-t-blue-600 rounded-full animate-spin" />
) : (
<span
className="material-symbols-outlined text-blue-600 group-hover:text-white transition-colors"
style={{ fontSize: 18 }}
>
{part.icon}
</span>
)}
</div>
<CircularProgress percent={part.progressPercent} size={44} />
</div>
<div className="font-extrabold text-lg text-slate-800 mb-0.5">{part.name}</div>
<div className="text-sm font-semibold text-slate-700 mb-2">{part.nameVi}</div>
<div className="flex items-center gap-1.5 text-xs text-slate-400">
<span className="material-symbols-outlined" style={{ fontSize: 14 }}>list_alt</span>
{part.questionCount} câu hỏi
</div>
</button>
))}
{/* Full Test card */}
<button
onClick={() => handleSelectPart(0, 'Full Test')}
className="relative rounded-2xl p-5 text-left overflow-hidden hover:-translate-y-1 hover:shadow-xl transition-all duration-200"
style={{ background: 'linear-gradient(135deg, #f59e0b, #d97706)' }}
>
<div className="absolute top-0 right-0 opacity-10">
<span className="material-symbols-outlined text-white" style={{ fontSize: 80 }}>
workspace_premium
</span>
</div>
<div className="relative z-10">
<div className="w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center mb-5">
<span className="material-symbols-outlined text-white" style={{ fontSize: 18 }}>
military_tech
</span>
</div>
<div className="font-extrabold text-2xl text-white mb-0.5">Full Test</div>
<div className="text-sm font-semibold text-amber-50 mb-2"> phỏng thi thật 2h</div>
<div className="flex items-center gap-1.5 text-xs text-amber-100">
<span className="material-symbols-outlined" style={{ fontSize: 14 }}>timer</span>
120 phút · 200 câu
</div>
</div>
</button>
</div>
{/* Tip */}
<div className="mt-8 bg-blue-50 border border-blue-100 rounded-2xl p-5 flex items-start gap-4">
<span className="material-symbols-outlined text-blue-600 flex-shrink-0 mt-0.5">tips_and_updates</span>
<div>
<div className="font-semibold text-blue-700 text-sm mb-1">Mẹo luyện thi</div>
<p className="text-slate-500 text-sm">
Bắt đu từ <strong>Part 5 (Điền từ)</strong> phần mang lại điểm nhanh nhất không phụ thuộc kỹ năng nghe. Mỗi ngày 20 câu, sau 2 tuần bạn sẽ thấy cải thiện rệt.
</p>
</div>
</div>
</div>
)
}