feat(ui): mobile card layout for the remaining item tables
OrderConfirmationModal (the order→confirmation editable items dialog) and InvoiceDetail's read-only paid-invoice items table now render stacked label:value cards on phones (< sm) instead of a wide horizontally-scrolling table; desktop keeps the table. Same pattern as the Offer/Invoice editors. Gates: tsc=0, build=0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1263,93 +1263,106 @@ export default function InvoiceDetail() {
|
||||
Položky
|
||||
</Typography>
|
||||
{invoice.items && invoice.items.length > 0 ? (
|
||||
<TableContainer sx={{ overflowX: "auto" }}>
|
||||
<Table
|
||||
size="small"
|
||||
sx={{ "& td, & th": { borderColor: "divider" } }}
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell sx={{ width: "2.5rem" }} align="center">
|
||||
#
|
||||
</TableCell>
|
||||
<TableCell>Popis</TableCell>
|
||||
<TableCell sx={{ width: "5.5rem" }} align="center">
|
||||
Množství
|
||||
</TableCell>
|
||||
<TableCell sx={{ width: "5rem" }} align="center">
|
||||
Jednotka
|
||||
</TableCell>
|
||||
<TableCell sx={{ width: "8rem" }} align="right">
|
||||
Jedn. cena
|
||||
</TableCell>
|
||||
<TableCell sx={{ width: "4rem" }} align="center">
|
||||
%DPH
|
||||
</TableCell>
|
||||
<TableCell sx={{ width: "9rem" }} align="right">
|
||||
Celkem
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{invoice.items.map((item, index) => {
|
||||
const lineSubtotal =
|
||||
(Number(item.quantity) || 0) *
|
||||
(Number(item.unit_price) || 0);
|
||||
const lineVat = Number(invoice.apply_vat)
|
||||
? (lineSubtotal * (Number(item.vat_rate) || 0)) / 100
|
||||
: 0;
|
||||
return (
|
||||
<TableRow key={item.id || index}>
|
||||
<TableCell
|
||||
align="center"
|
||||
sx={{ color: "text.secondary", fontWeight: 500 }}
|
||||
>
|
||||
{index + 1}
|
||||
</TableCell>
|
||||
<TableCell sx={{ fontWeight: 500 }}>
|
||||
{item.description || "—"}
|
||||
{item.item_description && (
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
display: "block",
|
||||
opacity: 0.8,
|
||||
mt: "2px",
|
||||
}}
|
||||
>
|
||||
{item.item_description}
|
||||
</Typography>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
{item.quantity}{" "}
|
||||
{item.unit && (
|
||||
<Box
|
||||
component="span"
|
||||
sx={{ color: "text.secondary" }}
|
||||
>
|
||||
{item.unit}
|
||||
</Box>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="center">{item.unit || "—"}</TableCell>
|
||||
<TableCell
|
||||
align="right"
|
||||
sx={{
|
||||
fontFamily: "'DM Mono', Menlo, monospace",
|
||||
}}
|
||||
isMobile ? (
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: 1.5 }}>
|
||||
{invoice.items.map((item, index) => {
|
||||
const lineSubtotal =
|
||||
(Number(item.quantity) || 0) *
|
||||
(Number(item.unit_price) || 0);
|
||||
const lineVat = Number(invoice.apply_vat)
|
||||
? (lineSubtotal * (Number(item.vat_rate) || 0)) / 100
|
||||
: 0;
|
||||
return (
|
||||
<Box
|
||||
key={item.id || index}
|
||||
sx={{
|
||||
border: 1,
|
||||
borderColor: "divider",
|
||||
borderRadius: 2,
|
||||
p: 1.5,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 0.75,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ fontWeight: 600 }}>
|
||||
{item.description || "—"}
|
||||
{item.item_description && (
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
display: "block",
|
||||
opacity: 0.8,
|
||||
fontWeight: 400,
|
||||
}}
|
||||
>
|
||||
{item.item_description}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
fontSize: ".85rem",
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
Množství
|
||||
</Typography>
|
||||
<span>
|
||||
{item.quantity} {item.unit}
|
||||
</span>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
fontSize: ".85rem",
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
Jedn. cena
|
||||
</Typography>
|
||||
<Box
|
||||
component="span"
|
||||
sx={{ fontFamily: "'DM Mono', Menlo, monospace" }}
|
||||
>
|
||||
{formatCurrency(item.unit_price, invoice.currency)}
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
{Number(invoice.apply_vat)
|
||||
? Number(item.vat_rate)
|
||||
: 0}
|
||||
%
|
||||
</TableCell>
|
||||
<TableCell
|
||||
align="right"
|
||||
</Box>
|
||||
</Box>
|
||||
{Number(invoice.apply_vat) ? (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
fontSize: ".85rem",
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
%DPH
|
||||
</Typography>
|
||||
<span>{Number(item.vat_rate)}%</span>
|
||||
</Box>
|
||||
) : null}
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "baseline",
|
||||
pt: 0.5,
|
||||
borderTop: 1,
|
||||
borderColor: "divider",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{ color: "text.secondary", fontWeight: 700 }}
|
||||
>
|
||||
Celkem
|
||||
</Typography>
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
fontFamily: "'DM Mono', Menlo, monospace",
|
||||
fontWeight: 600,
|
||||
@@ -1359,13 +1372,119 @@ export default function InvoiceDetail() {
|
||||
lineSubtotal + lineVat,
|
||||
invoice.currency,
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
) : (
|
||||
<TableContainer sx={{ overflowX: "auto" }}>
|
||||
<Table
|
||||
size="small"
|
||||
sx={{ "& td, & th": { borderColor: "divider" } }}
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell sx={{ width: "2.5rem" }} align="center">
|
||||
#
|
||||
</TableCell>
|
||||
<TableCell>Popis</TableCell>
|
||||
<TableCell sx={{ width: "5.5rem" }} align="center">
|
||||
Množství
|
||||
</TableCell>
|
||||
<TableCell sx={{ width: "5rem" }} align="center">
|
||||
Jednotka
|
||||
</TableCell>
|
||||
<TableCell sx={{ width: "8rem" }} align="right">
|
||||
Jedn. cena
|
||||
</TableCell>
|
||||
<TableCell sx={{ width: "4rem" }} align="center">
|
||||
%DPH
|
||||
</TableCell>
|
||||
<TableCell sx={{ width: "9rem" }} align="right">
|
||||
Celkem
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{invoice.items.map((item, index) => {
|
||||
const lineSubtotal =
|
||||
(Number(item.quantity) || 0) *
|
||||
(Number(item.unit_price) || 0);
|
||||
const lineVat = Number(invoice.apply_vat)
|
||||
? (lineSubtotal * (Number(item.vat_rate) || 0)) / 100
|
||||
: 0;
|
||||
return (
|
||||
<TableRow key={item.id || index}>
|
||||
<TableCell
|
||||
align="center"
|
||||
sx={{ color: "text.secondary", fontWeight: 500 }}
|
||||
>
|
||||
{index + 1}
|
||||
</TableCell>
|
||||
<TableCell sx={{ fontWeight: 500 }}>
|
||||
{item.description || "—"}
|
||||
{item.item_description && (
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
display: "block",
|
||||
opacity: 0.8,
|
||||
mt: "2px",
|
||||
}}
|
||||
>
|
||||
{item.item_description}
|
||||
</Typography>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
{item.quantity}{" "}
|
||||
{item.unit && (
|
||||
<Box
|
||||
component="span"
|
||||
sx={{ color: "text.secondary" }}
|
||||
>
|
||||
{item.unit}
|
||||
</Box>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
{item.unit || "—"}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
align="right"
|
||||
sx={{
|
||||
fontFamily: "'DM Mono', Menlo, monospace",
|
||||
}}
|
||||
>
|
||||
{formatCurrency(item.unit_price, invoice.currency)}
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
{Number(invoice.apply_vat)
|
||||
? Number(item.vat_rate)
|
||||
: 0}
|
||||
%
|
||||
</TableCell>
|
||||
<TableCell
|
||||
align="right"
|
||||
sx={{
|
||||
fontFamily: "'DM Mono', Menlo, monospace",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{formatCurrency(
|
||||
lineSubtotal + lineVat,
|
||||
invoice.currency,
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)
|
||||
) : (
|
||||
<EmptyState title="Žádné položky." />
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user