/** * ProgressMonitor Component * * Orchestrates progress monitoring UI with stats, progress bar, color blocks, and action buttons */ import { useMemo } from "react"; import { useAutoScroll } from "@/hooks"; import { useShallow } from "zustand/react/shallow"; import { useMachineStore } from "../../stores/useMachineStore"; import { usePatternStore } from "../../stores/usePatternStore"; import { ChartBarIcon } from "@heroicons/react/24/solid"; import { MachineStatus } from "../../types/machine"; import { calculatePatternTime } from "../../utils/timeCalculation"; import { Card, CardHeader, CardTitle, CardDescription, CardContent, } from "@/components/ui/card"; import { ProgressStats } from "./ProgressStats"; import { ProgressSection } from "./ProgressSection"; import { ColorBlockList } from "./ColorBlockList"; import { ProgressActions } from "./ProgressActions"; import type { ColorBlock } from "./ColorBlockItem"; export function ProgressMonitor() { // Machine store const { machineStatus, patternInfo, sewingProgress, isDeleting, startMaskTrace, startSewing, resumeSewing, } = useMachineStore( useShallow((state) => ({ machineStatus: state.machineStatus, patternInfo: state.patternInfo, sewingProgress: state.sewingProgress, isDeleting: state.isDeleting, startMaskTrace: state.startMaskTrace, startSewing: state.startSewing, resumeSewing: state.resumeSewing, })), ); // Pattern store const pesData = usePatternStore((state) => state.pesData); const uploadedPesData = usePatternStore((state) => state.uploadedPesData); const displayPattern = uploadedPesData || pesData; // State indicators const isMaskTraceComplete = machineStatus === MachineStatus.MASK_TRACE_COMPLETE; // Use PEN stitch count as fallback when machine reports 0 total stitches const totalStitches = patternInfo ? patternInfo.totalStitches === 0 && displayPattern?.penStitches ? displayPattern.penStitches.stitches.length : patternInfo.totalStitches : 0; const progressPercent = totalStitches > 0 ? ((sewingProgress?.currentStitch || 0) / totalStitches) * 100 : 0; // Calculate color block information from decoded penStitches const colorBlocks = useMemo(() => { if (!displayPattern || !displayPattern.penStitches) return []; const blocks: ColorBlock[] = []; // Use the pre-computed color blocks from decoded PEN data for (const penBlock of displayPattern.penStitches.colorBlocks) { const thread = displayPattern.threads[penBlock.colorIndex]; blocks.push({ colorIndex: penBlock.colorIndex, threadHex: thread?.hex || "#000000", threadCatalogNumber: thread?.catalogNumber ?? null, threadBrand: thread?.brand ?? null, threadDescription: thread?.description ?? null, threadChart: thread?.chart ?? null, startStitch: penBlock.startStitchIndex, endStitch: penBlock.endStitchIndex, stitchCount: penBlock.endStitchIndex - penBlock.startStitchIndex, }); } return blocks; }, [displayPattern]); // Determine current color block based on current stitch const currentStitch = sewingProgress?.currentStitch || 0; const currentBlockIndex = colorBlocks.findIndex( (block) => currentStitch >= block.startStitch && currentStitch < block.endStitch, ); // Calculate time based on color blocks (matches Brother app calculation) const { totalMinutes, elapsedMinutes } = useMemo(() => { if (colorBlocks.length === 0) { return { totalMinutes: 0, elapsedMinutes: 0 }; } const result = calculatePatternTime(colorBlocks, currentStitch); return { totalMinutes: result.totalMinutes, elapsedMinutes: result.elapsedMinutes, }; }, [colorBlocks, currentStitch]); // Auto-scroll to current block const currentBlockRef = useAutoScroll(currentBlockIndex); return (
Sewing Progress {sewingProgress && ( {progressPercent.toFixed(1)}% complete )}
{/* Pattern Info */} {patternInfo && ( )} {/* Progress Bar */} {sewingProgress && ( )} {/* Color Blocks */} {/* Action buttons */}
); }