import { createFileRoute, Link } from "@tanstack/react-router"; import { Reorder } from "framer-motion"; import { useEffect, useState } from "react"; import { CandidateCard } from "../../components/CandidateCard"; import { CandidateListItem } from "../../components/CandidateListItem"; import { useReorderCandidates, useUpdateCandidate, } from "../../hooks/useCandidates"; import { useThread } from "../../hooks/useThreads"; import { LucideIcon } from "../../lib/iconData"; import { useUIStore } from "../../stores/uiStore"; export const Route = createFileRoute("/threads/$threadId")({ component: ThreadDetailPage, }); function ThreadDetailPage() { const { threadId: threadIdParam } = Route.useParams(); const threadId = Number(threadIdParam); const { data: thread, isLoading, isError } = useThread(threadId); const openCandidateAddPanel = useUIStore((s) => s.openCandidateAddPanel); const candidateViewMode = useUIStore((s) => s.candidateViewMode); const setCandidateViewMode = useUIStore((s) => s.setCandidateViewMode); const updateCandidate = useUpdateCandidate(threadId); const reorderMutation = useReorderCandidates(threadId); const [tempItems, setTempItems] = useState( null, ); // Clear tempItems when server data changes (biome-ignore: thread?.candidates is intentional dep) // biome-ignore lint/correctness/useExhaustiveDependencies: thread?.candidates is the intended trigger useEffect(() => { setTempItems(null); }, [thread?.candidates]); if (isLoading) { return (
{[1, 2, 3].map((i) => (
))}
); } if (isError || !thread) { return (

Thread not found

Back to planning
); } const isActive = thread.status === "active"; const winningCandidate = thread.resolvedCandidateId ? thread.candidates.find((c) => c.id === thread.resolvedCandidateId) : null; const displayItems = tempItems ?? thread.candidates; function handleDragEnd() { if (!tempItems) return; reorderMutation.mutate( { orderedIds: tempItems.map((c) => c.id) }, { onSettled: () => setTempItems(null) }, ); } return (
{/* Header */}
← Back to planning

{thread.name}

{isActive ? "Active" : "Resolved"}
{/* Resolution banner */} {!isActive && winningCandidate && (

{winningCandidate.name} was picked as the winner and added to your collection.

)} {/* Toolbar: Add candidate + view toggle */}
{isActive && ( )} {thread.candidates.length > 0 && (
)}
{/* Candidates */} {thread.candidates.length === 0 ? (

No candidates yet

Add your first candidate to start comparing.

) : candidateViewMode === "list" ? ( isActive ? ( {displayItems.map((candidate, index) => ( updateCandidate.mutate({ candidateId: candidate.id, status: newStatus, }) } /> ))} ) : (
{displayItems.map((candidate, index) => ( updateCandidate.mutate({ candidateId: candidate.id, status: newStatus, }) } /> ))}
) ) : (
{thread.candidates.map((candidate, index) => ( updateCandidate.mutate({ candidateId: candidate.id, status: newStatus, }) } pros={candidate.pros} cons={candidate.cons} rank={index + 1} /> ))}
)}
); }