import { CheckCircleIcon, ArrowRightIcon, CircleStackIcon, PlayIcon, CheckBadgeIcon, ClockIcon, PauseCircleIcon, ExclamationCircleIcon, ChartBarIcon } from '@heroicons/react/24/solid'; import type { PatternInfo, SewingProgress } from '../types/machine'; import { MachineStatus } from '../types/machine'; import type { PesPatternData } from '../utils/pystitchConverter'; import { canStartSewing, canStartMaskTrace, canResumeSewing, getStateVisualInfo } from '../utils/machineStateHelpers'; interface ProgressMonitorProps { machineStatus: MachineStatus; patternInfo: PatternInfo | null; sewingProgress: SewingProgress | null; pesData: PesPatternData | null; onStartMaskTrace: () => void; onStartSewing: () => void; onResumeSewing: () => void; onDeletePattern: () => void; isDeleting?: boolean; } export function ProgressMonitor({ machineStatus, patternInfo, sewingProgress, pesData, onStartMaskTrace, onStartSewing, onResumeSewing, isDeleting = false, }: ProgressMonitorProps) { // State indicators const isMaskTraceComplete = machineStatus === MachineStatus.MASK_TRACE_COMPLETE; const stateVisual = getStateVisualInfo(machineStatus); const progressPercent = patternInfo ? ((sewingProgress?.currentStitch || 0) / patternInfo.totalStitches) * 100 : 0; // Calculate color block information from pesData const colorBlocks = pesData ? (() => { const blocks: Array<{ colorIndex: number; threadHex: string; startStitch: number; endStitch: number; stitchCount: number; }> = []; let currentColorIndex = pesData.stitches[0]?.[3] ?? 0; let blockStartStitch = 0; for (let i = 0; i < pesData.stitches.length; i++) { const stitchColorIndex = pesData.stitches[i][3]; // When color changes, save the previous block if (stitchColorIndex !== currentColorIndex || i === pesData.stitches.length - 1) { const endStitch = i === pesData.stitches.length - 1 ? i + 1 : i; blocks.push({ colorIndex: currentColorIndex, threadHex: pesData.threads[currentColorIndex]?.hex || '#000000', startStitch: blockStartStitch, endStitch: endStitch, stitchCount: endStitch - blockStartStitch, }); currentColorIndex = stitchColorIndex; blockStartStitch = i; } } return blocks; })() : []; // Determine current color block based on current stitch const currentStitch = sewingProgress?.currentStitch || 0; const currentBlockIndex = colorBlocks.findIndex( block => currentStitch >= block.startStitch && currentStitch < block.endStitch ); const stateIndicatorColors = { idle: 'bg-blue-50 dark:bg-blue-900/20 border-blue-600', info: 'bg-blue-50 dark:bg-blue-900/20 border-blue-600', active: 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-500', waiting: 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-500', warning: 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-500', complete: 'bg-green-50 dark:bg-green-900/20 border-green-600', success: 'bg-green-50 dark:bg-green-900/20 border-green-600', interrupted: 'bg-red-50 dark:bg-red-900/20 border-red-600', error: 'bg-red-50 dark:bg-red-900/20 border-red-600', danger: 'bg-red-50 dark:bg-red-900/20 border-red-600', }; return (

Sewing Progress

{sewingProgress && (

{progressPercent.toFixed(1)}% complete

)}
{/* Pattern Info */} {patternInfo && (
Total Stitches {patternInfo.totalStitches.toLocaleString()}
Est. Time {Math.floor(patternInfo.totalTime / 60)}:{String(patternInfo.totalTime % 60).padStart(2, '0')}
Speed {patternInfo.speed} spm
)} {/* Progress Bar */} {sewingProgress && (
Current Stitch {sewingProgress.currentStitch.toLocaleString()} / {patternInfo?.totalStitches.toLocaleString() || 0}
Time Elapsed {Math.floor(sewingProgress.currentTime / 60)}:{String(sewingProgress.currentTime % 60).padStart(2, '0')}
)} {/* State Visual Indicator */} {patternInfo && (() => { const iconMap = { ready: , active: , waiting: , complete: , interrupted: , error: }; return (
{iconMap[stateVisual.iconName]}
{stateVisual.label}
{stateVisual.description}
); })()} {/* Color Blocks */} {colorBlocks.length > 0 && (

Color Blocks

{colorBlocks.map((block, index) => { const isCompleted = currentStitch >= block.endStitch; const isCurrent = index === currentBlockIndex; // Calculate progress within current block let blockProgress = 0; if (isCurrent) { blockProgress = ((currentStitch - block.startStitch) / block.stitchCount) * 100; } else if (isCompleted) { blockProgress = 100; } return (
{/* Color swatch */}
{/* Thread info */}
Thread {block.colorIndex + 1}
{block.stitchCount.toLocaleString()} stitches
{/* Status icon */} {isCompleted ? ( ) : isCurrent ? ( ) : ( )}
{/* Progress bar for current block */} {isCurrent && (
)}
); })}
)} {/* Action buttons */}
{/* Resume has highest priority when available */} {canResumeSewing(machineStatus) && ( )} {/* Start Sewing - primary action */} {canStartSewing(machineStatus) && !canResumeSewing(machineStatus) && ( )} {/* Start Mask Trace - secondary action */} {canStartMaskTrace(machineStatus) && ( )}
); }