import { useRef, useEffect } from 'react'; import { useShallow } from 'zustand/react/shallow'; import { useMachineStore } from '../stores/useMachineStore'; import { useUIStore } from '../stores/useUIStore'; import { WorkflowStepper } from './WorkflowStepper'; import { ErrorPopover } from './ErrorPopover'; import { getStateVisualInfo } from '../utils/machineStateHelpers'; import { CheckCircleIcon, BoltIcon, PauseCircleIcon, ExclamationTriangleIcon, ArrowPathIcon, XMarkIcon, } from '@heroicons/react/24/solid'; export function AppHeader() { const { isConnected, machineInfo, machineStatus, machineStatusName, machineError, error: machineErrorMessage, isPairingError, isCommunicating: isPolling, disconnect, } = useMachineStore( useShallow((state) => ({ isConnected: state.isConnected, machineInfo: state.machineInfo, machineStatus: state.machineStatus, machineStatusName: state.machineStatusName, machineError: state.machineError, error: state.error, isPairingError: state.isPairingError, isCommunicating: state.isCommunicating, disconnect: state.disconnect, })) ); const { pyodideError, showErrorPopover, setErrorPopover, } = useUIStore( useShallow((state) => ({ pyodideError: state.pyodideError, showErrorPopover: state.showErrorPopover, setErrorPopover: state.setErrorPopover, })) ); const errorPopoverRef = useRef(null); const errorButtonRef = useRef(null); // Get state visual info for header status badge const stateVisual = getStateVisualInfo(machineStatus); const stateIcons = { ready: CheckCircleIcon, active: BoltIcon, waiting: PauseCircleIcon, complete: CheckCircleIcon, interrupted: PauseCircleIcon, error: ExclamationTriangleIcon, }; const StatusIcon = stateIcons[stateVisual.iconName]; // Close error popover when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( errorPopoverRef.current && !errorPopoverRef.current.contains(event.target as Node) && errorButtonRef.current && !errorButtonRef.current.contains(event.target as Node) ) { setErrorPopover(false); } }; if (showErrorPopover) { document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); } }, [showErrorPopover, setErrorPopover]); return (
{/* Machine Connection Status - Responsive width column */}

Respira

{isConnected && machineInfo?.serialNumber && ( • {machineInfo.serialNumber} )} {isPolling && ( )}
{isConnected ? ( <> {machineStatusName} ) : (

Not Connected

)} {/* Error indicator - always render to prevent layout shift */}
{/* Error popover */} {showErrorPopover && (machineErrorMessage || pyodideError) && ( )}
{/* Workflow Stepper - Flexible width column */}
); }