/** Reusable data tables for entity detail pages — all `.data-table.stack` (stacked cards under 768 px). */ import Link from 'next/link'; import { OrbitBadge, StatusBadge, TypeBadge } from '@/components/ui/badges'; import { MissionLabel } from '@/components/ui/badges'; import { fmtDate, fmtInt, fmtKm, fmtDeg, titleCase } from '@/lib/format'; import { routes } from '@/lib/site'; import type { Num } from '@/lib/types'; import { EmptyRow, ScrollTable } from './shared'; // ---------------------------------------------------------------------------------------------------- launches export interface LaunchLike { id: string; cospar_launch_id: string; launch_date: string | null; site_name: string | null; site_slug: string | null; satellites?: Num; payload_count?: Num; active?: Num; primary_name?: string | null; } export function LaunchesTable({ rows, showActive = false, showPrimary = false }: { rows: LaunchLike[]; showActive?: boolean; showPrimary?: boolean }) { const cols = 4 + (showActive ? 1 : 0) + (showPrimary ? 1 : 0); return ( {showPrimary && } {showActive && } {rows.length === 0 && No launches recorded.} {rows.map((l) => ( {showPrimary && } {showActive && } ))}
Launch DatePrimary payloadSite {showPrimary ? 'Payloads' : 'Satellites'}Active
{l.cospar_launch_id} {fmtDate(l.launch_date)}{l.primary_name ?? '—'} {l.site_slug ? {l.site_name ?? l.site_slug} : l.site_name ?? '—'} {fmtInt(l.satellites ?? l.payload_count)}{fmtInt(l.active)}
); } // ------------------------------------------------------------------------------------------------ launch sites export interface SiteLike { code: string; name: string; slug: string; country_code?: string | null; launches: Num; satellites?: Num; last_launch?: string | null; } export function SitesTable({ rows, showSatellites = false, showLast = false }: { rows: SiteLike[]; showSatellites?: boolean; showLast?: boolean }) { const cols = 3 + (showSatellites ? 1 : 0) + (showLast ? 1 : 0); return ( {showSatellites && } {showLast && } {rows.length === 0 && No launch sites recorded.} {rows.map((s) => ( {showSatellites && } {showLast && } ))}
Site Code LaunchesSatellitesLast launch
{s.name} {s.country_code && {s.country_code}} {s.code} {fmtInt(s.launches)}{fmtInt(s.satellites)}{fmtDate(s.last_launch)}
); } // -------------------------------------------------------------------------------------------------- satellites export interface SatLike { id: string; slug: string; name: string; norad_id: number | null; status: string; object_type?: string; orbit_class?: string | null; mission_type?: string | null; launch_date: string | null; perigee_km?: Num; apogee_km?: Num; inclination_deg?: Num; } export function SatellitesTable({ rows, columns }: { rows: SatLike[]; columns: ('type' | 'orbit' | 'mission' | 'perigee' | 'apogee' | 'inclination')[] }) { const has = (c: (typeof columns)[number]) => columns.includes(c); const cols = 4 + columns.length; return ( {has('type') && } {has('orbit') && } {has('mission') && } {has('perigee') && } {has('apogee') && } {has('inclination') && } {rows.length === 0 && No satellites recorded.} {rows.map((s) => ( {has('type') && } {has('orbit') && } {has('mission') && } {has('perigee') && } {has('apogee') && } {has('inclination') && } ))}
Satellite NORAD StatusTypeOrbitMissionLaunchedPerigeeApogeeIncl.
{s.name} {s.norad_id ?? '—'} {fmtDate(s.launch_date)}{fmtKm(s.perigee_km)}{fmtKm(s.apogee_km)}{fmtDeg(s.inclination_deg)}
); } // ------------------------------------------------------------------------------------------ constellation lists export interface ConstellationLike { id: string; slug: string; name: string; service_type: string | null; orbit_class: string | null; active: Num; total: Num; launched_last_365d?: Num; } export function ConstellationsMiniTable({ rows }: { rows: ConstellationLike[] }) { const showGrowth = rows.some((r) => r.launched_last_365d !== undefined); return ( {showGrowth && } {rows.length === 0 && No constellations linked.} {rows.map((c) => ( {showGrowth && } ))}
Constellation Service Orbit Active Total365 d
{c.name} {titleCase(c.service_type)} {fmtInt(c.active)} {fmtInt(c.total)}{fmtInt(c.launched_last_365d)}
); } // ----------------------------------------------------------------------------------------------- operator lists export interface OperatorLike { id: string; slug: string; name: string; kind: string; active_payloads: Num; total_payloads: Num; payloads_last_365d: Num; } export function OperatorsMiniTable({ rows }: { rows: OperatorLike[] }) { return ( {rows.length === 0 && No operators linked.} {rows.map((o) => ( ))}
Operator Kind Active Total 365 d
{o.name} {titleCase(o.kind)} {fmtInt(o.active_payloads)} {fmtInt(o.total_payloads)} {fmtInt(o.payloads_last_365d)}
); }