From 10be50eef57bf7a1bd248cafdf59909f25a9c38e Mon Sep 17 00:00:00 2001 From: queentiffany1111-cloud Date: Sat, 30 May 2026 14:19:54 +0000 Subject: [PATCH] feat(ui): redesign NFTCard with visual hierarchy and status indicator - Vaccine name promoted to h3 (most prominent element) - Date and issuer now use a dl with visible labels - Active/Revoked status badge added (green/red) - Card border color reflects revoked status - Tests updated to cover new layout and status badge Closes #2 --- frontend/src/components/NFTCard.jsx | 111 ++++++++++++++--------- frontend/src/components/NFTCard.test.jsx | 90 ++++++++++-------- 2 files changed, 120 insertions(+), 81 deletions(-) diff --git a/frontend/src/components/NFTCard.jsx b/frontend/src/components/NFTCard.jsx index 90cacc8..65f9219 100644 --- a/frontend/src/components/NFTCard.jsx +++ b/frontend/src/components/NFTCard.jsx @@ -36,6 +36,8 @@ export default function NFTCard({ record, onClick, loading = false }) { if (loading) return ; + const isRevoked = record.status === 'revoked'; + return (
(e.key === 'Enter' || e.key === ' ') && onClick?.()} style={{ background: '#1e293b', - border: '1px solid #334155', + border: `1px solid ${isRevoked ? '#7f1d1d' : '#334155'}`, borderRadius: 12, padding: '1.25rem', marginBottom: '1rem', @@ -55,52 +57,77 @@ export default function NFTCard({ record, onClick, loading = false }) { boxSizing: 'border-box', minWidth: 0, }} - onMouseEnter={(e) => (e.currentTarget.style.borderColor = '#38bdf8')} - onMouseLeave={(e) => (e.currentTarget.style.borderColor = '#334155')} + onMouseEnter={(e) => (e.currentTarget.style.borderColor = isRevoked ? '#f87171' : '#38bdf8')} + onMouseLeave={(e) => (e.currentTarget.style.borderColor = isRevoked ? '#7f1d1d' : '#334155')} > -
- + {/* Header: vaccine name (most prominent) + status badge */} +
+

💉 {record.vaccine_name} +

+ + {isRevoked ? '✕ Revoked' : '✓ Active'} -
- {record.dose_number != null && ( - = record.dose_series - ? '#166534' - : '#1e3a5f', - color: record.dose_series != null && record.dose_number >= record.dose_series - ? '#86efac' - : '#93c5fd', - whiteSpace: 'nowrap', - }} - > - {record.dose_series != null - ? `${record.dose_number}/${record.dose_series} doses` - : `Dose ${record.dose_number}`} - - )} - - #{record.token_id} - - -
-

- Date: {record.date_administered} -

-

- Issuer: - - {record.issuer?.slice(0, 8)}…{record.issuer?.slice(-4)} + + {/* Dose + token ID */} +

+ {record.dose_number != null && ( + = record.dose_series + ? '#166534' + : '#1e3a5f', + color: record.dose_series != null && record.dose_number >= record.dose_series + ? '#86efac' + : '#93c5fd', + whiteSpace: 'nowrap', + }} + > + {record.dose_series != null + ? `${record.dose_number}/${record.dose_series} doses` + : `Dose ${record.dose_number}`} - -

+ )} + + #{record.token_id} + + +
+ + {/* Labelled meta fields */} +
+
Date
+
{record.date_administered}
+ +
Issuer
+
+ + + {record.issuer?.slice(0, 8)}…{record.issuer?.slice(-4)} + + +
+
+