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