import { useState, useCallback } from 'react'; import { convertPesToPen, type PesPatternData } from '../utils/pystitchConverter'; import { MachineStatus } from '../types/machine'; import { canUploadPattern, getMachineStateCategory } from '../utils/machineStateHelpers'; import { PatternInfoSkeleton } from './SkeletonLoader'; import { ArrowUpTrayIcon, CheckCircleIcon, DocumentTextIcon, FolderOpenIcon } from '@heroicons/react/24/solid'; interface FileUploadProps { isConnected: boolean; machineStatus: MachineStatus; uploadProgress: number; onPatternLoaded: (pesData: PesPatternData, fileName: string) => void; onUpload: (penData: Uint8Array, pesData: PesPatternData, fileName: string, patternOffset?: { x: number; y: number }) => void; pyodideReady: boolean; patternOffset: { x: number; y: number }; patternUploaded: boolean; resumeAvailable: boolean; resumeFileName: string | null; pesData: PesPatternData | null; currentFileName: string; isUploading?: boolean; } export function FileUpload({ isConnected, machineStatus, uploadProgress, onPatternLoaded, onUpload, pyodideReady, patternOffset, patternUploaded, resumeAvailable, resumeFileName, pesData: pesDataProp, currentFileName, isUploading = false, }: FileUploadProps) { const [localPesData, setLocalPesData] = useState(null); const [fileName, setFileName] = useState(''); // Use prop pesData if available (from cached pattern), otherwise use local state const pesData = pesDataProp || localPesData; // Use currentFileName from App state, or local fileName, or resumeFileName for display const displayFileName = currentFileName || fileName || resumeFileName || ''; const [isLoading, setIsLoading] = useState(false); const handleFileChange = useCallback( async (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; if (!pyodideReady) { alert('Python environment is still loading. Please wait...'); return; } setIsLoading(true); try { const data = await convertPesToPen(file); setLocalPesData(data); setFileName(file.name); onPatternLoaded(data, file.name); } catch (err) { alert( `Failed to load PES file: ${ err instanceof Error ? err.message : 'Unknown error' }` ); } finally { setIsLoading(false); } }, [onPatternLoaded, pyodideReady] ); const handleUpload = useCallback(() => { if (pesData && displayFileName) { onUpload(pesData.penData, pesData, displayFileName, patternOffset); } }, [pesData, displayFileName, onUpload, patternOffset]); const borderColor = pesData ? 'border-orange-600 dark:border-orange-500' : 'border-gray-400 dark:border-gray-600'; const iconColor = pesData ? 'text-orange-600 dark:text-orange-400' : 'text-gray-600 dark:text-gray-400'; return (

Pattern File

{pesData && displayFileName ? (

{displayFileName}

) : (

No pattern loaded

)}
{resumeAvailable && resumeFileName && (

Cached: "{resumeFileName}"

)} {isLoading && } {!isLoading && pesData && (
Size {((pesData.bounds.maxX - pesData.bounds.minX) / 10).toFixed(1)} x{' '} {((pesData.bounds.maxY - pesData.bounds.minY) / 10).toFixed(1)} mm
Stitches {pesData.stitchCount.toLocaleString()}
Colors:
{pesData.threads.slice(0, 8).map((thread, idx) => (
))} {pesData.colorCount > 8 && (
+{pesData.colorCount - 8}
)}
)} {pesData && !canUploadPattern(machineStatus) && (
Cannot upload while {getMachineStateCategory(machineStatus)}
)} {isUploading && uploadProgress < 100 && (
Uploading {uploadProgress > 0 ? uploadProgress.toFixed(1) + '%' : 'Starting...'}
)}
{pesData && canUploadPattern(machineStatus) && !patternUploaded && uploadProgress < 100 && ( )}
); }