"use client"; import { useState, useEffect } from "react"; import { useParams, useRouter } from "next/navigation"; import { useJobProgress } from "@/hooks/use-job-progress"; interface CityDetail { slug: string; name: string; country_code: string; geofabrik_url: string; status: string; last_ingested: string | null; poi_count: number; grid_count: number; error_message: string | null; } export default function CityDetailPage() { const { slug } = useParams<{ slug: string }>(); const router = useRouter(); const [city, setCity] = useState(null); const [loading, setLoading] = useState(true); const [jobId, setJobId] = useState(null); const [deleting, setDeleting] = useState(false); const { stages, overall } = useJobProgress(jobId); useEffect(() => { fetch(`/api/admin/cities`) .then((r) => r.json()) .then((all: CityDetail[]) => { setCity(all.find((c) => c.slug === slug) ?? null); setLoading(false); }) .catch(() => setLoading(false)); }, [slug]); const handleReIngest = async () => { const res = await fetch(`/api/admin/ingest/${slug}`, { method: "POST" }); if (res.ok) { const data = await res.json(); setJobId(data.jobId); } }; const handleDelete = async () => { if (!confirm(`Delete city "${city?.name}"? This will remove all POI and grid data.`)) return; setDeleting(true); const res = await fetch(`/api/admin/cities/${slug}`, { method: "DELETE" }); if (res.ok) router.push("/admin"); else setDeleting(false); }; if (loading) return
Loading…
; if (!city) return (
City not found.{" "} Back
); return (
← Back

{city.name}

{city.slug}
{/* Stats */}
{[ { label: "POIs", value: city.poi_count.toLocaleString() }, { label: "Grid Points", value: city.grid_count.toLocaleString() }, { label: "Last Ingested", value: city.last_ingested ? new Date(city.last_ingested).toLocaleDateString() : "Never", }, ].map((s) => (

{s.value}

{s.label}

))}
{/* Source */}

Data Source

{city.geofabrik_url}

{/* Live progress if ingesting */} {jobId && (

Ingestion Progress

    {stages.map((s) => (
  1. {s.status === "completed" ? "✓" : s.status === "active" ? "…" : "○"} {s.label} {s.status === "active" && ( {s.pct}% )}
  2. ))}
{overall === "completed" && (

✓ Ingestion complete!

)}
)} {/* Actions */}
); }