--- phase: 19-pipeline-crm-kanban plan: 01 status: complete completed_at: "2026-06-19" requirements_satisfied: - PIPE-01 - PIPE-02 commits: - 2c67e6f - 607c257 - 34be934 --- # Plan 19-01 Summary — LeadsKanbanBoard + LeadsViewToggle ## What Was Built Plan 19-01 aggiunge una vista Kanban stile Pipedrive alla pagina `/admin/leads`, affiancata alla tabella esistente tramite un toggle Lista/Kanban. ### Componenti creati / modificati | File | Tipo | Descrizione | |------|------|-------------| | `src/components/admin/leads/LeadsKanbanBoard.tsx` | Nuovo | Board Kanban con 6 colonne stage, drag-drop via @dnd-kit, ottimistic update | | `src/components/admin/leads/LeadsViewToggle.tsx` | Nuovo | Client wrapper con `useState<"list" \| "kanban">`, search integrata, pill toggle | | `src/app/admin/leads/LeadsSearch.tsx` | Modificato | Svuotato e ri-esporta `LeadsViewToggle as LeadsSearch` per retrocompatibilità | | `src/app/admin/leads/page.tsx` | Modificato | Ora renderizza `` invece di `` | ### Dettaglio implementazione **LeadsKanbanBoard.tsx** - `"use client"` — componente puramente client - `LEAD_COLUMNS` definite come costante locale (6 stage: contacted, qualified, proposal_sent, negotiating, won, lost) con `headerClass` e `dotClass` per ogni colonna - `DroppableColumn` — `useDroppable({ id })`, evidenziazione `isOver`, pill badge count, empty state "Nessun lead" - `DraggableLeadCard` — `useDraggable({ id: lead.id })`, opacity-30 in drag, mostra name / company / next_action - `LeadsKanbanBoard` (export) — `useState>` ottimistic, `PointerSensor distance:5` + `KeyboardSensor`, `handleDragEnd` con guard client-side su `over.id ∈ LEAD_COLUMNS`, `startTransition(async () => { await updateLeadField(leadId, "status", newStage); router.refresh(); })` - Layout: `overflow-x-auto` → `grid grid-cols-6 gap-3 min-w-[1080px]` - `DragOverlay dropAnimation={null}` con ghost card `rotate-1 border-2 border-[#1A463C] shadow-xl` **LeadsViewToggle.tsx** - `useState<"list" | "kanban">("list")` per il toggle - `useState("")` per la query di ricerca - `useMemo` per `filtered` — filtra su name / email / company / status / tags - Barra superiore: search input (max-w-sm, flex-1) + pill toggle (flex-shrink-0) su singola riga `flex justify-between items-center` - Pill toggle con classi `bg-[#f4f4f5] rounded-lg p-1`, active: `bg-white text-[#1A463C] shadow-sm` - Condizionale: `view === "list"` → `` | `view === "kanban"` → `` **LeadsSearch.tsx** (ri-esportazione) - Ridotto a una singola riga: `export { LeadsViewToggle as LeadsSearch } from "@/components/admin/leads/LeadsViewToggle"` - Garantisce zero import-break su eventuali riferimenti residui **page.tsx** - Import aggiornato: `LeadsViewToggle` da `@/components/admin/leads/LeadsViewToggle` - Render: `` ## Commits | Hash | Descrizione | |------|-------------| | `2c67e6f` | Task 1 — LeadsKanbanBoard.tsx con 6 colonne e drag-drop persistente | | `607c257` | Task 2 — LeadsViewToggle.tsx + re-export LeadsSearch | | `34be934` | Task 3 — page.tsx aggiornato + build check verde + fix overflow clipping | > Nota: il commit `34be934` include anche un fix minore all'overflow del dropdown in `LeadTable` (il clipping del `overflow-x-auto` del wrapper Kanban tagliava il menu a tendina delle colonne tabella in vista Lista). Fix non bloccante, risolto nella stessa sessione. ## Requirements Satisfied | Req | Descrizione | Verifica | |-----|-------------|---------| | PIPE-01 | Board Kanban 6 colonne con drag-drop che aggiorna `leads.status` | Drag tra colonne → `updateLeadField(id, "status", newStage)` → `router.refresh()` — persistente dopo reload | | PIPE-02 | Vinto/Perso come cambio-colonna manuale, nessun modale | Trascinare su colonna "won" o "lost" registra l'esito direttamente | ## Must-Haves Verificati | Truth | Stato | |-------|-------| | Board 6 colonne (contacted → qualified → proposal_sent → negotiating → won → lost) | ✅ | | Drag-drop aggiorna `leads.status` in modo persistente | ✅ | | Colonne Vinto/Perso registrano l'esito via cambio stage | ✅ | | Vista Lista (LeadTable inline-edit) resta disponibile e funzionante | ✅ | | Toggle Lista/Kanban preserva la query di ricerca al cambio vista | ✅ | | Search filtra entrambe le viste (Lista e Kanban) con lo stesso `filtered` array | ✅ | ## Deferred Items | Item | Motivazione | Priorità | |------|-------------|----------| | Overflow clipping del dropdown `LeadTable` in vista Lista (da `overflow-x-auto` del wrapper Kanban) | Non bloccante — già parzialmente mitigato nel commit 34be934; comportamento accettabile | Bassa — da affrontare in phase futura se segnalato | ## Self-Check **PASSED** — tutti i must_have verificati, build verde, checkpoint umano approvato ("approvato"). Durata esecuzione: ~1 sessione sincrona (2026-06-19).