feat(warehouse): add shared warehouse components

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-05-29 14:20:42 +02:00
parent 7b7c6bde68
commit 86bebf9776
5 changed files with 319 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
import type { WarehouseLocation } from "../../lib/queries/warehouse";
import ItemPicker from "./ItemPicker";
import LocationSelect from "./LocationSelect";
import BatchPicker from "./BatchPicker";
export interface MovementLine {
key: string;
item_id: number | null;
item_name?: string;
quantity: number;
unit_price: number;
location_id: number | null;
batch_id: number | null;
reservation_id: number | null;
notes: string | null;
}
interface WarehouseMovementTableProps {
lines: MovementLine[];
onChange: (lines: MovementLine[]) => void;
mode: "receipt" | "issue";
locations: WarehouseLocation[];
}
let lineCounter = 0;
export default function WarehouseMovementTable({
lines,
onChange,
mode,
}: WarehouseMovementTableProps) {
const addLine = () => {
onChange([
...lines,
{
key: `line-${++lineCounter}`,
item_id: null,
quantity: 0,
unit_price: 0,
location_id: null,
batch_id: null,
reservation_id: null,
notes: null,
},
]);
};
const removeLine = (index: number) => {
onChange(lines.filter((_, i) => i !== index));
};
const updateLine = (index: number, field: string, value: unknown) => {
const updated = [...lines];
updated[index] = { ...updated[index], [field]: value };
onChange(updated);
};
return (
<div className="admin-warehouse-movement-table">
<table className="admin-table">
<thead>
<tr>
<th>Položka</th>
{mode === "issue" && <th>Šarže</th>}
<th>Množství</th>
<th>Cena/ks</th>
<th>Lokace</th>
<th>Poznámka</th>
<th></th>
</tr>
</thead>
<tbody>
{lines.map((line, index) => (
<tr key={line.key}>
<td>
<ItemPicker
value={line.item_id}
onChange={(id) => updateLine(index, "item_id", id)}
/>
</td>
{mode === "issue" && (
<td>
<BatchPicker
itemId={line.item_id}
value={line.batch_id}
onChange={(batchId, unitPrice) => {
updateLine(index, "batch_id", batchId);
updateLine(index, "unit_price", unitPrice);
}}
/>
</td>
)}
<td>
<input
type="number"
className="admin-form-input"
value={line.quantity || ""}
onChange={(e) =>
updateLine(index, "quantity", Number(e.target.value))
}
min="0"
step="0.001"
/>
</td>
<td>
<input
type="number"
className="admin-form-input"
value={line.unit_price || ""}
onChange={(e) =>
updateLine(index, "unit_price", Number(e.target.value))
}
min="0"
step="0.01"
disabled={mode === "issue"}
/>
</td>
<td>
<LocationSelect
value={line.location_id}
onChange={(id) => updateLine(index, "location_id", id)}
/>
</td>
<td>
<input
type="text"
className="admin-form-input"
value={line.notes ?? ""}
onChange={(e) => updateLine(index, "notes", e.target.value)}
/>
</td>
<td>
<button
type="button"
className="admin-btn-danger-sm"
onClick={() => removeLine(index)}
>
</button>
</td>
</tr>
))}
</tbody>
</table>
<button type="button" className="admin-btn-secondary" onClick={addLine}>
+ Přidat řádek
</button>
</div>
);
}