import type { ZoneObs, Action, PyTorchScore } from '../types' interface Props { zones: ZoneObs[] action?: Action | null falseSOSZones?: string[] pytorchScores?: PyTorchScore[] compact?: boolean } function severityColor(z: ZoneObs, isFalseSOS: boolean, isCompleted: boolean): string { if (isFalseSOS) return 'border-zinc-600 bg-zinc-900 opacity-60' if (isCompleted) return 'border-green-600 bg-green-950' if (z.severity >= 0.8) return 'border-red-500 bg-red-950' if (z.severity >= 0.6) return 'border-orange-500 bg-orange-950' return 'border-yellow-600 bg-yellow-950' } function severityBadgeColor(z: ZoneObs): string { if (z.severity >= 0.8) return 'bg-red-500' if (z.severity >= 0.6) return 'bg-orange-500' return 'bg-yellow-500' } export function DisasterMap({ zones, action, falseSOSZones = [], pytorchScores = [], compact = false }: Props) { const scoreMap = Object.fromEntries(pytorchScores.map(s => [s.zone_id, s])) const actionTarget = action?.to_zone ?? action?.from_zone const pad = compact ? 'p-2' : 'p-3' const gap = compact ? 'gap-2' : 'gap-3' const cols = zones.length <= 1 ? 'grid-cols-1' : zones.length <= 3 ? 'grid-cols-3' : zones.length <= 5 ? 'grid-cols-3' : 'grid-cols-5' return (
{zones.map(z => { const isFalseSOS = falseSOSZones.includes(z.zone_id) const isCompleted = z.casualties_remaining === 0 && z.supply_gap === 0 && !isFalseSOS const isTarget = actionTarget === z.zone_id const score = scoreMap[z.zone_id] const borderClass = severityColor(z, isFalseSOS, isCompleted) const pulseClass = isTarget ? (isCompleted ? 'zone-pulse-green' : 'zone-pulse') : '' return (
{/* Zone header */}
Zone {z.zone_id}
{z.road_blocked && !isFalseSOS && ( 🚧 )} {z.sos_active && !isFalseSOS && ( 🆘 )} {isFalseSOS && ( ⚠️ )} {isCompleted && ( )} {isTarget && action?.action === 'airlift' && ( 🚁 )}
{isFalseSOS ? (

False SOS — no casualties

) : ( <> {!compact && (
)}
Casualties 0 ? 'text-red-400' : 'text-green-400'}`}> {z.casualties_remaining}
Supply gap 0 ? 'text-orange-400' : 'text-green-400'}`}> {z.supply_gap}
{!compact && (
Teams {z.teams_present}
)} {score && !compact && (
PyTorch 0.6 ? 'text-purple-400' : score.score > 0.3 ? 'text-zinc-300' : 'text-zinc-600'}`}> {score.score.toFixed(3)}
)}
)} {/* Action highlight overlay */} {isTarget && (
)}
) })}
) }