refactor files
This commit is contained in:
86
src/features/settings/components/ExamDateCard.tsx
Normal file
86
src/features/settings/components/ExamDateCard.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
const STORAGE_KEY = 'settings_exam_date'
|
||||
|
||||
function getDaysUntil(dateStr: string): number {
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
const target = new Date(dateStr)
|
||||
target.setHours(0, 0, 0, 0)
|
||||
return Math.ceil((target.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
|
||||
}
|
||||
|
||||
function formatVi(dateStr: string): string {
|
||||
const d = new Date(dateStr)
|
||||
return d.toLocaleDateString('vi-VN', { day: 'numeric', month: 'long', year: 'numeric' })
|
||||
}
|
||||
|
||||
export function ExamDateCard() {
|
||||
const [examDate, setExamDate] = useState<string>(() => localStorage.getItem(STORAGE_KEY) ?? '')
|
||||
const [editing, setEditing] = useState(false)
|
||||
const [input, setInput] = useState(examDate)
|
||||
|
||||
function save() {
|
||||
if (!input) return
|
||||
setExamDate(input)
|
||||
localStorage.setItem(STORAGE_KEY, input)
|
||||
setEditing(false)
|
||||
}
|
||||
|
||||
const days = examDate ? getDaysUntil(examDate) : null
|
||||
|
||||
return (
|
||||
<section className="col-span-12 md:col-span-6 bg-white rounded-xl p-6 shadow-sm flex flex-col">
|
||||
<h2 className="text-lg font-bold mb-5 flex items-center gap-2 text-slate-800">
|
||||
<span className="material-symbols-outlined text-blue-600" style={{ fontSize: 22 }}>calendar_month</span>
|
||||
Ngày thi TOEIC
|
||||
</h2>
|
||||
|
||||
<div className="flex-1 flex flex-col justify-center">
|
||||
{examDate && days !== null ? (
|
||||
<>
|
||||
<div className="bg-gradient-to-br from-blue-600 to-blue-500 rounded-xl p-6 text-white text-center shadow-lg shadow-blue-200">
|
||||
<p className="text-sm font-medium opacity-80 mb-1">Đếm ngược kỳ thi</p>
|
||||
<p className="text-4xl font-extrabold tracking-tight">
|
||||
{days > 0 ? `Còn ${days} ngày` : days === 0 ? 'Hôm nay!' : 'Đã qua'}
|
||||
</p>
|
||||
<div className="mt-3 inline-flex items-center gap-1.5 px-3 py-1 bg-white/20 rounded-full text-xs">
|
||||
<span className="material-symbols-outlined" style={{ fontSize: 12 }}>event</span>
|
||||
<span>{formatVi(examDate)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => { setInput(examDate); setEditing(true) }}
|
||||
className="mt-4 w-full py-2.5 rounded-full border border-blue-200 text-blue-600 font-bold text-sm hover:bg-blue-50 transition-colors"
|
||||
>
|
||||
Thay đổi ngày thi
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<div className="text-center py-6">
|
||||
<span className="material-symbols-outlined text-slate-300 mb-2" style={{ fontSize: 48 }}>event_upcoming</span>
|
||||
<p className="text-slate-400 text-sm mb-4">Chưa đặt ngày thi</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{editing || !examDate ? (
|
||||
<div className="mt-3 flex gap-2">
|
||||
<input
|
||||
type="date"
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
min={new Date().toISOString().split('T')[0]}
|
||||
className="flex-1 border border-slate-200 rounded-lg px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-blue-200"
|
||||
/>
|
||||
<button onClick={save} disabled={!input} className="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-bold disabled:opacity-40 hover:bg-blue-700 transition-colors">
|
||||
Lưu
|
||||
</button>
|
||||
{editing && (
|
||||
<button onClick={() => setEditing(false)} className="px-3 py-2 text-slate-400 text-sm">Huỷ</button>
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user