feat(orders): invoices-style landing — month selector + Vydane-first tabs, content-only tab bodies
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,36 +1,187 @@
|
||||
import { lazy, Suspense } from "react";
|
||||
import { useState, lazy, Suspense } from "react";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import Box from "@mui/material/Box";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { Tabs, LoadingState } from "../ui";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
import Forbidden from "../components/Forbidden";
|
||||
import { Button, Tabs, PageHeader, PageEnter, LoadingState } from "../ui";
|
||||
import OrdersReceived from "./OrdersReceived";
|
||||
|
||||
const IssuedOrders = lazy(() => import("./IssuedOrders"));
|
||||
|
||||
const MONTH_NAMES = [
|
||||
"leden",
|
||||
"únor",
|
||||
"březen",
|
||||
"duben",
|
||||
"květen",
|
||||
"červen",
|
||||
"červenec",
|
||||
"srpen",
|
||||
"září",
|
||||
"říjen",
|
||||
"listopad",
|
||||
"prosinec",
|
||||
];
|
||||
|
||||
const PlusIcon = (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<line x1="12" y1="5" x2="12" y2="19" />
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
</svg>
|
||||
);
|
||||
const ChevronLeftIcon = (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.5"
|
||||
>
|
||||
<polyline points="15 18 9 12 15 6" />
|
||||
</svg>
|
||||
);
|
||||
const ChevronRightIcon = (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.5"
|
||||
>
|
||||
<polyline points="9 18 15 12 9 6" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default function Orders() {
|
||||
const { hasPermission } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const activeTab = searchParams.get("tab") === "vydane" ? "vydane" : "prijate";
|
||||
const activeTab =
|
||||
searchParams.get("tab") === "prijate" ? "prijate" : "vydane";
|
||||
const setActiveTab = (tab: string) =>
|
||||
setSearchParams({ tab }, { replace: true });
|
||||
|
||||
const [createOpen, setCreateOpen] = useState(false);
|
||||
|
||||
const now = new Date();
|
||||
const [statsMonth, setStatsMonth] = useState(now.getMonth() + 1);
|
||||
const [statsYear, setStatsYear] = useState(now.getFullYear());
|
||||
|
||||
const isCurrentMonth =
|
||||
statsMonth === now.getMonth() + 1 && statsYear === now.getFullYear();
|
||||
const monthLabel = `${MONTH_NAMES[statsMonth - 1]} ${statsYear}`;
|
||||
|
||||
const prevMonth = () => {
|
||||
if (statsMonth === 1) {
|
||||
setStatsMonth(12);
|
||||
setStatsYear((y) => y - 1);
|
||||
} else {
|
||||
setStatsMonth((m) => m - 1);
|
||||
}
|
||||
};
|
||||
|
||||
const nextMonth = () => {
|
||||
if (isCurrentMonth) return;
|
||||
if (statsMonth === 12) {
|
||||
setStatsMonth(1);
|
||||
setStatsYear((y) => y + 1);
|
||||
} else {
|
||||
setStatsMonth((m) => m + 1);
|
||||
}
|
||||
};
|
||||
|
||||
if (!hasPermission("orders.view")) return <Forbidden />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ display: "flex", justifyContent: "center", mb: 2.5 }}>
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onChange={(v) => setActiveTab(v)}
|
||||
tabs={[
|
||||
{ value: "prijate", label: "Přijaté" },
|
||||
{ value: "vydane", label: "Vydané" },
|
||||
]}
|
||||
/>
|
||||
<PageEnter>
|
||||
<PageHeader
|
||||
title="Objednávky"
|
||||
actions={
|
||||
hasPermission("orders.create") ? (
|
||||
activeTab === "vydane" ? (
|
||||
<Button
|
||||
startIcon={PlusIcon}
|
||||
onClick={() => navigate("/orders/issued/new")}
|
||||
>
|
||||
Vytvořit objednávku vydanou
|
||||
</Button>
|
||||
) : (
|
||||
<Button startIcon={PlusIcon} onClick={() => setCreateOpen(true)}>
|
||||
Vytvořit objednávku
|
||||
</Button>
|
||||
)
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 1,
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={prevMonth}
|
||||
aria-label="Předchozí měsíc"
|
||||
>
|
||||
{ChevronLeftIcon}
|
||||
</IconButton>
|
||||
<Typography
|
||||
sx={{ minWidth: 140, textAlign: "center", fontWeight: 600 }}
|
||||
>
|
||||
{monthLabel}
|
||||
</Typography>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={nextMonth}
|
||||
disabled={isCurrentMonth}
|
||||
aria-label="Následující měsíc"
|
||||
>
|
||||
{ChevronRightIcon}
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ display: "flex", justifyContent: "center", mb: 2.5 }}>
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onChange={(v) => setActiveTab(v)}
|
||||
tabs={[
|
||||
{ value: "vydane", label: "Vydané" },
|
||||
{ value: "prijate", label: "Přijaté" },
|
||||
]}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{activeTab === "vydane" ? (
|
||||
<Suspense fallback={<LoadingState />}>
|
||||
<IssuedOrders />
|
||||
<IssuedOrders month={statsMonth} year={statsYear} />
|
||||
</Suspense>
|
||||
) : (
|
||||
<OrdersReceived />
|
||||
<OrdersReceived
|
||||
month={statsMonth}
|
||||
year={statsYear}
|
||||
createOpen={createOpen}
|
||||
setCreateOpen={setCreateOpen}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</PageEnter>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user