import React, { useState, useEffect } from 'react'; import axios from 'axios'; interface StatusMonitorProps { jobId: string; onJobFinished: (jobId: string, results: any) => void; } const API_ENDPOINT = 'https://api.portfolio.techarvest.co.zw'; // Pipeline stages with their relative weights/progress and baseline durations (in seconds) const STAGES: Record = { 'queued': { progress: 5, label: 'In Queue', eta: 30 }, 'fetch_stac': { progress: 15, label: 'Fetching Satellite Imagery', eta: 120 }, 'build_features': { progress: 40, label: 'Computing Spectral Indices', eta: 180 }, 'load_dw': { progress: 50, label: 'Loading Base Classification', eta: 45 }, 'infer': { progress: 75, label: 'Running Ensemble Prediction', eta: 90 }, 'smooth': { progress: 85, label: 'Refining Results', eta: 30 }, 'export_cog': { progress: 95, label: 'Generating Output Maps', eta: 20 }, 'upload': { progress: 98, label: 'Finalizing Storage', eta: 10 }, 'finished': { progress: 100, label: 'Complete', eta: 0 }, 'done': { progress: 100, label: 'Complete', eta: 0 }, 'failed': { progress: 0, label: 'Job Failed', eta: 0 } }; const StatusMonitor: React.FC = ({ jobId, onJobFinished }) => { const [status, setStatus] = useState('queued'); const [countdown, setCountdown] = useState(0); useEffect(() => { let interval: number; const checkStatus = async () => { try { const response = await axios.get(`${API_ENDPOINT}/jobs/${jobId}`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` } }); const data = response.data; const currentStatus = data.status || 'queued'; setStatus(currentStatus); // Reset countdown whenever stage changes if (STAGES[currentStatus]) { setCountdown(STAGES[currentStatus].eta); } if (currentStatus === 'finished' || currentStatus === 'done') { clearInterval(interval); const result = data.result || data.outputs; const roi = data.roi; onJobFinished(jobId, { result, roi }); } else if (currentStatus === 'failed') { clearInterval(interval); } } catch (err) { console.error('Status check failed:', err); } }; interval = window.setInterval(checkStatus, 5000); checkStatus(); return () => clearInterval(interval); }, [jobId, onJobFinished]); // Handle local countdown timer useEffect(() => { const timer = setInterval(() => { setCountdown(prev => (prev > 0 ? prev - 1 : 0)); }, 1000); return () => clearInterval(timer); }, []); const stageInfo = STAGES[status] || { progress: 0, label: 'Processing...', eta: 60 }; const progress = stageInfo.progress; const getStatusColor = () => { if (status === 'finished' || status === 'done') return '#28a745'; if (status === 'failed') return '#dc3545'; return '#1a73e8'; }; return (
Job: {jobId.substring(0, 8)} {status}
Current Step: {stageInfo.label}
{(status !== 'finished' && status !== 'done' && status !== 'failed') ? (
Estimated Progress: {progress}% ETA: {Math.floor(countdown / 60)}m {countdown % 60}s
) : (status === 'finished' || status === 'done') ? ( ) : null}
); }; export default StatusMonitor;