feat(08-01): create StatusBadge component and wire into CandidateCard

- StatusBadge: clickable pill badge with popup menu (researching/ordered/arrived)
- Muted gray styling, LucideIcon per status, click-outside dismiss, Escape key support
- CandidateCard: status + onStatusChange props, StatusBadge in pill row after category
- Thread detail page: passes candidate.status and useUpdateCandidate for onStatusChange
- Fix Biome formatting for candidateStatusSchema enum

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 14:12:02 +01:00
parent 5f89acd503
commit 25956ed3ee
4 changed files with 123 additions and 1 deletions

View File

@@ -1,5 +1,6 @@
import { createFileRoute, Link } from "@tanstack/react-router";
import { CandidateCard } from "../../components/CandidateCard";
import { useUpdateCandidate } from "../../hooks/useCandidates";
import { useThread } from "../../hooks/useThreads";
import { LucideIcon } from "../../lib/iconData";
import { useUIStore } from "../../stores/uiStore";
@@ -13,6 +14,7 @@ function ThreadDetailPage() {
const threadId = Number(threadIdParam);
const { data: thread, isLoading, isError } = useThread(threadId);
const openCandidateAddPanel = useUIStore((s) => s.openCandidateAddPanel);
const updateCandidate = useUpdateCandidate(threadId);
if (isLoading) {
return (
@@ -144,6 +146,13 @@ function ThreadDetailPage() {
productUrl={candidate.productUrl}
threadId={threadId}
isActive={isActive}
status={candidate.status}
onStatusChange={(newStatus) =>
updateCandidate.mutate({
candidateId: candidate.id,
status: newStatus,
})
}
/>
))}
</div>