# CRM Step 05 — Frontend: Products Module ## Context Read `.claude/crm-build-plan.md` for full context and IMPORTANT NOTES. Backend Steps 01–04 must be complete and running. ## Task Build the Products section of the CRM frontend. ## Files to create ### `frontend/src/crm/products/ProductList.jsx` - Fetch `GET /api/crm/products` with auth headers - Show a table/list: Name, SKU, Category, Price, Stock (available), Active badge - Search input (client-side filter on name/sku) - Filter dropdown for category - "New Product" button → navigate to `/crm/products/new` - Row click → navigate to `/crm/products/:id` ### `frontend/src/crm/products/ProductForm.jsx` Used for both create and edit. Receives `productId` prop (null = create mode). Fields: - name (required), sku, category (dropdown from enum), description (textarea) - price (number), currency (default EUR) - Costs section (collapsible): pcb, components, enclosure, labor_hours, labor_rate, shipping_in — show computed total - Stock section: on_hand, reserved — show available = on_hand - reserved (readonly) - nextcloud_folder, linked_device_type, active (toggle) - Save / Cancel buttons - In edit mode: show Delete button with confirmation On save: POST `/api/crm/products` or PUT `/api/crm/products/:id` On delete: DELETE `/api/crm/products/:id` then navigate back to list ### `frontend/src/crm/products/index.js` Export both components. ## Routing In `frontend/src/App.jsx` add: ```jsx } /> } /> } /> ``` ## Sidebar In `frontend/src/layout/Sidebar.jsx` add a "CRM" section with: - Products → `/crm/products` (Customers and Orders will be added in later steps) ## Notes - Use existing UI patterns: SectionCard wrapper, inline styles for layout grid - Follow the same auth header pattern as other frontend modules (getAuthHeaders from `../api/auth` or equivalent) - Currency is always EUR for now — no need for a selector - Computed costs total = pcb + components + enclosure + (labor_hours * labor_rate) + shipping_in, shown live as user types - Category values: controller, striker, clock, part, repair_service — display as human-readable labels