import { useEffect, useMemo, useState } from "react"; import { Activity, Users, ShieldAlert, Clock, Flame, Gauge as GaugeIcon, ChevronDown, MapPin, Sparkles, AlertTriangle, } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input, Textarea, Label } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { SearchSelect } from "@/components/ui/search-select"; import { InfoTip } from "@/components/ui/popover"; import { Spinner } from "@/components/ui/feedback"; import { Gauge } from "@/components/Gauge"; import { LocationPicker } from "@/components/LocationPicker"; import { api } from "@/lib/api"; import type { OptionsResponse, PredictRequest, PredictResponse } from "@/lib/types"; import { cn } from "@/lib/utils"; import { LEVEL_STYLES, minutesToHuman, pct, titleCase } from "@/lib/format"; const DEFAULT_LAT = 12.9716; const DEFAULT_LNG = 77.5946; const CLOSURE_BASE = 0.072; const PRIORITY_BASE = 0.622; const HOTSPOT_BASE = 0.156; function nowLocalInput(): string { const d = new Date(); d.setMinutes(d.getMinutes() - d.getTimezoneOffset()); return d.toISOString().slice(0, 16); } // Treat the entered wall-clock time as Bengaluru local (IST, +05:30). const toIST = (local: string): string => `${local}:00+05:30`; const OPTIONAL_FIELDS: { key: keyof PredictRequest; label: string; search?: boolean }[] = [ { key: "police_station", label: "Police station", search: true }, { key: "junction", label: "Junction", search: true }, { key: "corridor", label: "Corridor" }, { key: "zone", label: "Zone" }, { key: "direction", label: "Direction" }, { key: "veh_type", label: "Vehicle type" }, { key: "reason_breakdown", label: "Breakdown reason" }, { key: "cargo_material", label: "Cargo material" }, ]; export default function Predict() { const [options, setOptions] = useState(null); const [lat, setLat] = useState(DEFAULT_LAT); const [lng, setLng] = useState(DEFAULT_LNG); const [startLocal, setStartLocal] = useState(nowLocalInput()); const [form, setForm] = useState>({ event_type: "unplanned", event_cause: "vehicle_breakdown", authenticated: "yes", description: "", }); const [showOptional, setShowOptional] = useState(false); const [result, setResult] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); useEffect(() => { api.options().then(setOptions).catch(() => setOptions(null)); }, []); const cats = options?.categories ?? {}; const setField = (key: keyof PredictRequest, value: string | number | undefined) => setForm((f) => ({ ...f, [key]: value })); async function onSubmit() { setLoading(true); setError(null); try { const payload: PredictRequest = { ...form, latitude: lat, longitude: lng, start_datetime: toIST(startLocal), } as PredictRequest; const res = await api.predict(payload); setResult(res); } catch (e) { setError((e as Error).message); setResult(null); } finally { setLoading(false); } } function pickStation(name: string | undefined) { setField("police_station", name); const st = options?.stations.find((s) => s.name === name); if (st) { setLat(st.lat); setLng(st.lng); } } return (
{/* ---------------- Form ---------------- */}

Forecast an event

Enter what's known at report time. Only location and start time are required — everything else sharpens the forecast.

{/* Required */}
Required
setStartLocal(e.target.value)} />
s.name)} value={form.police_station} onChange={pickStation} placeholder="Search station to center map…" />
setLat(Number(e.target.value))} />
setLng(Number(e.target.value))} />
{ setLat(la); setLng(ln); }} />
{/* Event details */}