| 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; | |