first commit
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
import React from 'react'
|
||||
|
||||
// ── Stat card data ────────────────────────────────────────────────────────────
|
||||
const STATS = [
|
||||
{
|
||||
id: 'pre-travel',
|
||||
icon: '♥',
|
||||
value: '24',
|
||||
label: 'In Pre-Travel',
|
||||
delta: '+3',
|
||||
deltaType: 'up',
|
||||
accent: 'violet',
|
||||
},
|
||||
{
|
||||
id: 'in-transit',
|
||||
icon: '◷',
|
||||
value: '8',
|
||||
label: 'In Transit',
|
||||
delta: null,
|
||||
accent: 'blue',
|
||||
},
|
||||
{
|
||||
id: 'at-risk',
|
||||
icon: '⌛',
|
||||
value: '11',
|
||||
label: 'At Risk',
|
||||
delta: '+2',
|
||||
deltaType: 'up',
|
||||
accent: 'amber',
|
||||
},
|
||||
{
|
||||
id: 'post-travel',
|
||||
icon: '✓',
|
||||
value: '47',
|
||||
label: 'In Post-Travel',
|
||||
delta: '+12%',
|
||||
deltaType: 'up',
|
||||
accent: 'teal',
|
||||
},
|
||||
]
|
||||
|
||||
// ── Placeholder patient journey rows ─────────────────────────────────────────
|
||||
const PATIENTS = [
|
||||
{ id: 'P-001', name: 'Maria Santos', departure: '2026-07-14', arrival: '2026-07-19', status: 'in-transit', email: 'name@example.com' },
|
||||
{ id: 'P-002', name: 'James Owusu', departure: '2026-07-12', arrival: '2026-07-20', status: 'at-risk', email: 'name@example.com' },
|
||||
{ id: 'P-003', name: 'Anya Kowalski', departure: '2026-07-12', arrival: '2026-07-21', status: 'in-transit', email: 'name@example.com' },
|
||||
{ id: 'P-004', name: 'Carlos Mendoza', departure: '2026-07-19', arrival: '2026-07-22', status: 'at-risk', email: 'name@example.com' },
|
||||
{ id: 'P-005', name: 'Priya Nair', departure: '2026-07-02', arrival: '2026-07-13', status: 'post-travel', email: 'name@example.com' },
|
||||
{ id: 'P-006', name: 'David Okonkwo', departure: '2026-07-19', arrival: '2026-07-24', status: 'pre-travel', email: 'name@example.com' },
|
||||
]
|
||||
|
||||
const STATUS_META = {
|
||||
'in-transit': { label: 'In Transit', className: 'status-in-transit' },
|
||||
'at-risk': { label: 'At Risk', className: 'status-at-risk' },
|
||||
'post-travel': { label: 'Post-Travel', className: 'status-post-travel' },
|
||||
'pre-travel': { label: 'Pre-Travel', className: 'status-pre-travel' },
|
||||
}
|
||||
|
||||
function getGreeting() {
|
||||
const h = new Date().getHours()
|
||||
if (h < 12) return 'Good morning'
|
||||
if (h < 17) return 'Good afternoon'
|
||||
return 'Good evening'
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard — main content viewport for CTM Concierge.
|
||||
* Shows real-time stat cards and a patient journey table.
|
||||
*/
|
||||
export default function Dashboard() {
|
||||
const today = new Date().toLocaleDateString('en-US', {
|
||||
weekday: 'long', year: 'numeric', month: 'long', day: 'numeric',
|
||||
})
|
||||
|
||||
return (
|
||||
<section className="dashboard" aria-label="Dashboard">
|
||||
|
||||
{/* ── Header ─────────────────────────────────────────────────────────── */}
|
||||
<header className="dashboard-header">
|
||||
<p className="dashboard-greeting">{getGreeting()}</p>
|
||||
<h1 className="dashboard-title">Patient Trip Overview</h1>
|
||||
<p className="dashboard-subtitle">{today}</p>
|
||||
</header>
|
||||
|
||||
{/* ── Stat Cards ─────────────────────────────────────────────────────── */}
|
||||
<div className="stat-grid" role="list" aria-label="Today's statistics">
|
||||
{STATS.map((stat) => (
|
||||
<article
|
||||
key={stat.id}
|
||||
id={`stat-${stat.id}`}
|
||||
className={`stat-card accent-${stat.accent}`}
|
||||
role="listitem"
|
||||
>
|
||||
<span className="stat-card-icon" aria-hidden="true">{stat.icon}</span>
|
||||
<div className="stat-card-value">{stat.value}</div>
|
||||
<div className="stat-card-label">{stat.label}</div>
|
||||
{stat.delta && (
|
||||
<span className={`stat-card-delta delta-${stat.deltaType}`} aria-label={`Change: ${stat.delta}`}>
|
||||
{stat.delta}
|
||||
</span>
|
||||
)}
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* ── Patient Journey Table ───────────────────────────────────────────── */}
|
||||
<div className="section-heading">
|
||||
<h2 className="section-title">Live Patient Board</h2>
|
||||
<span className="section-action" role="button" tabIndex={0}>View all →</span>
|
||||
</div>
|
||||
|
||||
<div className="journey-panel">
|
||||
<table className="journey-table" aria-label="Live patient journey board">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">ID</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Email</th>
|
||||
<th scope="col">Departure</th>
|
||||
<th scope="col">Arrival</th>
|
||||
<th scope="col">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{PATIENTS.map((p) => {
|
||||
const meta = STATUS_META[p.status]
|
||||
return (
|
||||
<tr key={p.id} id={`patient-row-${p.id}`}>
|
||||
<td>{p.id}</td>
|
||||
<td className="patient-name">{p.name}</td>
|
||||
<td>{p.email}</td>
|
||||
<td>{p.departure}</td>
|
||||
<td>{p.arrival}</td>
|
||||
<td>
|
||||
<span className={`status-pill ${meta.className}`}>
|
||||
{meta.label}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user