import { useEffect, useRef } from 'react'; import { useShallow } from 'zustand/react/shallow'; import { useMachineStore } from './stores/useMachineStore'; import { usePatternStore } from './stores/usePatternStore'; import { useUIStore } from './stores/useUIStore'; import { FileUpload } from './components/FileUpload'; import { PatternCanvas } from './components/PatternCanvas'; import { ProgressMonitor } from './components/ProgressMonitor'; import { WorkflowStepper } from './components/WorkflowStepper'; import { PatternSummaryCard } from './components/PatternSummaryCard'; import { BluetoothDevicePicker } from './components/BluetoothDevicePicker'; import { getErrorDetails } from './utils/errorCodeHelpers'; import { getStateVisualInfo } from './utils/machineStateHelpers'; import { CheckCircleIcon, BoltIcon, PauseCircleIcon, ExclamationTriangleIcon, ArrowPathIcon, XMarkIcon, InformationCircleIcon } from '@heroicons/react/24/solid'; import './App.css'; function App() { // Machine store const { isConnected, machineInfo, machineStatus, machineStatusName, machineError, patternInfo, error: machineErrorMessage, isPairingError, isCommunicating: isPolling, resumeFileName, resumedPattern, connect, disconnect, } = useMachineStore( useShallow((state) => ({ isConnected: state.isConnected, machineInfo: state.machineInfo, machineStatus: state.machineStatus, machineStatusName: state.machineStatusName, machineError: state.machineError, patternInfo: state.patternInfo, error: state.error, isPairingError: state.isPairingError, isCommunicating: state.isCommunicating, resumeFileName: state.resumeFileName, resumedPattern: state.resumedPattern, connect: state.connect, disconnect: state.disconnect, })) ); // Pattern store const { pesData, patternUploaded, setPattern, setPatternOffset, setPatternUploaded, } = usePatternStore( useShallow((state) => ({ pesData: state.pesData, patternUploaded: state.patternUploaded, setPattern: state.setPattern, setPatternOffset: state.setPatternOffset, setPatternUploaded: state.setPatternUploaded, })) ); // UI store const { pyodideError, showErrorPopover, initializePyodide, setErrorPopover, } = useUIStore( useShallow((state) => ({ pyodideError: state.pyodideError, showErrorPopover: state.showErrorPopover, initializePyodide: state.initializePyodide, setErrorPopover: state.setErrorPopover, })) ); const errorPopoverRef = useRef(null); const errorButtonRef = useRef(null); // Initialize Pyodide in background on mount (non-blocking thanks to worker) useEffect(() => { initializePyodide(); }, [initializePyodide]); // 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]); // Auto-load cached pattern when available if (resumedPattern && !pesData) { console.log('[App] Loading resumed pattern:', resumeFileName, 'Offset:', resumedPattern.patternOffset); setPattern(resumedPattern.pesData, resumeFileName || ''); // Restore the cached pattern offset if (resumedPattern.patternOffset) { setPatternOffset(resumedPattern.patternOffset.x, resumedPattern.patternOffset.y); } } // Track pattern uploaded state based on machine status if (!isConnected) { if (patternUploaded) { setPatternUploaded(false); } } else { // Pattern is uploaded if machine has pattern info const shouldBeUploaded = patternInfo !== null; if (patternUploaded !== shouldBeUploaded) { setPatternUploaded(shouldBeUploaded); } } // 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]; 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) && (
{(() => { const errorDetails = getErrorDetails(machineError); const isPairingErr = isPairingError; const errorMsg = pyodideError || machineErrorMessage || ''; const isInfo = isPairingErr || errorDetails?.isInformational; const bgColor = isInfo ? 'bg-blue-50 dark:bg-blue-900/95 border-blue-600 dark:border-blue-500' : 'bg-red-50 dark:bg-red-900/95 border-red-600 dark:border-red-500'; const iconColor = isInfo ? 'text-blue-600 dark:text-blue-400' : 'text-red-600 dark:text-red-400'; const textColor = isInfo ? 'text-blue-900 dark:text-blue-200' : 'text-red-900 dark:text-red-200'; const descColor = isInfo ? 'text-blue-800 dark:text-blue-300' : 'text-red-800 dark:text-red-300'; const listColor = isInfo ? 'text-blue-700 dark:text-blue-300' : 'text-red-700 dark:text-red-300'; const Icon = isInfo ? InformationCircleIcon : ExclamationTriangleIcon; const title = errorDetails?.title || (isPairingErr ? 'Pairing Required' : 'Error'); return (

{title}

{errorDetails?.description || errorMsg}

{errorDetails?.solutions && errorDetails.solutions.length > 0 && ( <>

{isInfo ? 'Steps:' : 'How to Fix:'}

    {errorDetails.solutions.map((solution, index) => (
  1. {solution}
  2. ))}
)} {machineError !== undefined && !errorDetails?.isInformational && (

Error Code: 0x{machineError.toString(16).toUpperCase().padStart(2, '0')}

)}
); })()}
)}
{/* Workflow Stepper - Flexible width column */}
{/* Left Column - Controls */}
{/* Connect Button - Show when disconnected */} {!isConnected && (

Get Started

Connect to your embroidery machine

)} {/* Pattern File - Show during upload stage (before pattern is uploaded) */} {isConnected && !patternUploaded && ( )} {/* Compact Pattern Summary - Show after upload (during sewing stages) */} {isConnected && patternUploaded && pesData && ( )} {/* Progress Monitor - Show when pattern is uploaded */} {isConnected && patternUploaded && (
)}
{/* Right Column - Pattern Preview */}
{pesData ? ( ) : (

Pattern Preview

{/* Decorative background pattern */}

No Pattern Loaded

Connect to your machine and choose a PES embroidery file to see your design preview

Drag to Position
Zoom & Pan
Real-time Preview
)}
{/* Bluetooth Device Picker (Electron only) */}
); } export default App;