import { cn } from '@/lib/cn' type Tone = 'muted' | 'safe' | 'warn' | 'danger' type ComputedSla = { tone: Tone label: string percent: number deadline: Date | null } function compute(deadline: string | null, createdAt: string | null | undefined): ComputedSla { if (!deadline) return { tone: 'muted', label: 'Không có SLA', percent: 0, deadline: null } const now = Date.now() const end = new Date(deadline).getTime() const start = createdAt ? new Date(createdAt).getTime() : end - 7 * 24 * 60 * 60 * 1000 const remaining = end - now const total = Math.max(end - start, 1) const elapsed = Math.min(Math.max(now - start, 0), total) const percent = (elapsed / total) * 100 if (remaining <= 0) { const overdueMs = -remaining const d = Math.floor(overdueMs / 86_400_000) const h = Math.floor((overdueMs % 86_400_000) / 3_600_000) const overdueLabel = d > 0 ? `${d} ngày ${h}h` : `${h}h` return { tone: 'danger', label: `Quá hạn ${overdueLabel}`, percent: 100, deadline: new Date(end) } } const days = Math.floor(remaining / 86_400_000) const hours = Math.floor((remaining % 86_400_000) / 3_600_000) const remainingLabel = days > 0 ? `${days} ngày ${hours}h` : `${hours}h` const tone: Tone = percent >= 80 ? 'warn' : 'safe' return { tone, label: `Còn ${remainingLabel}`, percent, deadline: new Date(end) } } const toneClasses: Record = { muted: { text: 'text-slate-400', bar: 'bg-slate-300', track: 'bg-slate-100' }, safe: { text: 'text-emerald-600', bar: 'bg-emerald-500', track: 'bg-emerald-50' }, warn: { text: 'text-amber-600', bar: 'bg-amber-500', track: 'bg-amber-50' }, danger: { text: 'text-red-600', bar: 'bg-red-500', track: 'bg-red-50' }, } export function SlaTimer({ deadline, createdAt, variant = 'inline', className, }: { deadline: string | null createdAt?: string | null variant?: 'inline' | 'full' className?: string }) { const s = compute(deadline, createdAt) const cls = toneClasses[s.tone] if (variant === 'inline') { return ( {s.tone === 'danger' && } {s.label} ) } return (
{s.label} {s.deadline && ( Hạn: {s.deadline.toLocaleString('vi-VN', { dateStyle: 'short', timeStyle: 'short' })} )}
) }