fix(ui): line-item number inputs — allow clearing the 0 (store raw string, coerce at totals/save), unify value alignment, widen Množství column
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,22 @@ import { useTheme } from "@mui/material/styles";
|
||||
import { Modal, Button, TextField, Field } from "../ui";
|
||||
import { useAlert } from "../context/AlertContext";
|
||||
|
||||
// Editable line-item. quantity/unit_price/vat_rate are held as the raw typed
|
||||
// string while editing (so a field can be cleared — empty renders fine in a
|
||||
// type="number" input) and are coerced to numbers in handleEditGenerate before
|
||||
// being handed to onGenerate (the parent posts them verbatim).
|
||||
interface ConfirmationItem {
|
||||
description: string;
|
||||
quantity: string | number;
|
||||
unit: string;
|
||||
unit_price: string | number;
|
||||
is_included_in_total: boolean;
|
||||
vat_rate: string | number;
|
||||
}
|
||||
|
||||
// Numeric shape handed to the parent (the raw editing strings are coerced in
|
||||
// handleEditGenerate). Distinct from the editable ConfirmationItem.
|
||||
interface GeneratedItem {
|
||||
description: string;
|
||||
quantity: number;
|
||||
unit: string;
|
||||
@@ -22,7 +37,7 @@ interface OrderConfirmationModalProps {
|
||||
onGenerate: (
|
||||
lang: string,
|
||||
applyVat: boolean,
|
||||
items?: ConfirmationItem[],
|
||||
items?: GeneratedItem[],
|
||||
) => Promise<void>;
|
||||
initialItems: ConfirmationItem[];
|
||||
orderNumber: string;
|
||||
@@ -81,7 +96,17 @@ export default function OrderConfirmationModal({
|
||||
const handleEditGenerate = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await onGenerate(lang, applyVatState, items);
|
||||
// Coerce the raw typed strings back to numbers so an empty/partial field
|
||||
// never reaches the server as NaN (the parent posts these verbatim).
|
||||
const coercedItems: GeneratedItem[] = items.map((it) => ({
|
||||
description: it.description,
|
||||
quantity: Number(it.quantity) || 0,
|
||||
unit: it.unit,
|
||||
unit_price: Number(it.unit_price) || 0,
|
||||
is_included_in_total: it.is_included_in_total,
|
||||
vat_rate: Number(it.vat_rate) || 0,
|
||||
}));
|
||||
await onGenerate(lang, applyVatState, coercedItems);
|
||||
// Only close on success — on error keep the user's edited items intact.
|
||||
onClose();
|
||||
} catch (err) {
|
||||
@@ -273,9 +298,9 @@ export default function OrderConfirmationModal({
|
||||
<TextField
|
||||
label="Množství"
|
||||
type="number"
|
||||
value={item.quantity}
|
||||
value={item.quantity ?? ""}
|
||||
onChange={(e) =>
|
||||
updateItem(i, "quantity", Number(e.target.value) || 0)
|
||||
updateItem(i, "quantity", e.target.value)
|
||||
}
|
||||
slotProps={{ htmlInput: { step: "0.001" } }}
|
||||
/>
|
||||
@@ -287,18 +312,18 @@ export default function OrderConfirmationModal({
|
||||
<TextField
|
||||
label="Cena"
|
||||
type="number"
|
||||
value={item.unit_price}
|
||||
value={item.unit_price ?? ""}
|
||||
onChange={(e) =>
|
||||
updateItem(i, "unit_price", Number(e.target.value) || 0)
|
||||
updateItem(i, "unit_price", e.target.value)
|
||||
}
|
||||
slotProps={{ htmlInput: { step: "0.01" } }}
|
||||
/>
|
||||
<TextField
|
||||
label="%DPH"
|
||||
type="number"
|
||||
value={item.vat_rate}
|
||||
value={item.vat_rate ?? ""}
|
||||
onChange={(e) =>
|
||||
updateItem(i, "vat_rate", Number(e.target.value) || 0)
|
||||
updateItem(i, "vat_rate", e.target.value)
|
||||
}
|
||||
slotProps={{ htmlInput: { step: "1" } }}
|
||||
/>
|
||||
@@ -350,15 +375,11 @@ export default function OrderConfirmationModal({
|
||||
<td>
|
||||
<TextField
|
||||
type="number"
|
||||
value={item.quantity}
|
||||
value={item.quantity ?? ""}
|
||||
onChange={(e) =>
|
||||
updateItem(
|
||||
i,
|
||||
"quantity",
|
||||
Number(e.target.value) || 0,
|
||||
)
|
||||
updateItem(i, "quantity", e.target.value)
|
||||
}
|
||||
sx={{ width: 90 }}
|
||||
sx={{ width: 112 }}
|
||||
slotProps={{ htmlInput: { step: "0.001" } }}
|
||||
/>
|
||||
</td>
|
||||
@@ -374,13 +395,9 @@ export default function OrderConfirmationModal({
|
||||
<td>
|
||||
<TextField
|
||||
type="number"
|
||||
value={item.unit_price}
|
||||
value={item.unit_price ?? ""}
|
||||
onChange={(e) =>
|
||||
updateItem(
|
||||
i,
|
||||
"unit_price",
|
||||
Number(e.target.value) || 0,
|
||||
)
|
||||
updateItem(i, "unit_price", e.target.value)
|
||||
}
|
||||
sx={{ width: 110 }}
|
||||
slotProps={{ htmlInput: { step: "0.01" } }}
|
||||
@@ -389,13 +406,9 @@ export default function OrderConfirmationModal({
|
||||
<td>
|
||||
<TextField
|
||||
type="number"
|
||||
value={item.vat_rate}
|
||||
value={item.vat_rate ?? ""}
|
||||
onChange={(e) =>
|
||||
updateItem(
|
||||
i,
|
||||
"vat_rate",
|
||||
Number(e.target.value) || 0,
|
||||
)
|
||||
updateItem(i, "vat_rate", e.target.value)
|
||||
}
|
||||
sx={{ width: 80 }}
|
||||
slotProps={{ htmlInput: { step: "1" } }}
|
||||
|
||||
Reference in New Issue
Block a user