import { Reorder } from "framer-motion";
import { useRef } from "react";
import { useFormatters } from "../hooks/useFormatters";
import type { CandidateDelta } from "../hooks/useImpactDeltas";
import { LucideIcon } from "../lib/iconData";
import { useUIStore } from "../stores/uiStore";
import { ImpactDeltaBadge } from "./ImpactDeltaBadge";
import { StatusBadge } from "./StatusBadge";
interface CandidateWithCategory {
id: number;
threadId: number;
name: string;
weightGrams: number | null;
priceCents: number | null;
categoryId: number;
notes: string | null;
productUrl: string | null;
imageFilename: string | null;
status: "researching" | "ordered" | "arrived";
pros: string | null;
cons: string | null;
createdAt: string;
updatedAt: string;
categoryName: string;
categoryIcon: string;
}
interface CandidateListItemProps {
candidate: CandidateWithCategory;
rank: number;
isActive: boolean;
onStatusChange: (status: "researching" | "ordered" | "arrived") => void;
delta?: CandidateDelta;
onDragEnd?: () => void;
}
const RANK_COLORS = ["#D4AF37", "#C0C0C0", "#CD7F32"]; // gold, silver, bronze
export function RankBadge({ rank }: { rank: number }) {
if (rank > 3) return null;
return (
);
}
export function CandidateListItem({
candidate,
rank,
isActive,
onStatusChange,
delta,
onDragEnd,
}: CandidateListItemProps) {
const isDragging = useRef(false);
const { weight, price } = useFormatters();
const openCandidateEditPanel = useUIStore((s) => s.openCandidateEditPanel);
const openConfirmDeleteCandidate = useUIStore(
(s) => s.openConfirmDeleteCandidate,
);
const openResolveDialog = useUIStore((s) => s.openResolveDialog);
const openExternalLink = useUIStore((s) => s.openExternalLink);
const sharedClassName =
"flex items-center gap-3 bg-white rounded-xl border border-gray-100 p-3 hover:border-gray-200 hover:shadow-sm group cursor-default";
const innerContent = (
<>
{/* Drag handle indicator */}
{isActive && (
)}
{/* Rank badge */}
{/* Image thumbnail */}
{candidate.imageFilename ? (

) : (
)}
{/* Name + badges */}
{/* Action buttons (hover-reveal) */}
{isActive && (
)}
{candidate.productUrl && (
)}
>
);
// Reorder.Item requires a Reorder.Group parent — only use it in active threads
if (isActive) {
return (
{
isDragging.current = true;
}}
onDragEnd={() => {
setTimeout(() => {
isDragging.current = false;
}, 0);
onDragEnd?.();
}}
whileDrag={{ cursor: "grabbing" }}
style={{ marginBottom: 8, cursor: "grab" }}
className={sharedClassName}
>
{innerContent}
);
}
return {innerContent}
;
}