refactor(mui): migrate OrderConfirmationModal to kit Modal

Replace legacy FormModal with the MUI kit Modal. Map the two-step
flow (choose/edit) onto the kit footer: submitText + onSubmit switch
per step, submitDisabled gates "Vygenerovat PDF" when there are no
items. Re-skin lang/VAT toggles (kit Button variants), item editor
(kit TextField + IconButton inside a Box table). All generate/preview
logic, props, and Czech text preserved verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-07 08:43:10 +02:00
parent 6f428b2297
commit e13f977c4d

View File

@@ -1,5 +1,8 @@
import { useState, useCallback } from "react"; import { useState, useCallback } from "react";
import FormModal from "./FormModal"; import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import IconButton from "@mui/material/IconButton";
import { Modal, Button, TextField, Field } from "../ui";
import { useAlert } from "../context/AlertContext"; import { useAlert } from "../context/AlertContext";
interface ConfirmationItem { interface ConfirmationItem {
@@ -103,119 +106,111 @@ export default function OrderConfirmationModal({
}, [defaultVatRate]); }, [defaultVatRate]);
return ( return (
<FormModal <Modal
isOpen={isOpen} isOpen={isOpen}
onClose={onClose} onClose={onClose}
title={`Potvrzení objednávky ${orderNumber}`} title={`Potvrzení objednávky ${orderNumber}`}
size={step === "edit" ? "lg" : "md"} maxWidth={step === "edit" ? "lg" : "md"}
loading={loading} loading={loading}
hideFooter submitText={
step === "choose" ? "Použít položky z objednávky" : "Vygenerovat PDF"
}
submitDisabled={step === "edit" && items.length === 0}
onSubmit={step === "choose" ? handleUseExisting : handleEditGenerate}
> >
{step === "choose" ? ( {step === "choose" ? (
<div className="admin-form"> <Box>
<div className="admin-form-group"> <Field label="Jazyk dokumentu">
<label className="admin-form-label">Jazyk dokumentu</label> <Box sx={{ display: "flex", gap: 1 }}>
<div className="flex-row gap-2"> <Button
<button size="small"
type="button" variant={lang === "cs" ? "contained" : "outlined"}
color={lang === "cs" ? "primary" : "inherit"}
onClick={() => setLang("cs")} onClick={() => setLang("cs")}
className={
lang === "cs"
? "admin-btn admin-btn-primary admin-btn-sm"
: "admin-btn admin-btn-secondary admin-btn-sm"
}
> >
Čeština Čeština
</button> </Button>
<button <Button
type="button" size="small"
variant={lang === "en" ? "contained" : "outlined"}
color={lang === "en" ? "primary" : "inherit"}
onClick={() => setLang("en")} onClick={() => setLang("en")}
className={
lang === "en"
? "admin-btn admin-btn-primary admin-btn-sm"
: "admin-btn admin-btn-secondary admin-btn-sm"
}
> >
English English
</button> </Button>
</div> </Box>
</div> </Field>
<div className="admin-form-group"> <Field label="DPH">
<label className="admin-form-label">DPH</label> <Box sx={{ display: "flex", gap: 1 }}>
<div className="flex-row gap-2"> <Button
<button size="small"
type="button" variant={applyVatState ? "contained" : "outlined"}
color={applyVatState ? "primary" : "inherit"}
onClick={() => setApplyVatState(true)} onClick={() => setApplyVatState(true)}
className={
applyVatState
? "admin-btn admin-btn-primary admin-btn-sm"
: "admin-btn admin-btn-secondary admin-btn-sm"
}
> >
S DPH S DPH
</button> </Button>
<button <Button
type="button" size="small"
variant={!applyVatState ? "contained" : "outlined"}
color={!applyVatState ? "primary" : "inherit"}
onClick={() => setApplyVatState(false)} onClick={() => setApplyVatState(false)}
className={
!applyVatState
? "admin-btn admin-btn-primary admin-btn-sm"
: "admin-btn admin-btn-secondary admin-btn-sm"
}
> >
Bez DPH Bez DPH
</button> </Button>
</div> </Box>
</div> </Field>
<div className="admin-form-group"> <Field label="Obsah potvrzení">
<label className="admin-form-label">Obsah potvrzení</label> <Typography variant="body2" color="text.secondary" sx={{ mb: 1.5 }}>
<p className="text-secondary" style={{ marginBottom: "0.75rem" }}>
Jak chcete připravit potvrzení objednávky? Jak chcete připravit potvrzení objednávky?
</p> </Typography>
<button <Button
onClick={handleUseExisting} fullWidth
disabled={loading}
className="admin-btn admin-btn-primary w-full"
style={{ marginBottom: "0.5rem" }}
>
{loading ? (
<>
<div className="admin-spinner admin-spinner-sm" />
Generuji...
</>
) : (
"Použít položky z objednávky"
)}
</button>
<button
onClick={() => { onClick={() => {
setItems(initialItems.length > 0 ? initialItems : []); setItems(initialItems.length > 0 ? initialItems : []);
setStep("edit"); setStep("edit");
}} }}
disabled={loading} disabled={loading}
className="admin-btn admin-btn-secondary w-full" variant="outlined"
color="inherit"
> >
Upravit položky Upravit položky
</button> </Button>
</div> </Field>
</Box>
<div className="admin-modal-footer"> ) : (
<button <Box>
type="button" <Box sx={{ mb: 1.5 }}>
onClick={onClose} <Button
className="admin-btn admin-btn-secondary" size="small"
variant="outlined"
color="inherit"
onClick={() => setStep("choose")}
disabled={loading} disabled={loading}
> >
Zrušit Zt
</button> </Button>
</div> </Box>
</div> <Box sx={{ overflowX: "auto" }}>
) : ( <Box
<div className="admin-form"> component="table"
<div className="admin-table-responsive"> sx={{
<table className="admin-table"> width: "100%",
borderCollapse: "collapse",
"& th": {
textAlign: "left",
fontSize: ".7rem",
textTransform: "uppercase",
letterSpacing: ".05em",
fontWeight: 700,
color: "text.secondary",
pb: 1,
},
"& td": { py: 0.5, pr: 1, verticalAlign: "middle" },
}}
>
<thead> <thead>
<tr> <tr>
<th>Popis</th> <th>Popis</th>
@@ -230,39 +225,34 @@ export default function OrderConfirmationModal({
{items.map((item, i) => ( {items.map((item, i) => (
<tr key={i}> <tr key={i}>
<td> <td>
<input <TextField
type="text"
value={item.description} value={item.description}
onChange={(e) => onChange={(e) =>
updateItem(i, "description", e.target.value) updateItem(i, "description", e.target.value)
} }
className="admin-form-input" sx={{ minWidth: 200 }}
style={{ minWidth: "200px" }}
/> />
</td> </td>
<td> <td>
<input <TextField
type="number" type="number"
value={item.quantity} value={item.quantity}
onChange={(e) => onChange={(e) =>
updateItem(i, "quantity", Number(e.target.value) || 0) updateItem(i, "quantity", Number(e.target.value) || 0)
} }
className="admin-form-input" sx={{ width: 90 }}
style={{ width: "80px" }} slotProps={{ htmlInput: { step: "0.001" } }}
step="0.001"
/> />
</td> </td>
<td> <td>
<input <TextField
type="text"
value={item.unit} value={item.unit}
onChange={(e) => updateItem(i, "unit", e.target.value)} onChange={(e) => updateItem(i, "unit", e.target.value)}
className="admin-form-input" sx={{ width: 70 }}
style={{ width: "60px" }}
/> />
</td> </td>
<td> <td>
<input <TextField
type="number" type="number"
value={item.unit_price} value={item.unit_price}
onChange={(e) => onChange={(e) =>
@@ -272,28 +262,28 @@ export default function OrderConfirmationModal({
Number(e.target.value) || 0, Number(e.target.value) || 0,
) )
} }
className="admin-form-input" sx={{ width: 110 }}
style={{ width: "100px" }} slotProps={{ htmlInput: { step: "0.01" } }}
step="0.01"
/> />
</td> </td>
<td> <td>
<input <TextField
type="number" type="number"
value={item.vat_rate} value={item.vat_rate}
onChange={(e) => onChange={(e) =>
updateItem(i, "vat_rate", Number(e.target.value) || 0) updateItem(i, "vat_rate", Number(e.target.value) || 0)
} }
className="admin-form-input" sx={{ width: 80 }}
style={{ width: "70px" }} slotProps={{ htmlInput: { step: "1" } }}
step="1"
/> />
</td> </td>
<td> <td>
<button <IconButton
size="small"
color="error"
onClick={() => removeItem(i)} onClick={() => removeItem(i)}
className="admin-btn-icon danger"
title="Odstranit" title="Odstranit"
aria-label="Odstranit"
> >
<svg <svg
width="16" width="16"
@@ -306,47 +296,25 @@ export default function OrderConfirmationModal({
<polyline points="3 6 5 6 21 6" /> <polyline points="3 6 5 6 21 6" />
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" /> <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
</svg> </svg>
</button> </IconButton>
</td> </td>
</tr> </tr>
))} ))}
</tbody> </tbody>
</table> </Box>
</div> </Box>
<button <Box sx={{ mt: 1.5 }}>
onClick={addItem} <Button
className="admin-btn admin-btn-secondary admin-btn-sm" size="small"
> variant="outlined"
+ Přidat položku color="inherit"
</button> onClick={addItem}
<div className="admin-modal-footer">
<button
type="button"
onClick={() => setStep("choose")}
className="admin-btn admin-btn-secondary"
disabled={loading}
> >
Zpět + Přidat položku
</button> </Button>
<button </Box>
type="button" </Box>
onClick={handleEditGenerate}
className="admin-btn admin-btn-primary"
disabled={loading || items.length === 0}
>
{loading ? (
<>
<div className="admin-spinner admin-spinner-sm" />
Generuji...
</>
) : (
"Vygenerovat PDF"
)}
</button>
</div>
</div>
)} )}
</FormModal> </Modal>
); );
} }