spb/market-atlas
Public
TypeScript 96.7%
SQL 1.6%
CSS 0.8%
JavaScript 0.5%
1import type { Metadata } from "next";2import Link from "next/link";3import { Empty, Page, PageHeader } from "@/components/ui/section";4import { apiEnvelope } from "@/lib/api";5import { cx, formatDateTime, instrumentHref } from "@/lib/format";6import type { Filing } from "@/lib/types";78export const metadata: Metadata = { title: "Filings", description: "Regulatory filings observed on SEC EDGAR, linked to instruments by CIK.", alternates: { canonical: "/filings" } };9export const dynamic = "force-dynamic";1011const FORMS = ["8-K", "10-K", "10-Q", "6-K", "S-1", "SC 13D", "SC 13G", "DEF 14A", "4", "424B4", "13F-HR"];1213export default async function FilingsPage({ searchParams }: { searchParams: Promise<Record<string, string | string[] | undefined>> }) {14 const sp = await searchParams;15 const form = typeof sp.form === "string" ? sp.form : "";16 const q = typeof sp.q === "string" ? sp.q : "";17 const cik = typeof sp.cik === "string" ? sp.cik : "";18 const page = Math.max(1, Number(sp.page ?? 1) || 1);19 const params = new URLSearchParams({ limit: "100", offset: String((page - 1) * 100) });20 if (form) params.set("form", form);21 if (q) params.set("q", q);22 if (cik) params.set("cik", cik);23 const env = await apiEnvelope<Filing[]>(`/v1/filings?${params}`);24 const rows = env.data;25 const link = (patch: Record<string, string | number>) => {26 const u = new URLSearchParams();27 for (const [k, v] of Object.entries({ form, q, cik, page: page > 1 ? page : "", ...patch })) if (v !== "" && v !== 0) u.set(k, String(v));28 const s = u.toString();29 return s ? `/filings?${s}` : "/filings";30 };31 return (32 <Page wide>33 <PageHeader kicker="Regulatory" title="Filings" lead={`Documents filed on SEC EDGAR as Market Atlas observes them (every 2 minutes). ${Number(env.meta.last_7_days ?? 0).toLocaleString("en-US")} filings in the last 7 days. Material forms (8-K, 10-K/Q, 6-K, S-1, 13D/G…) also appear as events.`} />34 <div className="mb-3 flex flex-wrap items-center gap-1.5">35 <Link href={link({ form: "", page: "" })} className={cx("inline-flex h-8 items-center rounded-full border px-3 text-xs", !form ? "border-ink bg-ink text-canvas" : "border-rule text-ink-2 hover:border-rule-strong")}>36 All forms37 </Link>38 {FORMS.map((f) => (39 <Link key={f} href={link({ form: f, page: "" })} className={cx("mono inline-flex h-8 items-center rounded-full border px-3 text-xs", form === f ? "border-ink bg-ink text-canvas" : "border-rule text-ink-2 hover:border-rule-strong")}>40 {f}41 </Link>42 ))}43 <form action="/filings" className="ml-auto flex gap-2">44 {form && <input type="hidden" name="form" value={form} />}45 <input name="q" defaultValue={q} placeholder="Company name" className="h-9 w-48 rounded-md border border-rule bg-surface px-2 text-sm outline-none focus:border-rule-strong" />46 </form>47 </div>48 {cik && (49 <p className="mb-2 text-xs text-ink-3">50 Filtered by CIK {cik} ·{" "}51 <Link href={link({ cik: "", page: "" })} className="text-accent hover:underline">52 clear53 </Link>54 </p>55 )}56 {rows.length ? (57 <div className="overflow-x-auto rounded-md border border-rule bg-surface">58 <table className="table-dense">59 <thead>60 <tr>61 <th>Filed (ET)</th>62 <th>Form</th>63 <th>Filer</th>64 <th className="hidden md:table-cell">CIK</th>65 <th className="hidden md:table-cell">Role</th>66 <th>Instruments</th>67 <th>Document</th>68 </tr>69 </thead>70 <tbody>71 {rows.map((f) => (72 <tr key={f.id}>73 <td className="mono text-ink-2">{formatDateTime(f.filed_at, { tz: "America/New_York" })}</td>74 <td className="mono font-medium">75 {f.form_type}76 {f.metadata.material === true && <span className="ml-1 text-[10px] uppercase text-accent">material</span>}77 </td>78 <td>79 <Link href={link({ q: f.company_name, page: "" })} className="hover:underline">80 {f.company_name}81 </Link>82 </td>83 <td className="mono hidden text-ink-3 md:table-cell">84 {f.cik ? (85 <Link href={link({ cik: f.cik, page: "" })} className="hover:underline">86 {f.cik}87 </Link>88 ) : (89 "—"90 )}91 </td>92 <td className="hidden text-xs text-ink-3 md:table-cell">{String(f.metadata.role ?? "—")}</td>93 <td>94 {f.instrument_ids.length ? (95 f.instrument_ids.slice(0, 3).map((id) => (96 <Link key={id} href={instrumentHref(id)} className="mono mr-1 text-xs text-accent hover:underline">97 {id.split("_").pop()?.toUpperCase()}98 </Link>99 ))100 ) : (101 <span className="text-xs text-ink-3">—</span>102 )}103 </td>104 <td>105 <a href={f.url} target="_blank" rel="noopener noreferrer" className="text-accent hover:underline">106 EDGAR ↗107 </a>108 </td>109 </tr>110 ))}111 </tbody>112 </table>113 </div>114 ) : (115 <Empty>No filings match.</Empty>116 )}117 <div className="mt-3 flex justify-between text-xs">118 {page > 1 ? (119 <Link href={link({ page: page - 1 })} className="text-accent hover:underline">120 ← Newer121 </Link>122 ) : (123 <span />124 )}125 {rows.length === 100 && (126 <Link href={link({ page: page + 1 })} className="text-accent hover:underline">127 Older →128 </Link>129 )}130 </div>131 </Page>132 );133}134