Files
english/src/features/writing/components/WritingHistory.tsx
2026-04-13 13:45:18 +07:00

135 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from 'react'
import { useWritingHistory } from '@/hooks/use-writing-history'
import { useAuthStore } from '@/store/auth-store'
import type { WritingSubmission } from '@/types'
function scoreColor(score: string) {
const n = parseFloat(score)
if (n >= 7) return 'bg-green-100 text-green-700'
if (n >= 5) return 'bg-amber-100 text-amber-700'
return 'bg-red-100 text-red-700'
}
function relativeTime(iso: string) {
const diff = Date.now() - new Date(iso).getTime()
const mins = Math.floor(diff / 60_000)
if (mins < 1) return 'vừa xong'
if (mins < 60) return `${mins} phút trước`
const hours = Math.floor(mins / 60)
if (hours < 24) return `${hours} giờ trước`
return `${Math.floor(hours / 24)} ngày trước`
}
function SubmissionCard({ item }: { item: WritingSubmission }) {
const [open, setOpen] = useState(false)
const fb = item.feedback
return (
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
<button
onClick={() => setOpen((v) => !v)}
className="w-full text-left p-4 flex items-start gap-3 hover:bg-slate-50 transition-colors"
>
<span className={`text-xs font-bold px-2 py-1 rounded-lg flex-shrink-0 mt-0.5 ${scoreColor(fb?.score ?? '0')}`}>
{fb?.score ?? ''}
</span>
<div className="flex-1 min-w-0">
<p className="text-sm text-slate-700 line-clamp-1">{item.content}</p>
<p className="text-xs text-slate-400 mt-0.5">{relativeTime(item.created_at)}</p>
</div>
<span className="material-symbols-outlined text-slate-400 flex-shrink-0 mt-0.5" style={{ fontSize: 18 }}>
{open ? 'expand_less' : 'expand_more'}
</span>
</button>
{open && fb && (
<div className="border-t border-slate-100 p-4 space-y-4">
<div>
<p className="text-xs text-slate-400 mb-2">Bài viết gốc</p>
<p className="text-xs text-slate-600 leading-relaxed whitespace-pre-wrap">{item.content}</p>
</div>
{fb.grammar?.length > 0 && (
<div>
<p className="text-xs font-semibold text-slate-600 mb-1.5 flex items-center gap-1.5">
<span className="w-1.5 h-1.5 rounded-full bg-red-500 inline-block" />
Ngữ pháp
</p>
<ul className="space-y-1">
{fb.grammar.map((g, i) => (
<li key={i} className="text-xs text-slate-600 flex gap-1.5">
<span className="text-red-400 flex-shrink-0"></span>{g}
</li>
))}
</ul>
</div>
)}
{fb.vocabulary?.length > 0 && (
<div>
<p className="text-xs font-semibold text-slate-600 mb-1.5 flex items-center gap-1.5">
<span className="w-1.5 h-1.5 rounded-full bg-amber-500 inline-block" />
Từ vựng
</p>
<ul className="space-y-1">
{fb.vocabulary.map((v, i) => (
<li key={i} className="text-xs text-slate-600 flex gap-1.5">
<span className="text-amber-400 flex-shrink-0"></span>{v}
</li>
))}
</ul>
</div>
)}
{fb.structure && (
<div>
<p className="text-xs font-semibold text-slate-600 mb-1">Cấu trúc</p>
<p className="text-xs text-slate-600">{fb.structure}</p>
</div>
)}
{fb.summary && (
<div className="bg-green-50 rounded-lg p-3">
<p className="text-xs font-semibold text-green-700 mb-1">Tổng nhận xét</p>
<p className="text-xs text-slate-600">{fb.summary}</p>
</div>
)}
</div>
)}
</div>
)
}
export function WritingHistory() {
const user = useAuthStore((s) => s.user)
const { data: history, isLoading } = useWritingHistory()
if (!user) return null
return (
<section className="px-4 lg:px-6 pb-10 max-w-6xl mx-auto">
<h2 className="text-lg font-bold text-slate-800 mb-4">Lịch sử chấm bài</h2>
{isLoading && (
<div className="flex items-center gap-2 text-sm text-slate-400">
<div className="w-4 h-4 border-2 border-slate-200 border-t-blue-500 rounded-full animate-spin" />
Đang tải...
</div>
)}
{!isLoading && !history?.length && (
<div className="text-center py-10 text-slate-400">
<span className="material-symbols-outlined mb-2 block" style={{ fontSize: 36 }}>history</span>
<p className="text-sm">Chưa bài nào đưc chấm.</p>
</div>
)}
{!!history?.length && (
<div className="space-y-2">
{history.map((item) => <SubmissionCard key={item.id} item={item} />)}
</div>
)}
</section>
)
}