Re_Figma_Code/src/pages/Form16/components/UploadCard.tsx

129 lines
3.9 KiB
TypeScript

import { Upload, CheckCircle2, AlertCircle, Loader2 } from 'lucide-react';
import { useState } from 'react';
export type UploadState = 'idle' | 'dragging' | 'validating' | 'extracting' | 'success' | 'error';
interface UploadCardProps {
state?: UploadState;
onFileSelect: (file: File) => void;
errorMessage?: string;
className?: string;
disabled?: boolean;
}
export function UploadCard({
state = 'idle',
onFileSelect,
errorMessage,
className = '',
disabled = false,
}: UploadCardProps) {
const [isDragging, setIsDragging] = useState(false);
const currentState = isDragging && !disabled ? 'dragging' : state;
const handleDragOver = (e: React.DragEvent) => {
e.preventDefault();
if (disabled) return;
setIsDragging(true);
};
const handleDragLeave = () => {
setIsDragging(false);
};
const handleDrop = (e: React.DragEvent) => {
e.preventDefault();
setIsDragging(false);
if (disabled) return;
const files = e.dataTransfer.files;
const file = files[0];
if (file) onFileSelect(file);
};
const handleFileInput = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
const file = files?.[0];
if (file) onFileSelect(file);
};
const stateConfig: Record<string, { icon: typeof Upload; text: string; subtext: string; bgColor: string; borderColor: string; iconColor: string }> = {
idle: {
icon: Upload,
text: 'Drop PDF here or click to browse',
subtext: 'Only .pdf | Form 16A certificate',
bgColor: 'bg-white hover:bg-gray-50',
borderColor: 'border-gray-300 border-dashed',
iconColor: 'text-gray-400',
},
dragging: {
icon: Upload,
text: 'Release to upload',
subtext: 'Drop your Form 16A PDF here',
bgColor: 'bg-blue-50',
borderColor: 'border-blue-400 border-dashed',
iconColor: 'text-blue-500',
},
validating: {
icon: Loader2,
text: 'Validating Form 16A...',
subtext: 'Please wait',
bgColor: 'bg-blue-50',
borderColor: 'border-blue-300',
iconColor: 'text-blue-600 animate-spin',
},
extracting: {
icon: Loader2,
text: 'Extracting data from Form 16A...',
subtext: 'Using Google Gemini (regex fallback if needed)',
bgColor: 'bg-blue-50',
borderColor: 'border-blue-300',
iconColor: 'text-blue-600 animate-spin',
},
success: {
icon: CheckCircle2,
text: 'Form 16A uploaded successfully',
subtext: 'Document ready for submission',
bgColor: 'bg-green-50',
borderColor: 'border-green-300',
iconColor: 'text-green-600',
},
error: {
icon: AlertCircle,
text: 'Upload failed',
subtext: errorMessage || 'Please try again',
bgColor: 'bg-red-50',
borderColor: 'border-red-300',
iconColor: 'text-red-600',
},
};
const config = stateConfig[currentState] ?? stateConfig.idle;
const Icon = config!.icon;
return (
<div className={className}>
<label
className={`flex flex-col items-center justify-center w-full min-h-[200px] border-2 rounded-lg transition-all ${config?.bgColor ?? ''} ${config?.borderColor ?? ''} ${!disabled && state === 'idle' ? 'cursor-pointer' : 'cursor-default'}`}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
>
<div className="flex flex-col items-center justify-center py-8 px-4">
<Icon className={`w-12 h-12 mb-4 ${config?.iconColor ?? ''}`} />
<p className="mb-2 text-gray-700 font-medium">{config?.text ?? ''}</p>
<p className="text-sm text-gray-500">{config?.subtext ?? ''}</p>
</div>
{currentState === 'idle' && !disabled && (
<input
type="file"
className="hidden"
accept=".pdf,application/pdf"
onChange={handleFileInput}
/>
)}
</label>
</div>
);
}