"use client"; import { use, useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import Link from "next/link"; import { ArrowLeft, Check, Copy, Globe, Lock, Minus, Search, X } from "lucide-react"; import { collectionsAPI, billsAPI } from "@/lib/api"; import type { Bill } from "@/lib/types"; import { billLabel, formatDate } from "@/lib/utils"; export default function CollectionDetailPage({ params }: { params: Promise<{ id: string }> }) { const { id } = use(params); const collectionId = parseInt(id, 10); const qc = useQueryClient(); const [editingName, setEditingName] = useState(false); const [nameInput, setNameInput] = useState(""); const [copied, setCopied] = useState(false); const [searchQ, setSearchQ] = useState(""); const [searchResults, setSearchResults] = useState([]); const [searching, setSearching] = useState(false); const { data: collection, isLoading } = useQuery({ queryKey: ["collection", collectionId], queryFn: () => collectionsAPI.get(collectionId), }); const updateMutation = useMutation({ mutationFn: (data: { name?: string; is_public?: boolean }) => collectionsAPI.update(collectionId, data), onSuccess: () => { qc.invalidateQueries({ queryKey: ["collection", collectionId] }); qc.invalidateQueries({ queryKey: ["collections"] }); setEditingName(false); }, }); const addBillMutation = useMutation({ mutationFn: (bill_id: string) => collectionsAPI.addBill(collectionId, bill_id), onSuccess: () => { qc.invalidateQueries({ queryKey: ["collection", collectionId] }); qc.invalidateQueries({ queryKey: ["collections"] }); }, }); const removeBillMutation = useMutation({ mutationFn: (bill_id: string) => collectionsAPI.removeBill(collectionId, bill_id), onSuccess: () => { qc.invalidateQueries({ queryKey: ["collection", collectionId] }); qc.invalidateQueries({ queryKey: ["collections"] }); }, }); async function handleSearch(q: string) { setSearchQ(q); if (!q.trim()) { setSearchResults([]); return; } setSearching(true); try { const res = await billsAPI.list({ q, per_page: 8 }); setSearchResults(res.items); } finally { setSearching(false); } } function copyShareLink() { if (!collection) return; navigator.clipboard.writeText(`${window.location.origin}/share/collection/${collection.share_token}`); setCopied(true); setTimeout(() => setCopied(false), 2000); } function startRename() { setNameInput(collection?.name ?? ""); setEditingName(true); } function submitRename(e: React.FormEvent) { e.preventDefault(); const name = nameInput.trim(); if (!name || name === collection?.name) { setEditingName(false); return; } updateMutation.mutate({ name }); } if (isLoading) { return
Loading…
; } if (!collection) { return (

Collection not found.

← Back to collections
); } const collectionBillIds = new Set(collection.bills.map((b) => b.bill_id)); return (
{/* Header */}
{editingName ? (
setNameInput(e.target.value)} maxLength={100} autoFocus className="flex-1 px-2 py-1 text-lg font-bold bg-background border-b-2 border-primary focus:outline-none" />
) : ( )}
{/* Public/private toggle */} {/* Copy share link */} {collection.bill_count} {collection.bill_count === 1 ? "bill" : "bills"}
{/* Add bills search */}
handleSearch(e.target.value)} placeholder="Search to add bills…" className="flex-1 text-sm bg-transparent focus:outline-none" /> {searching && Searching…}
{searchResults.length > 0 && searchQ && (
{searchResults.map((bill) => { const inCollection = collectionBillIds.has(bill.bill_id); return ( ); })}
)}
{/* Bill list */} {collection.bills.length === 0 ? (

No bills yet — search to add some.

) : (
{collection.bills.map((bill) => (
{billLabel(bill.bill_type, bill.bill_number)} {bill.short_title || bill.title || "Untitled"}
{bill.latest_action_date && (

Latest action: {formatDate(bill.latest_action_date)}

)}
))}
)}
); }