Import/Export Components
The CRUD bundle provides robust import and export functionality for bulk data operations. These components support CSV and Excel files with validation, progress tracking, and error handling.
Component Overview
1. FileUploader
Drag-and-drop file upload component with validation and preview.
Props
interface FileUploaderProps {
form: UseFormReturn<ImportFormDataType>; // React Hook Form instance
fqcn_bui: IFQCN_BUI; // Component configuration
onImport: (jobId: string) => void; // Import callback
locale: string; // Locale for translations
}Features
- Drag & Drop: Intuitive file upload interface
- File Validation: Type and size validation
- Preview: CSV data preview before import
- Progress: Upload progress indicator
- Error Handling: Clear error messages
2. ImportTable
Data preview table for imported CSV/Excel data.
Props
interface ImportTableProps {
csvData: CSVDataType; // Parsed CSV data
locale?: string; // Locale for translations
}
interface CSVDataType {
headers: string[]; // Column headers
rows: string[][]; // Data rows
}3. ImportForm
Configuration form for import settings.
Props
interface ImportFormProps {
form: UseFormReturn<ImportFormDataType>; // Form instance
fqcn_bui: IFQCN_BUI; // Configuration
csrfJwt: string; // CSRF token
locale?: string; // Locale
tenant: string; // Tenant identifier
}Complete Implementation
Basic Import
import {
FileUploader,
ImportTable,
ImportForm,
ReviewContainer
} from "@phpcreation/frontend-crud-react-nextjs-bundle/components";
function BasicImport() {
const [importStep, setImportStep] = useState<'upload' | 'configure' | 'preview' | 'import'>('upload');
const [csvData, setCsvData] = useState<CSVDataType | null>(null);
const [importJobId, setImportJobId] = useState<string | null>(null);
const form = useForm<ImportFormDataType>({
defaultValues: {
file: null,
fileName: "",
fieldDelimiter: ",",
textDelimiter: '"',
validation: "validate"
}
});
const handleFileImport = (jobId: string) => {
setImportJobId(jobId);
setImportStep('import');
};
return (
<div className="max-w-4xl mx-auto p-6">
<div className="bg-white rounded-lg shadow-md p-6">
<h1 className="text-2xl font-bold mb-6">Import Data</h1>
{/* Step Indicator */}
<div className="mb-8">
<div className="flex items-center justify-between">
{['upload', 'configure', 'preview', 'import'].map((step, index) => (
<div key={step} className="flex items-center">
<div className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium ${
importStep === step ? 'bg-blue-600 text-white' : 'bg-gray-200 text-gray-600'
}`}>
{index + 1}
</div>
<span className="ml-2 text-sm capitalize">{step}</span>
{index < 3 && <div className="w-16 h-0.5 bg-gray-200 mx-4" />}
</div>
))}
</div>
</div>
{/* Upload Step */}
{importStep === 'upload' && (
<div className="space-y-6">
<FileUploader
form={form}
fqcn_bui={{Bundle: "data", Unit: "import", Interface: "upload"}}
onImport={handleFileImport}
locale="en"
/>
{csvData && (
<div>
<h3 className="text-lg font-semibold mb-4">Data Preview</h3>
<ImportTable csvData={csvData} />
<div className="mt-4 text-right">
<Button onClick={() => setImportStep('configure')}>
Configure Import
</Button>
</div>
</div>
)}
</div>
)}
{/* Configure Step */}
{importStep === 'configure' && (
<div className="space-y-6">
<ImportForm
form={form}
fqcn_bui={{Bundle: "data", Unit: "import", Interface: "config"}}
csrfJwt={csrfToken}
tenant={tenant}
locale="en"
/>
<div className="flex justify-between">
<Button
variant="outline"
onClick={() => setImportStep('upload')}
>
Back
</Button>
<Button onClick={() => setImportStep('preview')}>
Preview Import
</Button>
</div>
</div>
)}
{/* Preview Step */}
{importStep === 'preview' && (
<div className="space-y-6">
<ReviewContainer
importData={csvData}
formConfig={form.getValues()}
onConfirm={() => setImportStep('import')}
/>
<div className="flex justify-between">
<Button
variant="outline"
onClick={() => setImportStep('configure')}
>
Back to Configuration
</Button>
<Button onClick={() => startImport()}>
Start Import
</Button>
</div>
</div>
)}
{/* Import Progress */}
{importStep === 'import' && importJobId && (
<ImportProgress jobId={importJobId} />
)}
</div>
</div>
);
}Best Practices
Last updated on