invoice_extractor / frontend /src /components /ProgressIndicator.jsx
github-actions[bot]
Sync from GitHub: 922d61677657398e61342f3cabff773c13c26de4
060dc2a
import React from 'react';
import { Loader2, CheckCircle, XCircle } from 'lucide-react';
const ProgressIndicator = ({ total, completed, current, results }) => {
const progress = total > 0 ? (completed / total) * 100 : 0;
const successCount = results.filter(r => r.success).length;
const errorCount = results.filter(r => !r.success).length;
return (
<div className="bg-white rounded-xl shadow-lg p-6 border border-gray-200">
<div className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold text-gray-800 flex items-center">
<Loader2 className="w-5 h-5 mr-2 text-primary-500 animate-spin" />
Processing Files
</h3>
<span className="text-sm font-medium text-gray-600">
{completed} / {total}
</span>
</div>
{/* Progress Bar */}
<div className="relative">
<div className="overflow-hidden h-3 text-xs flex rounded-full bg-gray-200">
<div
style={{ width: `${progress}%` }}
className="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-gradient-to-r from-primary-500 to-primary-600 transition-all duration-500"
/>
</div>
<div className="mt-2 text-xs text-gray-500 text-center">
{Math.round(progress)}% Complete
</div>
</div>
{/* Current Processing */}
{current && (
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3">
<p className="text-sm text-blue-800 flex items-center">
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
Currently processing: <span className="font-medium ml-1">{current}</span>
</p>
</div>
)}
{/* Statistics */}
<div className="grid grid-cols-3 gap-3 pt-2">
<div className="text-center">
<div className="text-2xl font-bold text-gray-800">{total}</div>
<div className="text-xs text-gray-500">Total</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-green-600 flex items-center justify-center">
{successCount}
{successCount > 0 && <CheckCircle className="w-5 h-5 ml-1" />}
</div>
<div className="text-xs text-gray-500">Success</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-red-600 flex items-center justify-center">
{errorCount}
{errorCount > 0 && <XCircle className="w-5 h-5 ml-1" />}
</div>
<div className="text-xs text-gray-500">Errors</div>
</div>
</div>
{/* Results List */}
{results.length > 0 && (
<div className="border-t pt-4 mt-4">
<h4 className="text-sm font-semibold text-gray-700 mb-3">Processing Status</h4>
<div className="space-y-2 max-h-48 overflow-y-auto">
{results.map((result, index) => (
<div
key={index}
className={`flex items-center justify-between p-2 rounded ${
result.success ? 'bg-green-50' : 'bg-red-50'
}`}
>
<span className="text-sm text-gray-700 truncate flex-1">
{result.filename}
</span>
{result.success ? (
<CheckCircle className="w-4 h-4 text-green-600 flex-shrink-0 ml-2" />
) : (
<XCircle className="w-4 h-4 text-red-600 flex-shrink-0 ml-2" />
)}
</div>
))}
</div>
</div>
)}
</div>
</div>
);
};
export default ProgressIndicator;