import React, { useState, useCallback } from 'react' import { Card, CardHeader } from '../Card' import { documents } from '@/data/documents' import { consultations } from '@/data/consultations' import { skills } from '@/data/skills' import { useDetailPanel } from '@/contexts/DetailPanelContext' import CareerConstellation from '../CareerConstellation' type ActivityType = 'role' | 'project' | 'cert' | 'edu' interface ActivityEntry { id: string type: ActivityType title: string meta: string date: string sortYear: number /** ID of the corresponding consultation in consultations.ts (role entries only) */ consultationId?: string } /** * Build timeline from multiple data sources * Matches the concept HTML entries exactly */ function buildTimeline(): ActivityEntry[] { const entries: ActivityEntry[] = [] // Roles from consultations entries.push({ id: 'interim-head-2025', type: 'role', title: 'Interim Head, Population Health & Data Analysis', meta: 'NHS Norfolk & Waveney ICB', date: '2024 – 2025', sortYear: 2024, consultationId: 'interim-head-2025', }) entries.push({ id: 'deputy-head-2024', type: 'role', title: 'Senior Data Analyst — Medicines Optimisation', meta: 'NHS Norfolk & Waveney ICB', date: '2021 – 2024', sortYear: 2021, consultationId: 'deputy-head-2024', }) entries.push({ id: 'high-cost-drugs-2022', type: 'role', title: 'Prescribing Data Pharmacist', meta: 'NHS Norwich CCG', date: '2018 – 2021', sortYear: 2018, consultationId: 'pharmacy-manager-2017', }) entries.push({ id: 'community-pharmacist-2016', type: 'role', title: 'Community Pharmacist', meta: 'Boots UK', date: '2016 – 2018', sortYear: 2016, consultationId: 'duty-pharmacist-2016', }) // Projects entries.push({ id: 'inv-budget', type: 'project', title: '£220M Prescribing Budget Oversight', meta: 'Lead analyst & budget owner', date: '2024', sortYear: 2024, }) entries.push({ id: 'inv-sql-transform', type: 'project', title: 'SQL Analytics Transformation', meta: 'Legacy migration project lead', date: '2025', sortYear: 2025, }) // Certifications entries.push({ id: 'cert-powerbi', type: 'cert', title: 'Power BI Data Analyst Associate', meta: 'Microsoft Certified', date: '2023', sortYear: 2023, }) entries.push({ id: 'cert-diploma', type: 'cert', title: 'Clinical Pharmacy Diploma', meta: 'Professional development', date: '2019', sortYear: 2019, }) entries.push({ id: 'doc-gphc', type: 'cert', title: 'GPhC Registration', meta: 'General Pharmaceutical Council', date: 'August 2016', sortYear: 2016, }) // Education const mpharm = documents.find((d) => d.id === 'doc-mpharm') if (mpharm) { entries.push({ id: mpharm.id, type: 'edu', title: 'MPharm (Hons) — 2:1', meta: 'University of East Anglia', date: '2011 – 2015', sortYear: 2011, }) } return entries.sort((a, b) => { if (b.sortYear !== a.sortYear) return b.sortYear - a.sortYear return 0 }) } const dotColorMap: Record = { role: '#0D6E6E', project: '#D97706', cert: '#059669', edu: '#7C3AED', } interface ActivityItemProps { entry: ActivityEntry onItemClick: () => void } const ActivityItem: React.FC = ({ entry, onItemClick }) => { const [isHovered, setIsHovered] = useState(false) const dotColor = dotColorMap[entry.type] const isClickable = entry.type === 'role' && entry.consultationId const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (!isClickable) return if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() onItemClick() } }, [isClickable, onItemClick], ) // Get consultation data for preview text const consultation = isClickable ? consultations.find((c) => c.id === entry.consultationId) : null // Get preview text (first 1-2 lines from examination) const previewText = consultation && consultation.examination.length > 0 ? consultation.examination[0] : null return (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} style={{ display: 'flex', flexDirection: 'column', background: 'var(--bg-dashboard)', borderRadius: 'var(--radius-sm)', border: '1px solid var(--border-light)', fontSize: '12px', transition: 'all 0.15s ease-out', cursor: isClickable ? 'pointer' : 'default', transform: isHovered && isClickable ? 'translateY(-1px)' : 'none', boxShadow: isHovered && isClickable ? '0 2px 8px rgba(26,43,42,0.08)' : '0 1px 2px rgba(26,43,42,0.05)', borderColor: isHovered && isClickable ? 'var(--accent-border)' : 'var(--border-light)', }} > {/* Item header row */}
) } export const CareerActivityTile: React.FC = () => { const timeline = buildTimeline() const { openPanel } = useDetailPanel() const handleRoleClick = useCallback( (roleId: string) => { const consultation = consultations.find((c) => c.id === roleId) if (consultation) { openPanel({ type: 'career-role', consultation }) } }, [openPanel], ) const handleSkillClick = useCallback( (skillId: string) => { const skill = skills.find((s) => s.id === skillId) if (skill) { openPanel({ type: 'skill', skill }) } }, [openPanel], ) const handleItemClick = useCallback( (entry: ActivityEntry) => { if (entry.type === 'role' && entry.consultationId) { handleRoleClick(entry.consultationId) } }, [handleRoleClick], ) return (
{timeline.map((entry) => ( handleItemClick(entry)} /> ))}
) }