refactor: remove dead code — orphaned files, unused types and functions

Delete 3 orphaned files (SubNav, TopBar, problems.ts), remove 4 unused
type definitions from pmr.ts (ViewId, NavItem, ReferralFormData, Problem),
trim types/index.ts to only Phase, and remove unused utility functions
(calculateSkillOffset, formatBootLine, getProfileContent, DotColorName).
This commit is contained in:
2026-02-17 02:24:40 +00:00
parent 1b19087782
commit 5eb46b02d8
8 changed files with 1 additions and 516 deletions
-96
View File
@@ -1,96 +0,0 @@
interface NavSection {
id: string
label: string
tileId: string // data-tile-id to scroll to
}
interface SubNavProps {
activeSection: string
onSectionClick: (sectionId: string) => void
}
const sections: NavSection[] = [
{ id: 'overview', label: 'Overview', tileId: 'patient-summary' },
{ id: 'skills', label: 'Skills', tileId: 'section-skills' },
{ id: 'experience', label: 'Experience', tileId: 'section-experience' },
{ id: 'projects', label: 'Significant Interventions', tileId: 'projects' },
{ id: 'education', label: 'Education', tileId: 'section-education' },
]
export function SubNav({ activeSection, onSectionClick }: SubNavProps) {
const handleSectionClick = (section: NavSection) => {
// Scroll to the tile
const tileEl = document.querySelector(`[data-tile-id="${section.tileId}"]`)
if (tileEl) {
tileEl.scrollIntoView({ behavior: 'smooth', block: 'start' })
}
// Notify parent of section change
onSectionClick(section.id)
}
return (
<nav
aria-label="Section navigation"
className="subnav-scroll md:justify-center"
style={{
position: 'sticky',
top: 'var(--topbar-height)',
zIndex: 99,
height: 'var(--subnav-height)',
background: 'var(--surface)',
borderBottom: '1px solid var(--border-light)',
display: 'flex',
alignItems: 'center',
gap: '24px',
overflowX: 'auto',
overflowY: 'hidden',
padding: '0 16px',
scrollbarWidth: 'none',
}}
>
{sections.map((section) => {
const isActive = activeSection === section.id
return (
<button
key={section.id}
onClick={() => handleSectionClick(section)}
aria-current={isActive ? 'true' : undefined}
style={{
position: 'relative',
fontSize: '14px',
fontWeight: 500,
color: isActive ? 'var(--accent)' : 'var(--text-secondary)',
background: 'none',
border: 'none',
padding: '0 4px 2px',
cursor: 'pointer',
transition: 'color 200ms ease-out',
fontFamily: 'var(--font-ui)',
flexShrink: 0,
minHeight: '42px',
display: 'flex',
alignItems: 'center',
}}
>
{section.label}
{isActive && (
<span
style={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: '2px',
background: 'var(--accent)',
transition: 'all 200ms ease-out',
}}
aria-hidden="true"
/>
)}
</button>
)
})}
</nav>
)
}
-208
View File
@@ -1,208 +0,0 @@
import { useState, useEffect } from 'react'
import { Search } from 'lucide-react'
import { CvmisLogo } from './CvmisLogo'
interface TopBarProps {
onSearchClick?: () => void
}
export function TopBar({ onSearchClick }: TopBarProps) {
const [currentTime, setCurrentTime] = useState(() => formatTime(new Date()))
useEffect(() => {
const interval = setInterval(() => {
setCurrentTime(formatTime(new Date()))
}, 60_000)
return () => clearInterval(interval)
}, [])
return (
<header
className="fixed top-0 left-0 right-0 flex items-center justify-between font-ui"
style={{
height: 'var(--topbar-height)',
background: 'var(--surface)',
borderBottom: '1px solid var(--border)',
padding: '0 20px',
zIndex: 100,
}}
>
{/* Skip to main content link (only visible on focus) */}
<a
href="#main-content"
className="skip-link"
style={{
position: 'absolute',
top: '-40px',
left: '0',
background: 'var(--accent)',
color: '#FFFFFF',
padding: '8px 16px',
textDecoration: 'none',
zIndex: 101,
borderRadius: '0 0 4px 0',
fontSize: '14px',
fontWeight: 600,
}}
onFocus={(e) => {
e.currentTarget.style.top = '0'
}}
onBlur={(e) => {
e.currentTarget.style.top = '-40px'
}}
>
Skip to main content
</a>
{/* Brand */}
<div className="flex items-center gap-2 shrink-0">
<CvmisLogo size={24} />
<span
className="font-ui hidden sm:inline"
style={{
fontSize: '15px',
fontWeight: 600,
color: 'var(--text-primary)',
}}
>
Headhunt Medical Center
</span>
<span
className="font-ui sm:hidden"
style={{
fontSize: '15px',
fontWeight: 600,
color: 'var(--text-primary)',
}}
>
HMC
</span>
<span
className="hidden lg:inline"
style={{
fontSize: '12px',
fontWeight: 400,
color: 'var(--text-tertiary)',
marginLeft: '2px',
}}
>
Remote
</span>
</div>
{/* Search bar (center) — triggers command palette, no inline search */}
<button
type="button"
onClick={onSearchClick}
className="hidden lg:flex items-center gap-2 cursor-pointer font-ui"
style={{
maxWidth: '560px',
minWidth: '400px',
height: '46px',
border: '1.5px solid var(--border)',
borderRadius: 'var(--radius-card)',
padding: '0 14px',
background: 'var(--surface)',
transition: 'border-color 150ms, box-shadow 150ms',
}}
onMouseEnter={(e) => {
e.currentTarget.style.borderColor = 'var(--accent-border)'
}}
onMouseLeave={(e) => {
if (document.activeElement !== e.currentTarget) {
e.currentTarget.style.borderColor = 'var(--border)'
}
}}
onFocus={(e) => {
e.currentTarget.style.borderColor = 'var(--accent)'
e.currentTarget.style.boxShadow = '0 0 0 3px rgba(13,110,110,0.12)'
}}
onBlur={(e) => {
e.currentTarget.style.borderColor = 'var(--border)'
e.currentTarget.style.boxShadow = 'none'
}}
aria-label="Search records, experience, skills. Press Control plus K"
>
<Search
size={17}
style={{ color: 'var(--text-tertiary)', flexShrink: 0 }}
aria-hidden="true"
/>
<span
className="flex-1 text-left"
style={{
fontSize: '14px',
color: 'var(--text-tertiary)',
fontFamily: 'var(--font-ui)',
}}
>
Search records, experience, skills...
</span>
<kbd
className="font-geist"
style={{
fontSize: '11px',
color: 'var(--text-tertiary)',
background: 'var(--bg-dashboard)',
border: '1px solid var(--border)',
padding: '2px 6px',
borderRadius: '4px',
lineHeight: 1,
}}
>
Ctrl+K
</kbd>
</button>
{/* Session info (right) */}
<div
className="flex items-center gap-2 sm:gap-3 shrink-0"
aria-label="Active session information"
>
<span
className="hidden sm:inline"
style={{
fontSize: '13px',
color: 'var(--text-secondary)',
fontFamily: 'var(--font-ui)',
}}
>
A.RECRUITER
</span>
<span
className="font-geist hidden xs:inline"
style={{
fontSize: '12px',
color: 'var(--text-tertiary)',
background: 'var(--accent-light)',
padding: '3px 10px',
borderRadius: '4px',
border: '1px solid var(--accent-border)',
}}
>
Active Session · {currentTime}
</span>
<span
className="font-geist xs:hidden"
style={{
fontSize: '12px',
color: 'var(--text-tertiary)',
background: 'var(--accent-light)',
padding: '3px 8px',
borderRadius: '4px',
border: '1px solid var(--accent-border)',
}}
>
{currentTime}
</span>
</div>
</header>
)
}
function formatTime(date: Date): string {
return date.toLocaleTimeString('en-GB', {
hour: '2-digit',
minute: '2-digit',
hour12: false,
})
}
-111
View File
@@ -1,111 +0,0 @@
import type { Problem } from '@/types/pmr'
export const problems: Problem[] = [
{
id: 'prob-budget',
code: 'MGT001',
description: '£220M prescribing budget oversight and management',
since: 'Jul 2024',
status: 'Active',
narrative: 'Responsible for managing the £220M prescribing budget for NHS Norfolk & Waveney ICB. Developed sophisticated forecasting models identifying cost pressures and enabling proactive financial planning. This is an ongoing responsibility requiring continuous monitoring and strategic intervention.',
linkedConsultations: ['deputy-head-2024'],
},
{
id: 'prob-sql-transform',
code: 'TRN001',
description: 'Patient-level SQL analytics transformation',
since: '2025',
status: 'In Progress',
narrative: 'Leading transformation from practice-level data to patient-level SQL analytics, enabling targeted interventions and a self-serve model for the wider team. This foundational change will unlock previously impossible analysis at population scale.',
linkedConsultations: ['interim-head-2025', 'deputy-head-2024'],
},
{
id: 'prob-data-literacy',
code: 'LEA001',
description: 'Team data literacy programme',
since: 'Jul 2024',
status: 'In Progress',
narrative: 'Educating colleagues on data interpretation and analytics best practices, improving data fluency across the team through training, documentation, and self-serve tools. Ongoing initiative to build sustainable analytical capability.',
linkedConsultations: ['deputy-head-2024'],
},
{
id: 'prob-efficiency',
code: 'EFF001',
description: 'Manual prescribing analysis inefficiency',
resolved: 'Oct 2025',
status: 'Resolved',
outcome: 'Python algorithm: 14,000 pts, £2.6M/yr',
narrative: 'Built Python-based switching algorithm using real-world GP prescribing data to automatically identify patients on expensive drugs suitable for cost-effective alternatives. Compressed months of manual analysis into 3 days. Identified 14,000 patients and £2.6M in annual savings, with £2M on target for delivery this financial year.',
linkedConsultations: ['interim-head-2025'],
},
{
id: 'prob-efficiency-target',
code: 'EFF002',
description: '£14.6M efficiency target identification and delivery',
resolved: 'Oct 2025',
status: 'Resolved',
outcome: 'Over-target performance achieved',
narrative: 'Identified and prioritised a £14.6M efficiency programme through comprehensive data analysis. Achieved over-target performance by October 2025 through targeted, evidence-based interventions across the integrated care system.',
linkedConsultations: ['interim-head-2025'],
},
{
id: 'prob-blueteq-backlog',
code: 'AUT001',
description: 'Blueteq form creation backlog',
resolved: '2023',
status: 'Resolved',
outcome: '70% reduction, 200hrs saved',
narrative: 'Developed software automating Blueteq prior approval form creation. Achieved 70% reduction in required forms, 200 hours immediate savings, and ongoing 78 hours weekly efficiency gains.',
linkedConsultations: ['high-cost-drugs-2022'],
},
{
id: 'prob-asthma-screening',
code: 'INN001',
description: 'Asthma screening scalability',
resolved: '2019',
status: 'Resolved',
outcome: 'National rollout: ~300 branches, ~£1M',
narrative: 'Identified and shared an asthma screening process that was adopted nationally across the Tesco pharmacy estate (~300 branches). Reduced pharmacist time from approximately 60 hours to 6 hours per store per month, enabling the network to claim approximately £1M in revenue.',
linkedConsultations: ['pharmacy-manager-2017'],
},
{
id: 'prob-incentive-calc',
code: 'AUT002',
description: 'Incentive scheme manual calculation',
resolved: '2025',
status: 'Resolved',
outcome: 'Automated: 50% Rx reduction in 2 months',
narrative: 'Automated incentive scheme analysis, improving accuracy and targeting precision whilst enabling a novel GP payment system linking rewards to delivered savings. Achieved 50% reduction in targeted prescribing within the first two months of deployment.',
linkedConsultations: ['interim-head-2025'],
},
{
id: 'prob-hcd-tracking',
code: 'DAT001',
description: 'High-cost drug spend tracking gaps',
resolved: '2023',
status: 'Resolved',
outcome: 'Blueteq-secondary care data integration',
narrative: 'Integrated Blueteq data with secondary care activity databases, resolving critical data-matching limitations and enabling accurate high-cost drug spend tracking across the system.',
linkedConsultations: ['high-cost-drugs-2022'],
},
{
id: 'prob-pathway-opacity',
code: 'VIS001',
description: 'Patient pathway opacity',
resolved: '2023',
status: 'Resolved',
outcome: 'Sankey chart analysis tool',
narrative: 'Created Python-based Sankey chart analysis tool visualising patient journeys through high-cost drug pathways, enabling trusts to audit compliance and identify improvement opportunities.',
linkedConsultations: ['high-cost-drugs-2022'],
},
{
id: 'prob-opioid-monitoring',
code: 'MON001',
description: 'Population opioid exposure monitoring',
resolved: '2024',
status: 'Resolved',
outcome: 'CD monitoring system: OME tracking',
narrative: 'Developed Python-based controlled drug monitoring system calculating oral morphine equivalents across all opioid prescriptions to track patient-level exposure over time, identifying high-risk patients and potential diversion—enabling previously impossible patient safety analysis at population scale.',
linkedConsultations: ['deputy-head-2024'],
},
]
-5
View File
@@ -5,16 +5,11 @@ import type {
EducationCopyEntry, EducationCopyEntry,
ExperienceEducationUICopy, ExperienceEducationUICopy,
LatestResultsCopy, LatestResultsCopy,
ProfileContent,
QuickActionCopyEntry, QuickActionCopyEntry,
SidebarCopy, SidebarCopy,
SkillsUICopy, SkillsUICopy,
} from '@/types/profile-content' } from '@/types/profile-content'
export function getProfileContent(): DeepReadonly<ProfileContent> {
return profileContent
}
export function getProfileSummaryText(): string { export function getProfileSummaryText(): string {
return profileContent.profile.patientSummaryNarrative return profileContent.profile.patientSummaryNarrative
} }
-2
View File
@@ -7,8 +7,6 @@ export const DOT_COLORS = {
purple: '#7C3AED', purple: '#7C3AED',
} as const } as const
export type DotColorName = keyof typeof DOT_COLORS
/** KPI color variants (subset of DOT_COLORS) */ /** KPI color variants (subset of DOT_COLORS) */
export const KPI_COLORS: Record<'green' | 'amber' | 'teal', string> = { export const KPI_COLORS: Record<'green' | 'amber' | 'teal', string> = {
green: DOT_COLORS.green, green: DOT_COLORS.green,
-9
View File
@@ -1,12 +1,3 @@
export function calculateSkillOffset(level: number, radius: number): number {
const circumference = 2 * Math.PI * radius
return circumference * (1 - level / 100)
}
export function formatBootLine(text: string): string {
return text
}
export function hexToRgba(hex: string, opacity: number): string { export function hexToRgba(hex: string, opacity: number): string {
const r = parseInt(hex.slice(1, 3), 16) const r = parseInt(hex.slice(1, 3), 16)
const g = parseInt(hex.slice(3, 5), 16) const g = parseInt(hex.slice(3, 5), 16)
-40
View File
@@ -1,41 +1 @@
export interface Skill {
name: string
level: number
category: 'Technical' | 'Clinical' | 'Strategic'
color: 'teal' | 'coral'
}
export interface Experience {
role: string
org: string
date: string
bullets: string[]
isCurrent?: boolean
}
export interface Education {
degree: string
institution: string
period: string
detail: string
}
export interface Project {
title: string
description: string
link?: string
}
export interface ContactItem {
icon: 'phone' | 'mail' | 'linkedin' | 'mapPin'
value: string
label: string
href?: string
}
export type Phase = 'boot' | 'ecg' | 'login' | 'pmr' export type Phase = 'boot' | 'ecg' | 'login' | 'pmr'
export interface BootLine {
html: string
delay: number
}
+1 -45
View File
@@ -48,34 +48,6 @@ export interface PrescribingHistoryEntry {
description: string description: string
} }
export interface Medication {
id: string
name: string
dose: number
frequency: 'Daily' | 'Weekly' | 'Monthly' | 'As needed'
startYear: number
status: 'Active' | 'Historical'
category: 'Active' | 'Clinical' | 'PRN'
prescribingHistory: PrescribingHistoryEntry[]
}
export interface Problem {
id: string
code: string
description: string
since?: string
resolved?: string
status: 'Active' | 'In Progress' | 'Resolved'
outcome?: string
narrative?: string
linkedConsultations?: string[]
}
export interface InvestigationResult {
label: string
value: string
}
export interface Investigation { export interface Investigation {
id: string id: string
name: string name: string
@@ -123,23 +95,6 @@ export interface Patient {
registrationYear: string registrationYear: string
} }
export type ViewId = 'summary' | 'consultations' | 'medications' | 'problems' | 'investigations' | 'documents' | 'referrals'
export interface NavItem {
id: ViewId
label: string
icon: string
}
export interface ReferralFormData {
priority: 'Urgent' | 'Routine' | 'Two-Week Wait'
referrerName: string
referrerEmail: string
referrerOrg?: string
reason: string
contactMethod: 'Email' | 'Phone' | 'LinkedIn'
}
export interface Tag { export interface Tag {
label: string label: string
colorVariant: 'teal' | 'amber' | 'green' colorVariant: 'teal' | 'amber' | 'green'
@@ -171,6 +126,7 @@ export interface SkillMedication {
category: 'Technical' | 'Domain' | 'Leadership' category: 'Technical' | 'Domain' | 'Leadership'
status: 'Active' | 'Historical' status: 'Active' | 'Historical'
icon: string icon: string
prescribingHistory?: PrescribingHistoryEntry[]
} }
// Skill categories for grouped display // Skill categories for grouped display