import type { FacilityFilters, FacilitySummary } from "@dci/core"; import Link from "next/link"; import { ConfidenceBadge, EstimateMark, FlagBadges, StatusBadge, TypeBadge } from "@/components/ui/badge"; import { CountryFlag } from "@/components/ui/country-flag"; import { EmptyState } from "@/components/ui/states"; import { RowLink, TBody, THead, Table, Td, Th, Tr } from "@/components/ui/table"; import { bestMw, fmtMw } from "@/lib/format"; import { filtersToQuery } from "@/lib/query"; import { routes } from "@/lib/routes"; export interface FacilityTableProps { items: FacilitySummary[]; /** current filters → sort links */ filters?: FacilityFilters; basePath?: string; /** hide columns for compact embeds */ columns?: Array<"operator" | "market" | "country" | "status" | "mw" | "type" | "confidence">; emptyTitle?: string; emptyDescription?: string; } const ALL: NonNullable = ["operator", "market", "country", "status", "mw", "type", "confidence"]; /** * Facility index table. Sortable headers link to ?sort=&order= (server-side). Under 640 px, rows * become stacked cards (data-label). Reused by /datacenters, /search and the entity pages. */ export function FacilityTable({ items, filters = {}, basePath = routes.datacenters(), columns = ALL, emptyTitle = "No facilities match these filters", emptyDescription = "Loosen a filter or clear them all." }: FacilityTableProps) { const has = (c: (typeof ALL)[number]) => columns.includes(c); const sortHref = (key: NonNullable) => { const dir = filters.sort === key ? (filters.order === "asc" ? "desc" : "asc") : key === "name" ? "asc" : "desc"; const q = filtersToQuery({ ...filters, sort: key, order: dir, page: undefined }); return `${basePath}${q ? `?${q}` : ""}`; }; const sortState = (key: NonNullable) => (filters.sort === key ? (filters.order ?? "desc") : null); if (!items.length) return ; return ( {has("operator") && } {has("market") && } {has("country") && } {has("status") && } {has("mw") && ( )} {has("type") && } {has("confidence") && ( )} {items.map((f) => { const { mw, kind } = bestMw(f); return ( {has("operator") && ( )} {has("market") && ( )} {has("country") && ( )} {has("status") && ( )} {has("mw") && ( )} {has("type") && ( )} {has("confidence") && ( )} ); })}
Facility OperatorMarketCountryStatus Capacity Type Confidence
{f.name}
{f.operator?.name ?? "Operator unknown"} {f.city ? ` · ${f.city}` : ""}
{f.operator ? ( {f.operator.name} ) : ( — )} {f.metro ? ( {f.metro.name} ) : ( f.city ?? "—" )} {mw === null ? ( — ) : ( {kind === "planned" && } {fmtMw(mw)} )}
); }