From 040e46cbea2943bfa1c7b5ee32e8c6043fd25a27 Mon Sep 17 00:00:00 2001 From: A Charlwood Date: Fri, 13 Feb 2026 17:21:32 +0000 Subject: [PATCH] Task 10: Build LatestResults tile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- src/components/DashboardLayout.tsx | 2 + src/components/tiles/LatestResultsTile.tsx | 72 ++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/components/tiles/LatestResultsTile.tsx diff --git a/src/components/DashboardLayout.tsx b/src/components/DashboardLayout.tsx index 89f85ca..4499620 100644 --- a/src/components/DashboardLayout.tsx +++ b/src/components/DashboardLayout.tsx @@ -3,6 +3,7 @@ import { motion } from 'framer-motion' import { TopBar } from './TopBar' import Sidebar from './Sidebar' import { PatientSummaryTile } from './tiles/PatientSummaryTile' +import { LatestResultsTile } from './tiles/LatestResultsTile' const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches @@ -98,6 +99,7 @@ export function DashboardLayout() { {/* LatestResultsTile — half width (left) */} + {/* CoreSkillsTile — half width (right) */} {/* LastConsultationTile — full width */} {/* CareerActivityTile — full width */} diff --git a/src/components/tiles/LatestResultsTile.tsx b/src/components/tiles/LatestResultsTile.tsx new file mode 100644 index 0000000..8823c28 --- /dev/null +++ b/src/components/tiles/LatestResultsTile.tsx @@ -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 = { + 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 ( +
+
{kpi.value}
+
{kpi.label}
+
{kpi.sub}
+
+ ) +} + +export function LatestResultsTile() { + const gridStyles: React.CSSProperties = { + display: 'grid', + gridTemplateColumns: '1fr 1fr', + gap: '12px', + } + + return ( + + +
+ {kpis.map((kpi) => ( + + ))} +
+
+ ) +}