busi488energy/src/components/map/region-detail-panel.tsx

84 lines
3.3 KiB
TypeScript

'use client';
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/components/ui/sheet.js';
import type { DatacenterMarkerData } from './datacenter-marker.js';
import type { RegionHeatmapData } from './region-overlay.js';
interface RegionDetailPanelProps {
region: RegionHeatmapData | null;
datacenters: DatacenterMarkerData[];
onClose: () => void;
}
export function RegionDetailPanel({ region, datacenters, onClose }: RegionDetailPanelProps) {
const regionDatacenters = region
? datacenters.filter(dc => dc.region_code === region.code).sort((a, b) => b.capacity_mw - a.capacity_mw)
: [];
return (
<Sheet open={region !== null} onOpenChange={open => !open && onClose()}>
<SheetContent side="right" className="overflow-y-auto bg-zinc-950 text-zinc-100">
{region && (
<>
<SheetHeader>
<SheetTitle className="text-zinc-100">{region.name}</SheetTitle>
<SheetDescription className="text-zinc-400">Grid region {region.code}</SheetDescription>
</SheetHeader>
<div className="flex flex-col gap-4 p-4">
<div className="grid grid-cols-2 gap-3">
<MetricItem
label="Avg Price (24h)"
value={region.avgPrice !== null ? `$${region.avgPrice.toFixed(2)}/MWh` : 'No data'}
/>
<MetricItem
label="Max Price (24h)"
value={region.maxPrice !== null ? `$${region.maxPrice.toFixed(2)}/MWh` : 'No data'}
/>
<MetricItem
label="Avg Demand"
value={region.avgDemand !== null ? `${Math.round(region.avgDemand).toLocaleString()} MW` : 'No data'}
/>
<MetricItem label="Datacenters" value={String(region.datacenterCount ?? 0)} />
<MetricItem
label="Total DC Capacity"
value={
region.totalDcCapacityMw !== null
? `${Math.round(region.totalDcCapacityMw).toLocaleString()} MW`
: '0 MW'
}
/>
</div>
{regionDatacenters.length > 0 && (
<div>
<h3 className="mb-2 text-sm font-semibold text-zinc-300">Datacenters in Region</h3>
<div className="flex flex-col gap-2">
{regionDatacenters.map(dc => (
<div key={dc.id} className="rounded-lg border border-zinc-800 bg-zinc-900/50 p-3">
<div className="text-sm font-medium text-zinc-200">{dc.name}</div>
<div className="mt-0.5 text-xs text-zinc-500">
{dc.operator} &middot; {dc.capacity_mw} MW &middot; {dc.status}
</div>
</div>
))}
</div>
</div>
)}
</div>
</>
)}
</SheetContent>
</Sheet>
);
}
function MetricItem({ label, value }: { label: string; value: string }) {
return (
<div className="rounded-lg border border-zinc-800 bg-zinc-900/50 p-3">
<div className="mb-0.5 text-xs font-medium text-zinc-500">{label}</div>
<div className="text-sm font-semibold text-zinc-200">{value}</div>
</div>
);
}