"use client"; import { useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { ListChecks, ChevronDown, ChevronUp } from "lucide-react"; import { billsAPI, followsAPI } from "@/lib/api"; import { cn, formatDate, partyBadgeColor } from "@/lib/utils"; import type { BillVote, MemberVotePosition } from "@/lib/types"; interface VotePanelProps { billId: string; alwaysRender?: boolean; } export function VotePanel({ billId, alwaysRender = false }: VotePanelProps) { const [expanded, setExpanded] = useState(true); const { data: votes, isLoading } = useQuery({ queryKey: ["votes", billId], queryFn: () => billsAPI.getVotes(billId), staleTime: 5 * 60 * 1000, }); const { data: follows } = useQuery({ queryKey: ["follows"], queryFn: () => followsAPI.list(), retry: false, throwOnError: false, }); const followedMemberIds = new Set( (follows || []) .filter((f) => f.follow_type === "member") .map((f) => f.follow_value) ); if (isLoading || !votes || votes.length === 0) { if (!alwaysRender) return null; return (

{isLoading ? "Checking for roll-call votes…" : "No roll-call votes have been recorded for this bill."}

); } return (
{expanded && (
{votes.map((vote) => ( ))}
)}
); } function VoteRow({ vote, followedMemberIds, }: { vote: BillVote; followedMemberIds: Set; }) { const [showPositions, setShowPositions] = useState(false); const total = (vote.yeas ?? 0) + (vote.nays ?? 0) + (vote.not_voting ?? 0); const yeaPct = total > 0 ? ((vote.yeas ?? 0) / total) * 100 : 0; const nayPct = total > 0 ? ((vote.nays ?? 0) / total) * 100 : 0; const resultLower = (vote.result ?? "").toLowerCase(); const passed = resultLower.includes("pass") || resultLower.includes("agreed") || resultLower.includes("adopted") || resultLower.includes("enacted"); const followedPositions: MemberVotePosition[] = vote.positions.filter( (p) => p.bioguide_id && followedMemberIds.has(p.bioguide_id) ); return (
{/* Header row */}
{vote.result && ( {vote.result} )} {vote.chamber} Roll #{vote.roll_number} {vote.vote_date && ` · ${formatDate(vote.vote_date)}`}
{vote.question && (

{vote.question}

)}
{vote.source_url && ( Source ↗ )}
{/* Yea / Nay bar */} {total > 0 && (
{vote.yeas ?? "—"} Yea {vote.nays ?? "—"} Nay {(vote.not_voting ?? 0) > 0 && ( {vote.not_voting} Not Voting )}
)} {/* Followed member positions */} {followedPositions.length > 0 && (
{showPositions && (
{followedPositions.map((p, i) => (
{vote.chamber === "Senate" ? "Sen." : "Rep."} {p.member_name} {p.party && ( {p.party} )} {p.state && {p.state}} {p.position}
))}
)}
)}
); }