respira/src/components/FileUpload/FileSelector.tsx
Jan-Henrik Bruhn 681ce223c3 refactor: Extract FileUpload sub-components and utilities
- Move FileUpload into dedicated folder with sub-components
- Extract FileSelector, PyodideProgress, UploadButton, UploadProgress, BoundsValidator
- Create useDisplayFilename hook for filename priority logic
- Reduce FileUpload.tsx from 391 to 261 lines (33% reduction)

Part of #33: Extract sub-components from large components

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-27 16:27:17 +01:00

92 lines
2.4 KiB
TypeScript

/**
* FileSelector Component
*
* Renders file input and selection button, handles native vs web file selection
*/
import { FolderOpenIcon, CheckCircleIcon } from "@heroicons/react/24/solid";
import { Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import type { IFileService } from "../../platform/interfaces/IFileService";
interface FileSelectorProps {
fileService: IFileService;
isLoading: boolean;
isDisabled: boolean;
onFileChange: (event?: React.ChangeEvent<HTMLInputElement>) => Promise<void>;
displayFileName: string;
patternUploaded: boolean;
}
export function FileSelector({
fileService,
isLoading,
isDisabled,
onFileChange,
patternUploaded,
}: FileSelectorProps) {
const hasNativeDialogs = fileService.hasNativeDialogs();
return (
<>
<input
type="file"
accept=".pes"
onChange={onFileChange}
id="file-input"
className="hidden"
disabled={isDisabled}
/>
<Button
asChild={!hasNativeDialogs && !isDisabled}
onClick={hasNativeDialogs ? () => onFileChange() : undefined}
disabled={isDisabled}
variant="outline"
className="flex-[2]"
>
{hasNativeDialogs ? (
<>
{isLoading ? (
<>
<Loader2 className="w-3.5 h-3.5 animate-spin" />
<span>Loading...</span>
</>
) : patternUploaded ? (
<>
<CheckCircleIcon className="w-3.5 h-3.5" />
<span>Locked</span>
</>
) : (
<>
<FolderOpenIcon className="w-3.5 h-3.5" />
<span>Choose PES File</span>
</>
)}
</>
) : (
<label
htmlFor="file-input"
className="flex items-center gap-2 cursor-pointer"
>
{isLoading ? (
<>
<Loader2 className="w-3.5 h-3.5 animate-spin" />
<span>Loading...</span>
</>
) : patternUploaded ? (
<>
<CheckCircleIcon className="w-3.5 h-3.5" />
<span>Locked</span>
</>
) : (
<>
<FolderOpenIcon className="w-3.5 h-3.5" />
<span>Choose PES File</span>
</>
)}
</label>
)}
</Button>
</>
);
}