Summary
Allow users to reorder Client sections in the sidebar via drag-and-drop. Order is persisted server-side.
Scope
- Add a
SortableContext for Client headers in the sidebar (separate from project sorting)
- Use
useSortable on Client header components
- On drag end, dispatch
client.reorder command with {clientId, newPosition}
- Server emits
client.reordered event, projector updates sort_order field
- "Unassigned" section is pinned to the bottom and not draggable
Technical notes
- The current dnd-kit setup uses
restrictToVerticalAxis and restrictToFirstScrollableAncestor modifiers — these work for Client reordering too
- Need to distinguish Client-header drags from Project-item drags. Use
data payload on useSortable to tag the drag type
- Consider adding a
DragOverlay for visual feedback (currently missing from the codebase)
- Optimistic UI: reorder locally on drag end, roll back if command fails
Key files to modify
apps/web/src/components/Sidebar.tsx — add Client-level SortableContext, distinguish drag types in onDragEnd
apps/web/src/store.ts — optimistic state update for client order
Dependencies
- F1 (Client entity with
sortOrder), F3 (sidebar hierarchy rendering)
Acceptance criteria
Summary
Allow users to reorder Client sections in the sidebar via drag-and-drop. Order is persisted server-side.
Scope
SortableContextfor Client headers in the sidebar (separate from project sorting)useSortableon Client header componentsclient.reordercommand with{clientId, newPosition}client.reorderedevent, projector updatessort_orderfieldTechnical notes
restrictToVerticalAxisandrestrictToFirstScrollableAncestormodifiers — these work for Client reordering toodatapayload onuseSortableto tag the drag typeDragOverlayfor visual feedback (currently missing from the codebase)Key files to modify
apps/web/src/components/Sidebar.tsx— add Client-levelSortableContext, distinguish drag types inonDragEndapps/web/src/store.ts— optimistic state update for client orderDependencies
sortOrder), F3 (sidebar hierarchy rendering)Acceptance criteria