({
completedJobs,
onDownloadAll,
onDownloadZip,
onClearCompleted,
isZipping,
})
| 12 | } |
| 13 | |
| 14 | export const StatsPanel: React.FC<StatsPanelProps> = ({ |
| 15 | completedJobs, |
| 16 | onDownloadAll, |
| 17 | onDownloadZip, |
| 18 | onClearCompleted, |
| 19 | isZipping, |
| 20 | }) => { |
| 21 | const stats = useMemo(() => { |
| 22 | let totalOriginal = 0; |
| 23 | let totalOptimized = 0; |
| 24 | |
| 25 | completedJobs.forEach(job => { |
| 26 | if (job.stats) { |
| 27 | totalOriginal += job.stats.originalSize; |
| 28 | totalOptimized += job.stats.optimizedSize; |
| 29 | } |
| 30 | }); |
| 31 | |
| 32 | const validIntervals = completedJobs |
| 33 | .filter(j => j.startedAt && j.completedAt) |
| 34 | .map(j => ({start: j.startedAt!, end: j.completedAt!})) |
| 35 | .sort((a, b) => a.start - b.start); |
| 36 | |
| 37 | let totalTime = 0; |
| 38 | if (validIntervals.length > 0) { |
| 39 | let currentStart = validIntervals[0].start; |
| 40 | let currentEnd = validIntervals[0].end; |
| 41 | |
| 42 | for (let i = 1; i < validIntervals.length; i++) { |
| 43 | const next = validIntervals[i]; |
| 44 | if (next.start < currentEnd) { |
| 45 | currentEnd = Math.max(currentEnd, next.end); |
| 46 | } else { |
| 47 | totalTime += currentEnd - currentStart; |
| 48 | currentStart = next.start; |
| 49 | currentEnd = next.end; |
| 50 | } |
| 51 | } |
| 52 | totalTime += currentEnd - currentStart; |
| 53 | } |
| 54 | |
| 55 | if (totalOriginal === 0) |
| 56 | return {percent: '0', isIncrease: false, savedBytes: 0, totalTime: 0}; |
| 57 | |
| 58 | const diff = totalOriginal - totalOptimized; |
| 59 | const percentVal = (diff / totalOriginal) * 100; |
| 60 | |
| 61 | return { |
| 62 | percent: Math.abs(percentVal).toFixed(1), |
| 63 | isIncrease: percentVal < 0, |
| 64 | savedBytes: diff, |
| 65 | totalTime, |
| 66 | }; |
| 67 | }, [completedJobs]); |
| 68 | |
| 69 | return ( |
| 70 | <div className="sticky top-6 space-y-6 z-20 transition-all duration-300 ease-out"> |
| 71 | <div className="bg-gleam-dark text-gleam-cream rounded-3xl p-8 shadow-xl relative overflow-hidden ring-4 ring-black/5 group transition-transform duration-300 dark:ring-white/5 dark:bg-black"> |
nothing calls this directly
no outgoing calls
no test coverage detected