`. The `isActive={false}` prop hides drag handles. Rank badges remain visible per user decision.
+
+ - When `candidateViewMode === "grid"` AND candidates exist:
+ - Render the existing `
` with `CandidateCard` components.
+ - Pass `rank={index + 1}` to each CandidateCard so rank badges appear in grid view too.
+ - Both active and resolved threads use static grid (no drag in grid view per user decision).
+
+ - **Important framer-motion detail**: `Reorder.Group` `values` must be the same array reference as what you iterate. Use `displayItems` for both `values` and `.map()`. The `Reorder.Item` `value` must be the same object reference (not a copy). Since we use the full candidate object, `value={candidate}` where candidate comes from `displayItems.map(...)`.
+
+ - **Empty state**: Keep the existing empty state rendering for both views.
+
+ - **useEffect to clear tempItems**: When `thread.candidates` changes (new data from server), clear tempItems:
+ ```typescript
+ useEffect(() => {
+ setTempItems(null);
+ }, [thread?.candidates]);
+ ```
+ This ensures that when React Query refetches, tempItems is cleared and we render fresh server data.
+
+
+ cd /home/jlmak/Projects/jlmak/GearBox && bun run lint 2>&1 | head -30
+
+
Thread detail page renders list/grid toggle. List view has drag-to-reorder via Reorder.Group with tempItems flicker prevention. Grid view shows rank badges. Resolved threads show static list/grid with rank badges but no drag handles. Lint passes.
+
+
+
+ Task 3: Verify drag-to-reorder ranking experience
+ none
+
+ Human verifies the complete drag-to-reorder candidate ranking with list/grid view toggle, rank badges (gold/silver/bronze), auto-save persistence, and resolved thread guard.
+
+ Complete drag-to-reorder candidate ranking with list/grid view toggle, rank badges (gold/silver/bronze), auto-save persistence, and resolved thread guard.
+
+ 1. Start dev servers: `bun run dev:client` and `bun run dev:server`
+ 2. Navigate to an existing active thread with 3+ candidates (or create one)
+ 3. Verify list view is the default (vertical stack of horizontal cards)
+ 4. Verify drag handles (grip icon) appear on the left of each card
+ 5. Drag a candidate to a new position — verify it moves smoothly with gap animation
+ 6. Release — verify the new order persists (refresh the page to confirm)
+ 7. Verify the top 3 candidates show gold, silver, bronze medal icons before their names
+ 8. Toggle to grid view — verify rank badges also appear on grid cards
+ 9. Toggle back to list view — verify drag still works
+ 10. Navigate to a resolved thread — verify NO drag handles, but rank badges ARE visible
+ 11. Verify candidates on resolved thread render in their ranked order (static)
+
+ Human confirms all 11 verification steps pass
+ All ranking features verified: drag reorder works, persists, shows rank badges in both views, disabled on resolved threads
+ Type "approved" or describe any issues
+
+
+
+
+
+```bash
+# Full test suite green
+bun test
+
+# Verify all key files exist
+ls src/client/components/CandidateListItem.tsx
+grep -n "useReorderCandidates" src/client/hooks/useCandidates.ts
+grep -n "candidateViewMode" src/client/stores/uiStore.ts
+grep -n "Reorder.Group" src/client/routes/threads/\$threadId.tsx
+grep -n "RankBadge" src/client/components/CandidateCard.tsx
+
+# Lint clean
+bun run lint
+```
+
+
+
+- List view shows horizontal cards with drag handles on active threads
+- Drag-to-reorder works via framer-motion Reorder.Group with grip handle
+- Order persists after page refresh via PATCH /api/threads/:id/candidates/reorder
+- tempItems pattern prevents React Query flicker
+- Top 3 candidates display gold (#D4AF37), silver (#C0C0C0), bronze (#CD7F32) medal badges
+- Rank badges visible in both list and grid views
+- Grid/list toggle works with list as default
+- Resolved threads: no drag handles, rank badges visible, static order
+- All tests pass, lint clean
+
+
+