'use client'; import { useState, type ChangeEvent } from 'react'; import type { ContractState, PlaneState, StateSnapshot } from '@/lib/game/state'; import { PLANE_TYPES } from '@/lib/game/catalog'; import { formatCash, formatFuel, formatSimClock } from '@/lib/format'; interface LeftPaneProps { state: StateSnapshot | null; loading: boolean; error: string | null; // The shell's single-poll refresh — called after a sim-control POST so the pane updates immediately. onRefresh: () => void; } const SCALE_OPTIONS = Array.from({ length: 60 }, (_, i) => i + 1); // 1x–60x, matching POST /api/sim's clamp range function planeLocation(p: PlaneState, contracts: ContractState[]): string { if (p.status === 'flying' && p.contractId) { const c = contracts.find((c) => c.id === p.contractId); if (c) return `${p.locationName} → ${c.destName}`; } return p.locationName; } export default function LeftPane({ state, loading, error, onRefresh }: LeftPaneProps) { const [busy, setBusy] = useState(false); // POST /api/sim, then refetch the full snapshot immediately so the pane reflects the new // controls without waiting for the next poll tick. On failure keep the stale UI — the // running poll retries on its own and surfaces the error state. const applySimControls = async (body: { timeScale?: number; paused?: boolean }) => { if (busy) return; setBusy(true); try { const res = await fetch('/api/sim', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), cache: 'no-store', }); if (!res.ok) throw new Error(`POST /api/sim → HTTP ${res.status}`); onRefresh(); } catch (err) { console.error('failed to apply sim controls', err); } finally { setBusy(false); } }; const paused = state?.simState.paused ?? false; const timeScale = state?.simState.timeScale ?? 1; return ( ); }