Files
PocketVeto/frontend/components/bills/ActionTimeline.tsx
Jack Levy f3a8c1218a Add chamber color badges, action history fallback, and task status polling
- Add chamberBadgeColor util: amber/gold for Senate, slate/silver for House
- Apply chamber badge to BillCard and bill detail header
- ActionTimeline: show latest_action_date/text as fallback when full history
  not yet fetched, with note that full history loads in background
- Manual Controls: poll task status every 5s after triggering, show spinning
  indicator while running, task ID prefix, and completion/failure state

Authored-By: Jack Levy
2026-03-01 11:29:11 -05:00

69 lines
2.6 KiB
TypeScript

import { Clock } from "lucide-react";
import { BillAction } from "@/lib/types";
import { formatDate } from "@/lib/utils";
interface ActionTimelineProps {
actions: BillAction[];
latestActionDate?: string;
latestActionText?: string;
}
export function ActionTimeline({ actions, latestActionDate, latestActionText }: ActionTimelineProps) {
const hasActions = actions && actions.length > 0;
const hasFallback = !hasActions && latestActionText;
if (!hasActions && !hasFallback) {
return (
<div className="bg-card border border-border rounded-lg p-6">
<h2 className="font-semibold mb-3 flex items-center gap-2">
<Clock className="w-4 h-4" />
Action History
</h2>
<p className="text-sm text-muted-foreground italic">No actions recorded yet.</p>
</div>
);
}
return (
<div className="bg-card border border-border rounded-lg p-6">
<h2 className="font-semibold mb-4 flex items-center gap-2">
<Clock className="w-4 h-4" />
Action History
{hasActions && (
<span className="text-xs text-muted-foreground font-normal">({actions.length})</span>
)}
</h2>
<div className="relative">
<div className="absolute left-2 top-0 bottom-0 w-px bg-border" />
<ul className="space-y-4 pl-7">
{hasActions ? (
actions.map((action) => (
<li key={action.id} className="relative">
<div className="absolute -left-5 top-1.5 w-2 h-2 rounded-full bg-primary/60 border-2 border-background" />
<div className="text-xs text-muted-foreground mb-0.5">
{formatDate(action.action_date)}
{action.chamber && ` · ${action.chamber}`}
</div>
<p className="text-sm leading-snug">{action.action_text}</p>
</li>
))
) : (
<li className="relative">
<div className="absolute -left-5 top-1.5 w-2 h-2 rounded-full bg-muted-foreground/40 border-2 border-background" />
<div className="text-xs text-muted-foreground mb-0.5">
{formatDate(latestActionDate)}
<span className="ml-1.5 italic">· latest known action</span>
</div>
<p className="text-sm leading-snug">{latestActionText}</p>
<p className="text-xs text-muted-foreground mt-1 italic">
Full history loads in the background refresh to see all actions.
</p>
</li>
)}
</ul>
</div>
</div>
);
}