3.7 KiB
3.7 KiB
CRM Step 06 — Frontend: Customers List + Detail Page
Context
Read .claude/crm-build-plan.md for full context, data models, and IMPORTANT NOTES.
Backend Steps 01–04 and Frontend Step 05 must be complete.
Task
Build the Customers section — the core of the CRM.
Files to create
frontend/src/crm/customers/CustomerList.jsx
- Fetch
GET /api/crm/customers(query: search, tag) - Show cards or table rows: Name, Organization, Location, Tags, primary contact
- Search input → query param
search - "New Customer" button →
/crm/customers/new - Row/card click →
/crm/customers/:id
frontend/src/crm/customers/CustomerForm.jsx
Create/edit form. Receives customerId prop (null = create).
Sections:
- Basic Info — name, organization, language, tags (pill input), nextcloud_folder
- Location — city, country, region
- Contacts — dynamic list of
{ type, label, value, primary }entries. Add/remove rows. Radio to set primary per type group. - Notes — dynamic list of
{ text, by, at }. Add new note button. Existing notes shown as read-only with author/date.byauto-filled from current user name. - Owned Items — dynamic list with type selector:
console_device: device_id text input + labelproduct: product selector (fetch/api/crm/productsfor dropdown) + quantity + serial_numbers (comma-separated input)freetext: description + serial_number + notes Add/remove rows.
- Linked App Accounts — list of Firebase UIDs (simple text inputs, add/remove). Label: "Linked App User IDs"
Save: POST or PUT. Delete with confirmation.
frontend/src/crm/customers/CustomerDetail.jsx
The main customer page. Fetches customer by ID. Tab layout:
Tab 1: Overview
- Show all info from CustomerForm fields in read-only view
- "Edit" button → opens CustomerForm in a modal or navigates to edit route
Tab 2: Orders
- Fetch
GET /api/crm/orders?customer_id=:id - List orders: order_number, status badge, total_price, date
- "New Order" button → navigate to
/crm/orders/new?customer_id=:id - Row click →
/crm/orders/:id
Tab 3: Comms
- Fetch
GET /api/crm/comms?customer_id=:id - Timeline view sorted by occurred_at descending
- Each entry shows: type icon, direction indicator, subject/body preview, date
- "Log Entry" button → inline form to create a new comms entry (type, direction, subject, body, occurred_at)
Tab 4: Media
- Fetch
GET /api/crm/media?customer_id=:id - Grid of files: filename, direction badge (Received/Sent/Internal), date
- "Add Media Record" button → form with filename, nextcloud_path, direction, tags (manual entry for now — Nextcloud integration comes in Step 9)
Tab 5: Devices (read-only summary)
- Display
owned_itemsgrouped by type - For console_device items: link to
/devices/:device_idin a new tab
frontend/src/crm/customers/index.js
Export all components.
Routing in frontend/src/App.jsx
<Route path="/crm/customers" element={<CustomerList />} />
<Route path="/crm/customers/new" element={<CustomerForm />} />
<Route path="/crm/customers/:id" element={<CustomerDetail />} />
<Route path="/crm/customers/:id/edit" element={<CustomerForm />} />
Sidebar update
Add to CRM section:
- Customers →
/crm/customers
Notes
- ALL hooks in CustomerDetail must be before any early returns (loading/error states)
- Tag input: comma or enter to add, click pill to remove
- Contact type icons: use simple text labels or emoji (📧 📞 💬) — keep it simple
- Comms type icons: simple colored badges per type (email=blue, whatsapp=green, call=yellow, note=grey)
- No file upload UI yet in Media tab — just nextcloud_path text field for now (Step 9 adds real upload)