"use client"; import { use, useEffect, useRef, useState } from "react"; import { useQuery } from "@tanstack/react-query"; import Link from "next/link"; import { ArrowLeft, ExternalLink, FileX, Tag, User } from "lucide-react"; import { useBill, useBillNews, useBillTrend } from "@/lib/hooks/useBills"; import { useAuthStore } from "@/stores/authStore"; import { BriefPanel } from "@/components/bills/BriefPanel"; import { DraftLetterPanel } from "@/components/bills/DraftLetterPanel"; import { NotesPanel } from "@/components/bills/NotesPanel"; import { ActionTimeline } from "@/components/bills/ActionTimeline"; import { VotePanel } from "@/components/bills/VotePanel"; import { TrendChart } from "@/components/bills/TrendChart"; import { NewsPanel } from "@/components/bills/NewsPanel"; import { FollowButton } from "@/components/shared/FollowButton"; import { CollectionPicker } from "@/components/bills/CollectionPicker"; import { billLabel, chamberBadgeColor, congressLabel, formatDate, partyBadgeColor, cn } from "@/lib/utils"; import { TOPIC_LABEL, TOPIC_TAGS } from "@/lib/topics"; const TABS = [ { id: "analysis", label: "Analysis" }, { id: "timeline", label: "Timeline" }, { id: "votes", label: "Votes" }, { id: "notes", label: "Notes" }, ] as const; type TabId = typeof TABS[number]["id"]; export default function BillDetailPage({ params }: { params: Promise<{ id: string }> }) { const { id } = use(params); const billId = decodeURIComponent(id); const [activeTab, setActiveTab] = useState("analysis"); const token = useAuthStore((s) => s.token); const { data: bill, isLoading } = useBill(billId); const { data: trendData } = useBillTrend(billId, 30); const { data: newsArticles, refetch: refetchNews } = useBillNews(billId); const { data: note } = useQuery({ queryKey: ["note", billId], queryFn: () => import("@/lib/api").then((m) => m.notesAPI.get(billId)), enabled: !!token, retry: false, throwOnError: false, }); const newsRetryRef = useRef(0); useEffect(() => { newsRetryRef.current = 0; }, [billId]); useEffect(() => { if (newsArticles === undefined || newsArticles.length > 0) return; if (newsRetryRef.current >= 3) return; const timer = setTimeout(() => { newsRetryRef.current += 1; refetchNews(); }, 6000); return () => clearTimeout(timer); }, [newsArticles]); // eslint-disable-line react-hooks/exhaustive-deps if (isLoading) { return
Loading bill...
; } if (!bill) { return (

Bill not found.

← Back to bills
); } const label = billLabel(bill.bill_type, bill.bill_number); return (
{/* Header */}
{label} {bill.chamber && ( {bill.chamber} )} {congressLabel(bill.congress_number)}

{bill.short_title || bill.title || "Untitled Bill"}

{bill.sponsor && (
{bill.sponsor.name} {bill.sponsor.party && ( {bill.sponsor.party} )} {bill.sponsor.state && {bill.sponsor.state}}
)}

{bill.introduced_date && ( Introduced: {formatDate(bill.introduced_date)} )} {bill.congress_url && ( congress.gov )}

{/* Content grid */}
{/* Pinned note always visible above tabs */} {note?.pinned && } {/* Tab bar */}
{TABS.map((tab) => ( ))}
{/* Topic tags — only show tags that have a matching topic page */} {bill.briefs[0]?.topic_tags && bill.briefs[0].topic_tags.filter((t) => TOPIC_TAGS.has(t)).length > 0 && (
{bill.briefs[0].topic_tags.filter((t) => TOPIC_TAGS.has(t)).map((tag) => ( {TOPIC_LABEL[tag] ?? tag} ))}
)} {/* Tab content */} {activeTab === "analysis" && (
{bill.briefs.length > 0 ? ( <> ) : bill.has_document ? (

Analysis pending

Bill text was retrieved but has not yet been analyzed. Check back shortly.

) : (
No bill text published

As of {new Date().toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" })},{" "} no official text has been received for{" "} {billLabel(bill.bill_type, bill.bill_number)}. Analysis will be generated automatically once text is published on Congress.gov.

{bill.congress_url && ( Check status on Congress.gov )}
)}
)} {activeTab === "timeline" && ( )} {activeTab === "votes" && ( )} {activeTab === "notes" && ( )}
); }