fastcheck/src/components/dashboard/BulkEvaluationProgressMeter.tsx
2026-04-08 13:58:46 -04:00

137 lines
4.6 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { getBulkEvaluations } from '../../services/api';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { logger } from '../../utils/logger';
interface BulkEvaluation {
_id: string;
status: 'pending' | 'processing' | 'completed' | 'failed';
totalEvaluations: number;
completedEvaluations: number;
failedEvaluations: number;
createdAt: Date;
}
const BulkEvaluationProgressMeter: React.FC = () => {
const { t } = useTranslation();
const [evaluations, setEvaluations] = useState<BulkEvaluation[]>([]);
const [loading, setLoading] = useState(true);
const navigate = useNavigate();
useEffect(() => {
const fetchEvaluations = async () => {
try {
const data = await getBulkEvaluations();
setEvaluations(data);
setLoading(false);
// Check if all evaluations are completed
const processingEval = data.find(evaluation => evaluation.status === 'processing');
if (!processingEval) {
navigate('/dashboard');
}
} catch (error) {
logger.error('Error fetching bulk evaluations:', error);
setLoading(false);
}
};
fetchEvaluations();
const interval = setInterval(fetchEvaluations, 60000); // Poll every 1 minute
return () => clearInterval(interval);
}, [navigate]);
const getLatestProcessing = () => {
return evaluations.find(evaluation => evaluation.status === 'processing');
};
const processingEvaluation = getLatestProcessing();
if (loading) {
return (
<div className="space-y-6">
<div className="h-4 bg-gray-200 rounded w-3/4"></div>
<div className="space-y-3 mt-4">
<div className="h-8 bg-gray-200 rounded"></div>
</div>
</div>
);
}
if (!processingEvaluation) {
return (
<div className="bg-gray-800 rounded-lg shadow p-6">
<h3 className="text-lg font-semibold text-gray-100 mb-4">{t('bulkProgress.title')}</h3>
<div className="space-y-4">
<div className="relative pt-1">
<div className="flex mb-2 items-center justify-between">
<div>
<span className="text-xs font-semibold inline-block py-1 px-2 uppercase rounded-full text-blue-200 bg-blue-900">
{t('bulkProgress.progress')}
</span>
</div>
<div className="text-right">
<span className="text-xs font-semibold inline-block text-blue-200">
0%
</span>
</div>
</div>
<div className="mt-4 h-4 rounded-full bg-gray-700">
<div
style={{ width: '0%' }}
className="h-4 rounded-full bg-blue-500"
></div>
</div>
<div className="text-sm text-gray-300">
{t('bulkProgress.completed', { completed: 0, total: 0 })}
</div>
</div>
</div>
</div>
);
}
const progress = Math.round(
(processingEvaluation.completedEvaluations / processingEvaluation.totalEvaluations) * 100
);
return (
<div className="bg-gray-800 rounded-lg shadow p-6">
<h3 className="text-lg font-semibold text-gray-100 mb-4">{t('bulkProgress.title')}</h3>
<div className="space-y-4">
<div className="relative pt-1">
<div className="flex mb-2 items-center justify-between">
<div>
<span className="text-xs font-semibold inline-block py-1 px-2 uppercase rounded-full text-blue-200 bg-blue-900">
{t('bulkProgress.progress')}
</span>
</div>
<div className="text-right">
<span className="text-xs font-semibold inline-block text-blue-200">
{progress}%
</span>
</div>
</div>
<div className="mt-4 h-4 rounded-full bg-gray-700">
<div
style={{ width: `${progress}%` }}
className="h-4 rounded-full bg-blue-500"
></div>
</div>
<div className="text-sm text-gray-300">
{t('bulkProgress.completed', { completed: processingEvaluation.completedEvaluations, total: processingEvaluation.totalEvaluations })}
</div>
{processingEvaluation.failedEvaluations > 0 && (
<div className="text-sm text-red-400 mt-1">
{t('bulkProgress.failed', { count: processingEvaluation.failedEvaluations })}
</div>
)}
</div>
</div>
</div>
);
};
export default BulkEvaluationProgressMeter;