bac757a987
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
96 lines
4.9 KiB
Markdown
96 lines
4.9 KiB
Markdown
---
|
|
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 `<LeadsViewToggle>` invece di `<LeadsSearch>` |
|
|
|
|
### 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<Record<string, LeadStage>>` 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"` → `<LeadTable>` | `view === "kanban"` → `<LeadsKanbanBoard>`
|
|
|
|
**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: `<LeadsViewToggle leads={leads} options={options} />`
|
|
|
|
## 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).
|