Price Book
Price Book Components During Creation
Add inventory components while creating price book items — required vs optional parts of bundled services.
8 min readPrice Book Inventory Components During Creation
Summary
Problem: Previously, when creating a new price book item, users had to save the item first before they could add inventory components. This required a two-step process: create the item, then go back to add components.
Solution: Users can now select inventory components while creating a price book item. All components are saved together when the price book item is created, streamlining the workflow.
Changes Made
Frontend (apps/web/src/pages/priceBook/PriceBook.tsx)
1. Added New Imports
import { InventoryItemSelector, type SelectedInventoryItem } from '../../components/InventoryItemSelector'
2. Added State Management
const [pendingComponents, setPendingComponents] = useState<SelectedInventoryItem[]>([])
const [showComponentSelector, setShowComponentSelector] = useState(false)
pendingComponents: Stores temporarily selected inventory items before the price book item is createdshowComponentSelector: Controls the visibility of the inventory item selector modal
3. Updated Event Handlers
handleAdd: Resets pending components when opening the create modal
const handleAdd = () => {
setEditingItem(null)
setPendingComponents([]) // Clear pending components
// ... rest of the code
}
handleModalCancel: Clears pending components when closing the modal
const handleModalCancel = () => {
// ... existing code
setPendingComponents([]) // Clear pending components
}
handleModalOk: Saves pending components after creating the price book item
if (editingItem) {
// Update existing item
} else {
const result = await createPriceBookItem(formData).unwrap()
const newPriceBookItemId = result.data?.id
// If there are pending components, create them now
if (newPriceBookItemId && pendingComponents.length > 0) {
for (const component of pendingComponents) {
await apiClient.post(`/api/price-book/${newPriceBookItemId}/components`, {
inventoryItemId: component.id,
quantity: component.quantity,
unitCost: component.unitCost,
isOptional: component.isOptional || false,
description: component.description,
sortOrder: successCount
})
}
}
}
4. Updated "Inventory Components" Tab
Before: Showed a message "Components will be available after saving"
After: Shows a full interface for adding and managing components:
- Alert explaining components can be added before saving
- "Add Components" button to open inventory selector
- Table showing selected components with:
- Item name and SKU
- Editable quantity (inline editing)
- Unit cost
- Total cost calculation
- Optional/Required tag
- Delete button to remove individual components
- Empty state when no components are added
5. Added Inventory Item Selector Modal
<InventoryItemSelector
visible={showComponentSelector}
onClose={() => setShowComponentSelector(false)}
onSelect={(selectedItems) => {
// Merge with existing pending components, avoiding duplicates
const existingIds = new Set(pendingComponents.map(c => c.id))
const newComponents = selectedItems.filter(item => !existingIds.has(item.id))
setPendingComponents([...pendingComponents, ...newComponents])
setShowComponentSelector(false)
}}
selectedItemIds={pendingComponents.map(c => c.id)}
title="Add Inventory Components"
showQuantityInput={true}
showCostOverride={true}
showOptionalFlag={true}
multiSelect={true}
/>
User Experience
New Workflow (Streamlined)
- Click "Add Item" to create a new price book item
- Fill in "Basic Information" tab (name, price, etc.)
- Switch to "Inventory Components" tab
- Click "Add Components" button
- Select inventory items from the modal
- Set quantities
- Override costs if needed
- Mark as optional/required
- Review selected components in the table
- Edit quantities inline
- Remove unwanted components
- Click "OK" to save
- ✨ Price book item AND all components are saved together!
Old Workflow (Required Two Steps)
- Create price book item
- Save it
- Reopen the item
- Go to Inventory Components tab
- Add components
- Save again
Features
Component Management During Creation
- ✅ Add Multiple Components: Select multiple inventory items at once
- ✅ Set Quantities: Define quantity for each component
- ✅ Cost Override: Override default inventory cost if needed
- ✅ Optional/Required: Mark components as optional or required
- ✅ Edit Before Saving: Modify quantities or remove components before creating the item
- ✅ Visual Feedback: See total cost calculations in real-time
- ✅ Duplicate Prevention: Can't add the same inventory item twice
Table Features
- Inline Quantity Editing: Change quantities directly in the table
- Cost Calculation: Automatic total cost = unit cost × quantity
- Remove Components: Delete button for each component
- Component Counter: Shows count of selected components
Success Messages
- If components are added:
"Price book item created with X component(s)!" - If no components:
"Price book item created successfully"
API Integration
Create Price Book Item
POST /api/price-book
{
name: string
itemType: string
unitPrice: number
// ... other fields
}
Add Components (After Creation)
POST /api/price-book/:priceBookItemId/components
{
inventoryItemId: string
quantity: number
unitCost?: number
isOptional: boolean
description?: string
sortOrder: number
}
Note: Components are added sequentially after the price book item is created. If any component fails, others will still be added (graceful degradation).
Benefits
- ⚡ Faster Workflow: Save time by not having to reopen items to add components
- 📦 Single Transaction: All data saved together
- ✨ Better UX: More intuitive - configure everything before saving
- 🔄 Consistent with Other Forms: Matches pattern used in job creation, estimates, etc.
- 🛡️ Data Integrity: Components are added immediately after item creation
- 👀 Preview: See exactly what components will be added before committing
Edge Cases Handled
- ✅ No inventory items: Tab is disabled if no inventory exists
- ✅ Duplicate prevention: Can't add the same item twice
- ✅ Modal cancellation: Pending components are cleared if modal is cancelled
- ✅ Component creation failure: Each component creation is wrapped in try-catch
- ✅ Editing existing items: Still uses the original
PriceBookComponentscomponent
Files Modified
apps/web/src/pages/priceBook/PriceBook.tsx- Added imports for
InventoryItemSelector - Added state for pending components
- Updated event handlers
- Completely redesigned "Inventory Components" tab for new items
- Added inventory selector modal
- Added imports for
Testing Checklist
- Create a new price book item without components (works as before)
- Create a new price book item with components
- Add multiple components at once
- Edit component quantities before saving
- Remove a component before saving
- Cancel the modal and verify components are cleared
- Verify components are saved with correct data
- Edit an existing price book item (should work as before)
- Try adding duplicate components (should be prevented)
- Verify success messages display correctly
- Check that tab is disabled when no inventory items exist
Future Enhancements
- Add visual cost summary in the components tab (like in the PriceBookComponents view)
- Allow bulk editing of component quantities
- Drag-and-drop reordering of components before saving
- Import components from another price book item
- Template support for common component combinations
Created: October 18, 2025
Status: ✅ Complete - Ready for Testing
Status: ✅ Complete - Ready for Testing