Task 10: Build LatestResults tile

- Created LatestResultsTile with 2x2 metric grid displaying four KPIs
- Each MetricCard shows value (22px, colored by variant), label, and sub text
- Metric cards use 6px radius, border-light, dashboard background
- Data sourced from src/data/kpis.ts (Budget £220M, Savings £14.6M, Years 9+, Team 12)
- CardHeader with teal dot + "LATEST RESULTS" + "Updated May 2025" right text
- Added data-kpi-id attributes for Task 17 flip card interaction
- Wired into DashboardLayout as half-width tile (left column)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 17:21:32 +00:00
parent 6501439cef
commit 040e46cbea
2 changed files with 74 additions and 0 deletions
+2
View File
@@ -3,6 +3,7 @@ import { motion } from 'framer-motion'
import { TopBar } from './TopBar' import { TopBar } from './TopBar'
import Sidebar from './Sidebar' import Sidebar from './Sidebar'
import { PatientSummaryTile } from './tiles/PatientSummaryTile' import { PatientSummaryTile } from './tiles/PatientSummaryTile'
import { LatestResultsTile } from './tiles/LatestResultsTile'
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
@@ -98,6 +99,7 @@ export function DashboardLayout() {
<PatientSummaryTile /> <PatientSummaryTile />
{/* LatestResultsTile — half width (left) */} {/* LatestResultsTile — half width (left) */}
<LatestResultsTile />
{/* CoreSkillsTile — half width (right) */} {/* CoreSkillsTile — half width (right) */}
{/* LastConsultationTile — full width */} {/* LastConsultationTile — full width */}
{/* CareerActivityTile — full width */} {/* CareerActivityTile — full width */}
@@ -0,0 +1,72 @@
import React from 'react'
import { Card, CardHeader } from '../Card'
import { kpis } from '@/data/kpis'
import type { KPI } from '@/types/pmr'
const colorMap: Record<KPI['colorVariant'], string> = {
green: '#059669',
amber: '#D97706',
teal: '#0D6E6E',
}
interface MetricCardProps {
kpi: KPI
}
function MetricCard({ kpi }: MetricCardProps) {
const cardStyles: React.CSSProperties = {
padding: '14px',
borderRadius: 'var(--radius-sm)',
border: '1px solid var(--border-light)',
background: 'var(--bg-dashboard)',
}
const valueStyles: React.CSSProperties = {
fontSize: '22px',
fontWeight: 700,
letterSpacing: '-0.02em',
lineHeight: 1.2,
color: colorMap[kpi.colorVariant],
}
const labelStyles: React.CSSProperties = {
fontSize: '11px',
fontWeight: 500,
color: 'var(--text-secondary)',
marginTop: '3px',
}
const subStyles: React.CSSProperties = {
fontSize: '10px',
color: 'var(--text-tertiary)',
fontFamily: "'Geist Mono', monospace",
marginTop: '4px',
}
return (
<div style={cardStyles} data-kpi-id={kpi.id}>
<div style={valueStyles}>{kpi.value}</div>
<div style={labelStyles}>{kpi.label}</div>
<div style={subStyles}>{kpi.sub}</div>
</div>
)
}
export function LatestResultsTile() {
const gridStyles: React.CSSProperties = {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: '12px',
}
return (
<Card>
<CardHeader dotColor="teal" title="LATEST RESULTS" rightText="Updated May 2025" />
<div style={gridStyles}>
{kpis.map((kpi) => (
<MetricCard key={kpi.id} kpi={kpi} />
))}
</div>
</Card>
)
}