From fcc3246d8efb0278895a5353a69e659f50ed10be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IT=E7=8B=97?= Date: Tue, 21 Jul 2026 22:31:26 +0800 Subject: [PATCH] StatusBadge: surface leave/holiday suffix as secondary chip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit status_text fields like '異常-遲到48分 + SL2h' or '缺勤 (🎉香港特區…)' carried important leave/holiday context that the simplified badge was dropping on the list page — the user had no way to tell an abnormal record was partly covered by sick leave. Extract the suffix from status_text and render a small secondary chip next to the basic-status badge (violet for leave types, indigo for holidays). Detail page picks this up automatically since the component is shared. Example: '異常 +SL2h' / '缺勤 🎉香港特區成立紀念日' --- frontend/src/components/StatusBadge.jsx | 59 ++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/StatusBadge.jsx b/frontend/src/components/StatusBadge.jsx index 6b2ca90..f0edc04 100644 --- a/frontend/src/components/StatusBadge.jsx +++ b/frontend/src/components/StatusBadge.jsx @@ -11,9 +11,13 @@ import { CheckCircle, AlertCircle, CalendarX, Palmtree, Briefcase } from 'lucide * - normal → 正常 (green) * - everything else (late/early/ot/abnormal/late_early/...) → 異常 (orange) * + * If status_text carries a leave/holiday suffix (e.g. '+ SL2h', '🎉香港…'), + * a small secondary chip is rendered next to the main badge so the list page + * shows the underlying leave/holiday detail without expanding the row. + * * Props: * - code: status_code string - * - text: status_text string (fallback signal) + * - text: status_text string (fallback signal + suffix source) * - size: 'sm' | 'md' (default 'sm') */ export default function StatusBadge({ code = '', text = '', size = 'sm' }) { @@ -28,32 +32,73 @@ export default function StatusBadge({ code = '', text = '', size = 'sm' }) { ) - const c = String(code || '').toLowerCase() + // Extract leave/holiday suffix from status_text: + // '異常-遲到48分 + SL2h' → ['SL2h'] + // '缺勤 (🎉香港特別行政區成立紀念日)' → ['🎉香港特別行政區成立紀念日'] + // 'OT3分 + AL4h + SL3h' → ['AL4h', 'SL3h'] + // '正常 + CL4h' → ['CL4h'] const t = String(text || '') + const noteParts = [] + const split = t.split(' + ').map(s => s.trim()) + if (split.length > 1) { + for (let i = 1; i < split.length; i++) { + noteParts.push(split[i].replace(/^\(|\)$/g, '').trim()) + } + } else if (t.includes('🎉')) { + const m = t.match(/🎉[^)\s]+(?:\s[^)\s]+)*/) + if (m) noteParts.push(m[0]) + } + + const noteChips = noteParts.filter(Boolean).map((part, idx) => { + // Strip trailing ')' + const clean = part.replace(/\)+$/, '') + const isHoliday = clean.startsWith('🎉') + const cls = isHoliday + ? 'bg-indigo-50 text-indigo-600 border border-indigo-200' + : 'bg-violet-50 text-violet-600 border border-violet-200' + return ( + + {isHoliday ? clean : `+${clean}`} + + ) + }) + + const wrap = (content) => ( + + {content} + {noteChips} + + ) + + const c = String(code || '').toLowerCase() // 缺勤 (missing) if (c === 'missing' || t === '缺勤') { - return badge(, '缺勤', 'bg-gray-200 text-gray-700') + return wrap(badge(, '缺勤', 'bg-gray-200 text-gray-700')) } // 公假 (holiday) if (c === 'holiday' || t.includes('公假') || t.includes('🏖️')) { - return badge(, '公假', 'bg-indigo-100 text-indigo-700') + return wrap(badge(, '公假', 'bg-indigo-100 text-indigo-700')) } // 請假 (any leave type) if (['al', 'sl', 'cl', 'mixed_leave'].includes(c) || t.includes('年假') || t.includes('病假') || t.includes('補鐘') || t.includes('混合假')) { - return badge(, '請假', 'bg-violet-100 text-violet-700') + return wrap(badge(, '請假', 'bg-violet-100 text-violet-700')) } // 正常 (only when status_code is 'normal' — text suffix like '+ CL4h' is allowed, // we still want to flag it as 正常 first since the employee did clock in/out normally) if (c === 'normal') { - return badge(, '正常', 'bg-green-100 text-green-700') + return wrap(badge(, '正常', 'bg-green-100 text-green-700')) } // 異常 (late/early/ot/abnormal/late_early/late_ot/early_ot/...) - return badge(, '異常', 'bg-orange-100 text-orange-700') + return wrap(badge(, '異常', 'bg-orange-100 text-orange-700')) } \ No newline at end of file