feat: material override in new product order wizard (Step 3)
- Dropdown in Step 3 review to set a single material override for all lines - Override is passed to each OrderLine.material_override at creation time - Amber background when override is active - Library materials loaded on Step 3 entry Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,8 @@ import { listOutputTypes } from '../api/outputTypes'
|
||||
import { createOrder } from '../api/orders'
|
||||
import { estimatePrice } from '../api/pricing'
|
||||
import { listGlobalRenderPositions } from '../api/renderPositions'
|
||||
import { listMaterials } from '../api/materials'
|
||||
import type { Material } from '../api/materials'
|
||||
import type { Product, RenderPosition } from '../api/products'
|
||||
import type { GlobalRenderPosition } from '../api/renderPositions'
|
||||
import type { OutputType } from '../api/outputTypes'
|
||||
@@ -47,6 +49,7 @@ export default function NewProductOrderPage() {
|
||||
const [positionSelections, setPositionSelections] = useState<PositionSelections>({})
|
||||
const [globalPositionSelections, setGlobalPositionSelections] = useState<GlobalPositionSelections>({})
|
||||
const [notes, setNotes] = useState('')
|
||||
const [materialOverride, setMaterialOverride] = useState<string>('')
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
|
||||
// ---- Step 1: load products with STEP files ----
|
||||
@@ -72,6 +75,13 @@ export default function NewProductOrderPage() {
|
||||
queryFn: listGlobalRenderPositions,
|
||||
})
|
||||
|
||||
const { data: allMaterials } = useQuery({
|
||||
queryKey: ['materials'],
|
||||
queryFn: listMaterials,
|
||||
enabled: step >= 3,
|
||||
})
|
||||
const libMaterials = (allMaterials ?? []).filter((m: Material) => m.schaeffler_code !== null).sort((a: Material, b: Material) => a.name.localeCompare(b.name))
|
||||
|
||||
function initPositionsForProduct(product: Product, globals: GlobalRenderPosition[] = []) {
|
||||
// Pre-select all per-product positions (if any)
|
||||
if ((product.render_positions?.length ?? 0) > 0) {
|
||||
@@ -378,6 +388,7 @@ export default function NewProductOrderPage() {
|
||||
output_type_id: l.outputType.id,
|
||||
render_position_id: l.position?.id ?? null,
|
||||
global_render_position_id: l.globalPosition?.id ?? null,
|
||||
material_override: materialOverride || null,
|
||||
})),
|
||||
})
|
||||
toast.success(`Draft order ${result.order_number} created — review and submit`)
|
||||
@@ -823,6 +834,27 @@ export default function NewProductOrderPage() {
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Material Override */}
|
||||
<div className="card p-4 mb-4">
|
||||
<label className="block text-sm font-medium text-content-secondary mb-1">
|
||||
Material Override (optional)
|
||||
</label>
|
||||
<p className="text-xs text-content-muted mb-2">
|
||||
Apply a single material to all parts of all products in this order. Leave empty to use each product's own materials.
|
||||
</p>
|
||||
<select
|
||||
value={materialOverride}
|
||||
onChange={(e) => setMaterialOverride(e.target.value)}
|
||||
className="w-full max-w-md px-3 py-2 border border-border-default rounded-lg text-sm focus:outline-none focus:border-accent"
|
||||
style={{ backgroundColor: materialOverride ? 'rgba(245, 158, 11, 0.1)' : 'var(--color-bg-surface)' }}
|
||||
>
|
||||
<option value="">No material override</option>
|
||||
{libMaterials.map((m: Material) => (
|
||||
<option key={m.id} value={m.name}>{m.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Notes */}
|
||||
<div className="card p-4 mb-4">
|
||||
<label className="block text-sm font-medium text-content-secondary mb-1">
|
||||
|
||||
Reference in New Issue
Block a user