feat: US-005 - Restructure Patient Summary as parent section with Latest Results subsection

This commit is contained in:
2026-02-14 17:59:41 +00:00
parent 9be2fb9017
commit c86b252629
2 changed files with 104 additions and 65 deletions
+2 -5
View File
@@ -6,7 +6,6 @@ import Sidebar from './Sidebar'
import { CommandPalette } from './CommandPalette'
import { DetailPanel } from './DetailPanel'
import { PatientSummaryTile } from './tiles/PatientSummaryTile'
import { LatestResultsTile } from './tiles/LatestResultsTile'
import { CoreSkillsTile } from './tiles/CoreSkillsTile'
import { LastConsultationTile } from './tiles/LastConsultationTile'
import { CareerActivityTile } from './tiles/CareerActivityTile'
@@ -165,12 +164,10 @@ export function DashboardLayout() {
}}
>
<div className="dashboard-grid">
{/* PatientSummaryTile — full width */}
{/* PatientSummaryTile — full width (includes Latest Results subsection) */}
<PatientSummaryTile />
{/* LatestResultsTile — half width (left) */}
<LatestResultsTile />
{/* ProjectsTile — half width (right) */}
{/* ProjectsTile — half width */}
<ProjectsTile />
{/* CoreSkillsTile — full width */}
+102 -60
View File
@@ -1,54 +1,105 @@
import React from 'react'
import { Card, CardHeader } from '../Card'
import { CardHeader } from '../Card'
import { ParentSection } from '../ParentSection'
import { kpis } from '@/data/kpis'
import type { KPI } from '@/types/pmr'
import { useDetailPanel } from '@/contexts/DetailPanelContext'
const colorMap: Record<KPI['colorVariant'], string> = {
green: '#059669',
amber: '#D97706',
teal: '#0D6E6E',
}
interface MetricCardProps {
kpi: KPI
}
function MetricCard({ kpi }: MetricCardProps) {
const { openPanel } = useDetailPanel()
const handleClick = () => {
openPanel({ type: 'kpi', kpi })
}
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
openPanel({ type: 'kpi', kpi })
}
}
const buttonStyles: React.CSSProperties = {
width: '100%',
textAlign: 'left',
padding: '16px',
background: 'var(--surface)',
border: '1px solid var(--border-light)',
borderRadius: 'var(--radius-sm)',
cursor: 'pointer',
transition: 'border-color 150ms ease-out, box-shadow 150ms ease-out',
}
const valueStyles: React.CSSProperties = {
fontSize: '28px',
fontWeight: 700,
letterSpacing: '-0.02em',
lineHeight: 1.2,
color: colorMap[kpi.colorVariant],
}
const labelStyles: React.CSSProperties = {
fontSize: '12px',
fontWeight: 500,
color: 'var(--text-primary)',
marginTop: '4px',
}
const subStyles: React.CSSProperties = {
fontSize: '10px',
color: 'var(--text-tertiary)',
fontFamily: 'var(--font-geist-mono)',
marginTop: '2px',
}
return (
<button
onClick={handleClick}
onKeyDown={handleKeyDown}
style={buttonStyles}
aria-label={`${kpi.label}: ${kpi.value}. Click to view details.`}
onMouseEnter={(e) => {
e.currentTarget.style.borderColor = 'var(--accent-border)'
e.currentTarget.style.boxShadow = 'var(--shadow-md)'
}}
onMouseLeave={(e) => {
e.currentTarget.style.borderColor = 'var(--border-light)'
e.currentTarget.style.boxShadow = 'none'
}}
>
<div style={valueStyles}>{kpi.value}</div>
<div style={labelStyles}>{kpi.label}</div>
<div style={subStyles}>{kpi.sub}</div>
</button>
)
}
export function PatientSummaryTile() {
// Key statistics from CV_v4.md
const highlights = [
{ label: '9+ Years', sublabel: 'Professional Experience' },
{ label: '1.2M', sublabel: 'Population Served' },
{ label: '£220M', sublabel: 'Budget Managed' },
{ label: '£14.6M+', sublabel: 'Savings Identified' },
]
const highlightStripStyles: React.CSSProperties = {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))',
gap: '12px',
marginBottom: '20px',
paddingBottom: '20px',
borderBottom: '1px solid var(--border-light)',
}
const highlightItemStyles: React.CSSProperties = {
display: 'flex',
flexDirection: 'column',
gap: '2px',
}
const highlightValueStyles: React.CSSProperties = {
fontSize: '18px',
fontWeight: 700,
color: 'var(--accent)',
fontFamily: 'var(--font-ui)',
}
const highlightLabelStyles: React.CSSProperties = {
fontSize: '11px',
fontWeight: 500,
color: 'var(--text-secondary)',
textTransform: 'uppercase',
letterSpacing: '0.02em',
}
const profileTextStyles: React.CSSProperties = {
fontSize: '13px',
lineHeight: '1.6',
color: 'var(--text-primary)',
}
// Split profile text into structured sections with bold key phrases
const renderProfileWithHierarchy = () => {
return (
const kpiGridStyles: React.CSSProperties = {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: '12px',
}
return (
<ParentSection title="Patient Summary" tileId="patient-summary">
{/* Profile text */}
<div style={profileTextStyles}>
<strong>Healthcare leader</strong> combining clinical pharmacy expertise with proficiency in{' '}
<strong>Python, SQL, and data analytics</strong>, self-taught over the past decade through a drive to find root causes in data and build the most efficient solutions to complex problems. Currently{' '}
@@ -58,25 +109,16 @@ export function PatientSummaryTile() {
<strong>£14.6M+</strong> through automated, data-driven analysis. Skilled at translating complex clinical, financial, and analytical requirements into clear recommendations for{' '}
<strong>executive stakeholders</strong>.
</div>
)
}
return (
<Card full tileId="patient-summary">
<CardHeader dotColor="teal" title="PATIENT SUMMARY" />
{/* Highlight strip with key stats */}
<div style={highlightStripStyles}>
{highlights.map((highlight, idx) => (
<div key={idx} style={highlightItemStyles}>
<div style={highlightValueStyles}>{highlight.label}</div>
<div style={highlightLabelStyles}>{highlight.sublabel}</div>
</div>
))}
{/* Latest Results subsection */}
<div style={{ marginTop: '24px' }}>
<CardHeader dotColor="teal" title="LATEST RESULTS" rightText="Updated May 2025" />
<div style={kpiGridStyles}>
{kpis.map((kpi) => (
<MetricCard key={kpi.id} kpi={kpi} />
))}
</div>
</div>
{/* Profile text with visual hierarchy through bold key phrases */}
{renderProfileWithHierarchy()}
</Card>
</ParentSection>
)
}