busi488energy/src/components/dashboard/grid-stress-gauge.tsx

88 lines
2.4 KiB
TypeScript

'use client';
import { cn } from '@/lib/utils.js';
interface GridStressGaugeProps {
regionCode: string;
regionName: string;
demandMw: number;
capacityMw: number;
className?: string;
}
function getStressColor(pct: number): string {
if (pct >= 90) return '#ef4444';
if (pct >= 80) return '#f97316';
if (pct >= 60) return '#eab308';
return '#22c55e';
}
function getStressLabel(pct: number): string {
if (pct >= 90) return 'Critical';
if (pct >= 80) return 'High';
if (pct >= 60) return 'Moderate';
return 'Normal';
}
export function GridStressGauge({ regionCode, regionName, demandMw, capacityMw, className }: GridStressGaugeProps) {
const pct = capacityMw > 0 ? Math.min((demandMw / capacityMw) * 100, 100) : 0;
const color = getStressColor(pct);
const label = getStressLabel(pct);
const radius = 40;
const circumference = Math.PI * radius;
const offset = circumference - (pct / 100) * circumference;
const isCritical = pct >= 85;
return (
<div className={cn('flex flex-col items-center gap-2', className)}>
<svg
viewBox="0 0 100 55"
className="w-full max-w-[140px]"
style={{
filter: isCritical ? `drop-shadow(0 0 8px ${color}80)` : undefined,
}}>
{/* Background arc */}
<path
d="M 10 50 A 40 40 0 0 1 90 50"
fill="none"
stroke="currentColor"
strokeWidth="8"
strokeLinecap="round"
className="text-muted/40"
/>
{/* Filled arc */}
<path
d="M 10 50 A 40 40 0 0 1 90 50"
fill="none"
stroke={color}
strokeWidth="8"
strokeLinecap="round"
strokeDasharray={circumference}
strokeDashoffset={offset}
style={{
transition: 'stroke-dashoffset 1s ease-in-out, stroke 0.5s ease',
}}
/>
{/* Percentage text */}
<text
x="50"
y="45"
textAnchor="middle"
className="fill-foreground text-[14px] font-bold"
style={{ fontFamily: 'ui-monospace, monospace' }}>
{pct.toFixed(0)}%
</text>
</svg>
<div className="text-center">
<div className="text-xs font-semibold">{regionCode}</div>
<div className="text-[10px] text-muted-foreground">{regionName}</div>
<div className="mt-0.5 text-[10px] font-medium" style={{ color }}>
{label}
</div>
</div>
</div>
);
}