8.5 KiB
phase: 10 plan: 02 subsystem: CRM Lead Management UI tags:
- lead-management
- admin-interface
- next-app-router
- shadcn-components
dependency_graph:
requires: [10-01]
provides: [10-03]
affects: [admin-dashboard]
tech_stack:
added:
- date-fns (date formatting with Italian locale)
- @radix-ui/react-dialog (dialog component primitive)
- @radix-ui/react-slot (slot composition primitive) patterns:
- Server components for data fetching (/admin/leads, /admin/leads/[id])
- Client components for interactive forms (LeadForm, LeadTable)
- React Hook Form + Zod validation for form handling
- Server actions for CRUD operations with path revalidation key_files: created:
- src/app/admin/leads/page.tsx
- src/app/admin/leads/[id]/page.tsx
- src/app/admin/leads/actions.ts
- src/components/admin/leads/LeadTable.tsx
- src/components/admin/leads/LeadForm.tsx
- src/components/admin/leads/LeadDetail.tsx
- src/components/ui/dialog.tsx
- src/components/ui/form.tsx modified:
- package.json (added date-fns, @radix-ui dependencies)
- package-lock.json decisions:
- Used React Hook Form + Zod for consistent form validation pattern
- Dialog modals for create/edit flows (non-destructive modal UX)
- Separate LeadTable and LeadDetail components for reusability
- Server actions with revalidatePath for automatic UI sync after mutations
- Stage colors (blue→purple→amber→orange→green→red) for visual pipeline clarity metrics: duration: 45 minutes completed_date: 2026-06-11 tasks_completed: 1 files_created: 8 files_modified: 2 commits: 1
Phase 10 Plan 2: Lead Management UI Summary
Wave 2 Objective: Implement the admin-facing lead management interface with list, detail, and form components. Enable admins to view leads, create new leads, edit existing leads, and track activity history.
Output: Complete CRUD interface for lead management at /admin/leads
Completed Tasks
Task 1: Lead List Page and LeadTable Component ✓
What was built:
/admin/leads/page.tsx— Server component with title, "Create Lead" button, and LeadTableLeadTable.tsx— Client component rendering all leads in a table with:- Columns: Name, Email, Company, Status (badge), Last Contact Date, Next Action, Detail Link
- Status badge colors: blue (contacted), purple (qualified), amber (proposal_sent), orange (negotiating), green (won), red (lost)
- Table sorted by last_contact_date descending (most recent first)
- Links to detail pages at
/admin/leads/[id] - Empty state message when no leads exist
Key features:
- Uses
getAllLeads()from lead-service.ts (created in Plan 1) - formatDistanceToNow() for relative date display (Italian locale)
- Hover underline on lead names for better link affordance
- Table body with proper semantic HTML structure
Task 2: Lead Detail Page with Activity Log ✓
What was built:
/admin/leads/[id]/page.tsx— Server component that fetches lead + activity log + remindersLeadDetail.tsx— Client component displaying:- Header: Lead name, company, Edit button, and action buttons
- Profile Card: Status badge, email, phone, last contact, next action
- Reminders Card: Upcoming reminders with due dates (empty state if none)
- Notes Card: Free-form notes section
- Activity Log: Reverse chronological list with:
- Type icons (📞 📧 📅 📝)
- Activity type, timestamp (relative), notes, duration (if recorded)
- Left border styling for visual grouping
Key features:
- Uses
getLeadById(),getActivityLog(),getUpcomingReminders()from lead-service.ts - 3-column grid layout (responsive: 1 column on mobile, 3 on desktop)
- Uses Card component for semantic grouping
- Italian locale support via date-fns
itlocale
Task 3: Lead Form Component and Server Actions ✓
What was built:
-
LeadForm.tsx— Two modal components:- CreateLeadModal: Form in a dialog to create new leads
- Fields: Name (required), Email (optional), Phone (optional), Company (optional), Status (required, default "contacted"), Notes (optional)
- Trigger: "+ Nuovo Lead" button on list page
- On submit: calls
createLead()server action, closes dialog on success
- EditLeadModal: Form in a dialog to edit existing leads
- Same fields as create, pre-populated with current lead values
- Trigger: "Modifica" button on detail page
- On submit: calls
updateLead()server action, closes dialog on success
- CreateLeadModal: Form in a dialog to create new leads
-
actions.ts— Server actions for mutations:- createLead(): Validates via createLeadSchema, inserts into DB, returns lead with ID
- updateLead(): Validates via updateLeadSchema, updates only provided fields, maintains updated_at
- deleteLead(): Deletes lead from DB (prepared for future use)
- All actions revalidate
/admin/leadsand/admin/leads/[id]paths for automatic UI refresh
Key features:
- React Hook Form + Zod for consistent validation
- Error handling with user-friendly Italian error messages
- Form submission state management (isSubmitting flag)
- Revalidation ensures UI stays in sync with DB
- Both modals are dialog-based for non-destructive UX
Supporting Components ✓
UI Components created:
dialog.tsx— Radix UI dialog primitive wrapper with shadcn stylingform.tsx— React Hook Form + Zod integration with FormField, FormItem, FormLabel, FormControl, FormMessage exports
Dependencies installed:
date-fns— For date formatting and relative time display (with Italian locale)@radix-ui/react-dialog— Dialog modal primitive@radix-ui/react-slot— Slot composition primitive for form controls
Build & Verification
Build Status: ✓ PASSED
npm run build 2>&1
✓ Compiled successfully in 2.8s
✓ Finished TypeScript in 3.1s
✓ Generating static pages (11/11)
Routes Generated:
├ ƒ /admin/leads— List page (server component)├ ƒ /admin/leads/[id]— Detail page (server component)
Type Checking: ✓ All TypeScript errors resolved
- Fixed form resolver type compatibility (createLeadSchema vs updateLeadSchema)
- Corrected Slot type reference in FormControl component
Test Plan
The following manual tests should be performed:
-
List Page Load
- Navigate to
/admin/leads - Verify table renders with all existing leads
- Check status badge colors match pipeline stages
- Click "Dettagli" link → navigates to detail page
- Navigate to
-
Create Lead Flow
- Click "+ Nuovo Lead" button
- Modal opens with empty form
- Fill fields (name required, others optional)
- Submit → lead appears in table
- Verify list revalidates automatically
-
Edit Lead Flow
- Navigate to any lead detail page
- Click "Modifica" button
- Modal opens with pre-filled values
- Update a field (e.g., company name)
- Submit → detail page updates automatically
-
Activity Log Display
- View lead detail page with existing activities
- Verify activity type icons display correctly
- Verify relative dates show in Italian (e.g., "1 giorno fa")
- Verify duration_minutes displays if present
-
Form Validation
- Try to create lead without name → error displays
- Try invalid email → error displays
- Optional fields can be left blank → no error
Deviations from Plan
None — plan executed exactly as written. All components follow established patterns from Phase 9 (Quote Builder).
Known Stubs
No stubs introduced. All components have complete implementations:
- LeadTable renders actual data from getAllLeads()
- LeadDetail shows real activity log and reminders
- Forms integrate with database via server actions
Threat Surface Scan
No new security-relevant surfaces introduced beyond Plan 1:
- Form inputs sanitized by React (auto-escaped)
- Server actions validate via Zod before DB insert
- No new API endpoints created
- Admin-only routes protected by Auth.js middleware (verified in prior phases)
Self-Check: PASSED
- ✓ src/app/admin/leads/page.tsx exists (list page)
- ✓ src/app/admin/leads/[id]/page.tsx exists (detail page)
- ✓ src/components/admin/leads/LeadTable.tsx exists
- ✓ src/components/admin/leads/LeadForm.tsx exists
- ✓ src/components/admin/leads/LeadDetail.tsx exists
- ✓ src/app/admin/leads/actions.ts exists (server actions)
- ✓ src/components/ui/dialog.tsx exists
- ✓ src/components/ui/form.tsx exists
- ✓ Commit
2d9cf1aexists with all 10 files - ✓ npm run build passes with zero errors
- ✓ Routes /admin/leads and /admin/leads/[id] in output