import { useMemo, useState, useCallback } from 'react' import { ChevronRight, ChevronDown, History } from 'lucide-react' import { motion, AnimatePresence } from 'framer-motion' import { ExpandableCardShell } from './ExpandableCardShell' import { useDetailPanel } from '@/contexts/DetailPanelContext' import { timelineEntities, timelineConsultations } from '@/data/timeline' import { getExperienceEducationUICopy } from '@/lib/profile-content' import type { TimelineEntity } from '@/types/pmr' import { hexToRgba, motionSafeTransition } from '@/lib/utils' const VISIBLE_COUNT = 4 interface TimelineInterventionItemProps { entity: TimelineEntity isExpanded: boolean isHighlightedFromGraph: boolean isDimmedByFocus: boolean isEducationAnchor: boolean onToggle: () => void onViewFull: () => void onHighlight?: (id: string | null) => void } function TimelineInterventionItem({ entity, isExpanded, isHighlightedFromGraph, isDimmedByFocus, isEducationAnchor, onToggle, onViewFull, onHighlight, }: TimelineInterventionItemProps) { const experienceEducationCopy = getExperienceEducationUICopy() const isEducation = entity.kind === 'education' const interventionLabel = isEducation ? experienceEducationCopy.educationLabel : experienceEducationCopy.employmentLabel return ( onHighlight?.(entity.id)} onMouseLeave={() => onHighlight?.(null)} renderHeader={() => (
{interventionLabel} {entity.dateRange.end === null && ( Current )}
{entity.title}
{entity.organization} {entity.dateRange.display}
{(entity.band || entity.employmentBasis) && (
{entity.band && ( Band {entity.band.toUpperCase()} )} {entity.employmentBasis && ( {entity.employmentBasis} )}
)}
)} renderBody={() => ( <> {entity.contextNote && (
{entity.contextNote}
)} {!!entity.codedEntries?.length && (
{entity.codedEntries.map((entry) => ( {entry.code}: {entry.description} ))}
)} )} /> ) } interface TimelineInterventionsSubsectionProps { onNodeHighlight?: (id: string | null) => void highlightedRoleId?: string | null focusRelatedIds?: Set | null } export function TimelineInterventionsSubsection({ onNodeHighlight, highlightedRoleId, focusRelatedIds }: TimelineInterventionsSubsectionProps) { const [expandedId, setExpandedId] = useState(null) const [historicalOpen, setHistoricalOpen] = useState(false) const { openPanel } = useDetailPanel() const visibleEntities = useMemo(() => timelineEntities.slice(0, VISIBLE_COUNT), []) const historicalEntities = useMemo(() => timelineEntities.slice(VISIBLE_COUNT), []) const consultationsById = useMemo( () => new Map(timelineConsultations.map((consultation) => [consultation.id, consultation])), [], ) const firstEducationId = useMemo( () => timelineEntities.find((entity) => entity.kind === 'education')?.id ?? null, [], ) const handleToggle = useCallback((id: string) => { setExpandedId((prev) => (prev === id ? null : id)) }, []) const handleViewFull = useCallback((entity: TimelineEntity) => { const consultation = consultationsById.get(entity.id) if (!consultation) return openPanel({ type: 'career-role', consultation }) }, [consultationsById, openPanel]) const historicalHasAnyFocusRelevance = focusRelatedIds !== null && focusRelatedIds !== undefined && historicalEntities.some((e) => focusRelatedIds.has(e.id)) const historicalDimmed = focusRelatedIds !== null && focusRelatedIds !== undefined && !historicalHasAnyFocusRelevance return (
{visibleEntities.map((entity) => ( handleToggle(entity.id)} onViewFull={() => handleViewFull(entity)} onHighlight={onNodeHighlight} /> ))} {historicalEntities.length > 0 && (
setHistoricalOpen((prev) => !prev)} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() setHistoricalOpen((prev) => !prev) } }} aria-expanded={historicalOpen} aria-label={`${historicalOpen ? 'Hide' : 'Show'} ${historicalEntities.length} historical entries`} style={{ display: 'flex', alignItems: 'center', gap: '8px', padding: '6px 10px', background: 'var(--bg-dashboard)', borderRadius: 'var(--radius-sm)', border: '1px solid var(--border-light)', cursor: 'pointer', transition: 'border-color 0.15s, box-shadow 0.15s', }} onMouseEnter={(e) => { e.currentTarget.style.borderColor = 'rgba(0, 137, 123, 0.2)' e.currentTarget.style.boxShadow = 'var(--shadow-md)' }} onMouseLeave={(e) => { e.currentTarget.style.borderColor = 'var(--border-light)' e.currentTarget.style.boxShadow = 'none' }} > {historicalOpen ? 'Hide' : 'View'} historical entries ({historicalEntities.length})
{historicalOpen && (
{historicalEntities.map((entity) => ( handleToggle(entity.id)} onViewFull={() => handleViewFull(entity)} onHighlight={onNodeHighlight} /> ))}
)}
)}
) }