feat(mui): migrate Warehouse overview + replace residual admin-loading loaders with LoadingState
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@ import {
|
||||
FilterBar,
|
||||
Tabs,
|
||||
PageHeader,
|
||||
LoadingState,
|
||||
type DataColumn,
|
||||
type TabDef,
|
||||
} from "../ui";
|
||||
@@ -450,11 +451,7 @@ export default function Offers() {
|
||||
};
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="admin-loading">
|
||||
<div className="admin-spinner" />
|
||||
</div>
|
||||
);
|
||||
return <LoadingState />;
|
||||
}
|
||||
|
||||
const total = pagination?.total ?? quotations.length;
|
||||
|
||||
@@ -15,7 +15,7 @@ import PlanGrid from "../components/PlanGrid";
|
||||
import PlanCellModal from "../components/PlanCellModal";
|
||||
import PlanCategoriesModal from "../components/PlanCategoriesModal";
|
||||
import Forbidden from "../components/Forbidden";
|
||||
import { Button, Alert } from "../ui";
|
||||
import { Button, Alert, LoadingState } from "../ui";
|
||||
import { projectListOptions, type Project } from "../lib/queries/projects";
|
||||
import { planCategoriesOptions, type PlanCategory } from "../lib/queries/plan";
|
||||
// plan.css is imported once globally in AdminApp.tsx — no per-page re-import.
|
||||
@@ -670,11 +670,7 @@ export default function PlanWork() {
|
||||
</Box>
|
||||
</motion.div>
|
||||
|
||||
{gridLoading && (
|
||||
<div className="admin-loading">
|
||||
<div className="admin-spinner" />
|
||||
</div>
|
||||
)}
|
||||
{gridLoading && <LoadingState />}
|
||||
|
||||
{/*
|
||||
Grid entrance: same pattern as the h1 / banner / toolbar above
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
DateField,
|
||||
StatusChip,
|
||||
CheckboxField,
|
||||
LoadingState,
|
||||
type DataColumn,
|
||||
} from "../ui";
|
||||
|
||||
@@ -234,11 +235,7 @@ export default function Projects() {
|
||||
};
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="admin-loading">
|
||||
<div className="admin-spinner" />
|
||||
</div>
|
||||
);
|
||||
return <LoadingState />;
|
||||
}
|
||||
|
||||
const columns: DataColumn<Project>[] = [
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
SwitchField,
|
||||
Select,
|
||||
StatusChip,
|
||||
LoadingState,
|
||||
type DataColumn,
|
||||
} from "../ui";
|
||||
|
||||
@@ -247,11 +248,7 @@ export default function Users() {
|
||||
};
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="admin-loading">
|
||||
<div className="admin-spinner" />
|
||||
</div>
|
||||
);
|
||||
return <LoadingState />;
|
||||
}
|
||||
|
||||
const columns: DataColumn<User>[] = [
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
Field,
|
||||
TextField,
|
||||
SwitchField,
|
||||
LoadingState,
|
||||
type DataColumn,
|
||||
} from "../ui";
|
||||
|
||||
@@ -222,11 +223,7 @@ export default function Vehicles() {
|
||||
};
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="admin-loading">
|
||||
<div className="admin-spinner" />
|
||||
</div>
|
||||
);
|
||||
return <LoadingState />;
|
||||
}
|
||||
|
||||
const columns: DataColumn<Vehicle>[] = [
|
||||
|
||||
@@ -1,32 +1,89 @@
|
||||
import { Link } from "react-router-dom";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { motion } from "framer-motion";
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
import Forbidden from "../components/Forbidden";
|
||||
import { motion } from "framer-motion";
|
||||
import {
|
||||
warehouseStockStatusOptions,
|
||||
warehouseBelowMinimumOptions,
|
||||
warehouseReservationListOptions,
|
||||
warehouseMovementLogOptions,
|
||||
type WarehouseItem,
|
||||
type WarehouseReservation,
|
||||
} from "../lib/queries/warehouse";
|
||||
import { formatCurrency, formatDate } from "../utils/formatters";
|
||||
import useReducedMotion from "../hooks/useReducedMotion";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
DataTable,
|
||||
StatCard,
|
||||
StatusChip,
|
||||
EmptyState,
|
||||
LoadingState,
|
||||
PageHeader,
|
||||
type DataColumn,
|
||||
type StatCardColor,
|
||||
} from "../ui";
|
||||
|
||||
const TYPE_LABEL: Record<string, string> = {
|
||||
receipt: "Příjem",
|
||||
issue: "Výdej",
|
||||
};
|
||||
|
||||
const TYPE_TONE: Record<string, string> = {
|
||||
receipt: "admin-badge-incoming",
|
||||
issue: "admin-badge-outgoing",
|
||||
// Movement type → StatusChip color (legacy: incoming=success, outgoing=info)
|
||||
const TYPE_COLOR: Record<string, "success" | "info"> = {
|
||||
receipt: "success",
|
||||
issue: "info",
|
||||
};
|
||||
|
||||
const ReceiptIcon = (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<polyline points="17 11 12 6 7 11" />
|
||||
<line x1="12" y1="6" x2="12" y2="18" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
const IssueIcon = (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<polyline points="7 13 12 18 17 13" />
|
||||
<line x1="12" y1="18" x2="12" y2="6" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
interface BelowMinRow {
|
||||
id: number;
|
||||
name: string;
|
||||
available_quantity: number;
|
||||
min_quantity: number;
|
||||
}
|
||||
|
||||
interface MovementRow {
|
||||
_idx: number;
|
||||
date: string;
|
||||
type: string;
|
||||
document_number: string;
|
||||
item_name: string;
|
||||
quantity: number;
|
||||
supplier_or_project: string;
|
||||
}
|
||||
|
||||
export default function Warehouse() {
|
||||
const { hasPermission } = useAuth();
|
||||
const reducedMotion = useReducedMotion();
|
||||
|
||||
const { data: stockItems, isPending: stockPending } = useQuery(
|
||||
warehouseStockStatusOptions(),
|
||||
@@ -60,253 +117,270 @@ export default function Warehouse() {
|
||||
const isLoading =
|
||||
stockPending || belowMinPending || reservationsPending || movementsLoading;
|
||||
|
||||
const belowMinColor: StatCardColor =
|
||||
belowMinimumCount > 0 ? "error" : "warning";
|
||||
|
||||
const belowMinColumns: DataColumn<BelowMinRow>[] = [
|
||||
{
|
||||
key: "name",
|
||||
header: "Název",
|
||||
width: "50%",
|
||||
bold: true,
|
||||
render: (item) => item.name,
|
||||
},
|
||||
{
|
||||
key: "available_quantity",
|
||||
header: "K dispozici",
|
||||
width: "25%",
|
||||
mono: true,
|
||||
render: (item) => String(item.available_quantity),
|
||||
},
|
||||
{
|
||||
key: "min_quantity",
|
||||
header: "Min. množství",
|
||||
width: "25%",
|
||||
mono: true,
|
||||
render: (item) => String(item.min_quantity),
|
||||
},
|
||||
];
|
||||
|
||||
const movementColumns: DataColumn<MovementRow>[] = [
|
||||
{
|
||||
key: "date",
|
||||
header: "Datum",
|
||||
width: "12%",
|
||||
mono: true,
|
||||
render: (row) => formatDate(row.date),
|
||||
},
|
||||
{
|
||||
key: "type",
|
||||
header: "Typ",
|
||||
width: "12%",
|
||||
render: (row) => (
|
||||
<StatusChip
|
||||
label={TYPE_LABEL[row.type] ?? row.type}
|
||||
color={TYPE_COLOR[row.type] ?? "info"}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "document_number",
|
||||
header: "Doklad",
|
||||
width: "16%",
|
||||
mono: true,
|
||||
render: (row) => row.document_number || "—",
|
||||
},
|
||||
{
|
||||
key: "item_name",
|
||||
header: "Položka",
|
||||
width: "28%",
|
||||
bold: true,
|
||||
render: (row) => row.item_name,
|
||||
},
|
||||
{
|
||||
key: "quantity",
|
||||
header: "Množství",
|
||||
width: "12%",
|
||||
mono: true,
|
||||
render: (row) => String(row.quantity),
|
||||
},
|
||||
{
|
||||
key: "supplier_or_project",
|
||||
header: "Dodavatel / Projekt",
|
||||
width: "20%",
|
||||
render: (row) => row.supplier_or_project || "—",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Box>
|
||||
<motion.div
|
||||
className="admin-page-header"
|
||||
initial={{ opacity: 0, y: 12 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.25 }}
|
||||
>
|
||||
<div>
|
||||
<h1 className="admin-page-title">Sklad</h1>
|
||||
<p className="admin-page-subtitle">Přehled skladových zásob</p>
|
||||
</div>
|
||||
<div className="admin-page-actions">
|
||||
{hasPermission("warehouse.operate") && (
|
||||
<>
|
||||
<Link
|
||||
to="/warehouse/receipts/new"
|
||||
className="admin-btn admin-btn-primary"
|
||||
>
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
<PageHeader
|
||||
title="Sklad"
|
||||
subtitle="Přehled skladových zásob"
|
||||
actions={
|
||||
<Box sx={{ display: "flex", gap: 1.5, flexWrap: "wrap" }}>
|
||||
{hasPermission("warehouse.operate") && (
|
||||
<>
|
||||
<Button
|
||||
component={RouterLink}
|
||||
to="/warehouse/receipts/new"
|
||||
startIcon={ReceiptIcon}
|
||||
>
|
||||
Nový příjem
|
||||
</Button>
|
||||
<Button
|
||||
component={RouterLink}
|
||||
to="/warehouse/issues/new"
|
||||
variant="outlined"
|
||||
color="inherit"
|
||||
startIcon={IssueIcon}
|
||||
>
|
||||
Nový výdej
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{hasPermission("warehouse.manage") && (
|
||||
<Button
|
||||
component={RouterLink}
|
||||
to="/warehouse/categories"
|
||||
variant="outlined"
|
||||
color="inherit"
|
||||
>
|
||||
<polyline points="17 11 12 6 7 11" />
|
||||
<line x1="12" y1="6" x2="12" y2="18" />
|
||||
</svg>
|
||||
Nový příjem
|
||||
</Link>
|
||||
<Link
|
||||
to="/warehouse/issues/new"
|
||||
className="admin-btn admin-btn-secondary"
|
||||
Kategorie
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
component={RouterLink}
|
||||
to="/warehouse/items"
|
||||
variant="outlined"
|
||||
color="inherit"
|
||||
>
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<polyline points="7 13 12 18 17 13" />
|
||||
<line x1="12" y1="18" x2="12" y2="6" />
|
||||
</svg>
|
||||
Nový výdej
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
{hasPermission("warehouse.manage") && (
|
||||
<Link
|
||||
to="/warehouse/categories"
|
||||
className="admin-btn admin-btn-secondary"
|
||||
>
|
||||
Kategorie
|
||||
</Link>
|
||||
)}
|
||||
<Link to="/warehouse/items" className="admin-btn admin-btn-secondary">
|
||||
Položky
|
||||
</Link>
|
||||
<Link
|
||||
to="/warehouse/reports"
|
||||
className="admin-btn admin-btn-secondary"
|
||||
>
|
||||
Reporty
|
||||
</Link>
|
||||
</div>
|
||||
Položky
|
||||
</Button>
|
||||
<Button
|
||||
component={RouterLink}
|
||||
to="/warehouse/reports"
|
||||
variant="outlined"
|
||||
color="inherit"
|
||||
>
|
||||
Reporty
|
||||
</Button>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
{/* KPI cards */}
|
||||
<div className="admin-kpi-grid admin-kpi-4">
|
||||
<motion.div
|
||||
className="admin-stat-card info"
|
||||
initial={{ opacity: 0, y: 12 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{
|
||||
duration: reducedMotion ? 0 : 0.25,
|
||||
delay: reducedMotion ? 0 : 0.06,
|
||||
}}
|
||||
>
|
||||
<div className="admin-stat-label">Celkem položek</div>
|
||||
<div className="admin-stat-value admin-mono">
|
||||
{isLoading ? "—" : totalItems}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="admin-stat-card success"
|
||||
initial={{ opacity: 0, y: 12 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{
|
||||
duration: reducedMotion ? 0 : 0.25,
|
||||
delay: reducedMotion ? 0 : 0.08,
|
||||
}}
|
||||
>
|
||||
<div className="admin-stat-label">Hodnota zásob</div>
|
||||
<div className="admin-stat-value admin-mono">
|
||||
{isLoading ? "—" : formatCurrency(totalStockValue, "CZK")}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className={`admin-stat-card ${belowMinimumCount > 0 ? "danger" : "warning"}`}
|
||||
initial={{ opacity: 0, y: 12 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{
|
||||
duration: reducedMotion ? 0 : 0.25,
|
||||
delay: reducedMotion ? 0 : 0.1,
|
||||
}}
|
||||
>
|
||||
<div className="admin-stat-label">Pod minimem</div>
|
||||
<div className="admin-stat-value admin-mono">
|
||||
{isLoading ? "—" : belowMinimumCount}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="admin-stat-card info"
|
||||
initial={{ opacity: 0, y: 12 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{
|
||||
duration: reducedMotion ? 0 : 0.25,
|
||||
delay: reducedMotion ? 0 : 0.12,
|
||||
}}
|
||||
>
|
||||
<div className="admin-stat-label">Aktivní rezervace</div>
|
||||
<div className="admin-stat-value admin-mono">
|
||||
{isLoading ? "—" : activeReservationCount}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
<Box
|
||||
component={motion.div}
|
||||
initial={{ opacity: 0, y: 12 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.25, delay: 0.06 }}
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: {
|
||||
xs: "1fr",
|
||||
sm: "repeat(2, 1fr)",
|
||||
lg: "repeat(4, 1fr)",
|
||||
},
|
||||
gap: 2,
|
||||
mb: 3,
|
||||
}}
|
||||
>
|
||||
<StatCard
|
||||
color="info"
|
||||
label="Celkem položek"
|
||||
value={isLoading ? "—" : totalItems}
|
||||
/>
|
||||
<StatCard
|
||||
color="success"
|
||||
label="Hodnota zásob"
|
||||
value={isLoading ? "—" : formatCurrency(totalStockValue, "CZK")}
|
||||
/>
|
||||
<StatCard
|
||||
color={belowMinColor}
|
||||
label="Pod minimem"
|
||||
value={isLoading ? "—" : belowMinimumCount}
|
||||
/>
|
||||
<StatCard
|
||||
color="info"
|
||||
label="Aktivní rezervace"
|
||||
value={isLoading ? "—" : activeReservationCount}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Below minimum alert */}
|
||||
{belowMin.length > 0 && (
|
||||
<motion.div
|
||||
className="admin-card admin-card-danger"
|
||||
<Box
|
||||
component={motion.div}
|
||||
initial={{ opacity: 0, y: 12 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{
|
||||
duration: reducedMotion ? 0 : 0.25,
|
||||
delay: reducedMotion ? 0 : 0.14,
|
||||
}}
|
||||
transition={{ duration: 0.25, delay: 0.14 }}
|
||||
sx={{ mb: 3 }}
|
||||
>
|
||||
<div className="admin-card-header flex-between">
|
||||
<h2 className="admin-card-title" style={{ color: "var(--danger)" }}>
|
||||
Položky pod minimem
|
||||
</h2>
|
||||
<Link
|
||||
to="/warehouse/reports"
|
||||
className="admin-btn admin-btn-primary admin-btn-sm"
|
||||
<Card sx={{ borderColor: "error.main", borderWidth: 1 }}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
gap: 2,
|
||||
flexWrap: "wrap",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
Reporty →
|
||||
</Link>
|
||||
</div>
|
||||
<div className="admin-card-body">
|
||||
<div className="admin-table-responsive">
|
||||
<table className="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Název</th>
|
||||
<th>K dispozici</th>
|
||||
<th>Min. množství</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{belowMin.map((item) => (
|
||||
<tr key={item.id} className="admin-warehouse-row-danger">
|
||||
<td className="fw-500">{item.name}</td>
|
||||
<td className="admin-mono admin-warehouse-danger-value">
|
||||
{item.available_quantity ?? 0}
|
||||
</td>
|
||||
<td className="admin-mono">{item.min_quantity ?? 0}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
<Typography variant="h6" sx={{ color: "error.main" }}>
|
||||
Položky pod minimem
|
||||
</Typography>
|
||||
<Button
|
||||
component={RouterLink}
|
||||
to="/warehouse/reports"
|
||||
size="small"
|
||||
sx={{ flexShrink: 0 }}
|
||||
>
|
||||
Reporty →
|
||||
</Button>
|
||||
</Box>
|
||||
<DataTable<BelowMinRow>
|
||||
columns={belowMinColumns}
|
||||
rows={belowMin.map((item) => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
available_quantity: item.available_quantity ?? 0,
|
||||
min_quantity: item.min_quantity ?? 0,
|
||||
}))}
|
||||
rowKey={(item) => item.id}
|
||||
rowDanger={() => true}
|
||||
/>
|
||||
</Card>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Recent movements */}
|
||||
<motion.div
|
||||
className="admin-card"
|
||||
<Box
|
||||
component={motion.div}
|
||||
initial={{ opacity: 0, y: 12 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{
|
||||
duration: reducedMotion ? 0 : 0.25,
|
||||
delay: reducedMotion ? 0 : 0.16,
|
||||
}}
|
||||
transition={{ duration: 0.25, delay: 0.16 }}
|
||||
>
|
||||
<div className="admin-card-header flex-between">
|
||||
<h2 className="admin-card-title">Poslední pohyby</h2>
|
||||
<Link
|
||||
to="/warehouse/reports"
|
||||
className="admin-btn admin-btn-primary admin-btn-sm"
|
||||
<Card>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
gap: 2,
|
||||
flexWrap: "wrap",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
Vše →
|
||||
</Link>
|
||||
</div>
|
||||
<div className="admin-card-body">
|
||||
<Typography variant="h6">Poslední pohyby</Typography>
|
||||
<Button
|
||||
component={RouterLink}
|
||||
to="/warehouse/reports"
|
||||
size="small"
|
||||
sx={{ flexShrink: 0 }}
|
||||
>
|
||||
Vše →
|
||||
</Button>
|
||||
</Box>
|
||||
{movementsLoading ? (
|
||||
<div className="admin-loading">
|
||||
<div className="admin-spinner" />
|
||||
</div>
|
||||
) : recentMovements.length === 0 ? (
|
||||
<div className="admin-empty-state">Žádné nedávné pohyby</div>
|
||||
<LoadingState />
|
||||
) : (
|
||||
<div className="admin-table-responsive">
|
||||
<table className="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Typ</th>
|
||||
<th>Doklad</th>
|
||||
<th>Položka</th>
|
||||
<th>Množství</th>
|
||||
<th>Dodavatel / Projekt</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{recentMovements.map((row, i) => (
|
||||
<tr key={i}>
|
||||
<td className="admin-mono">{formatDate(row.date)}</td>
|
||||
<td>
|
||||
<span
|
||||
className={`admin-badge ${TYPE_TONE[row.type] ?? ""}`}
|
||||
>
|
||||
{TYPE_LABEL[row.type] ?? row.type}
|
||||
</span>
|
||||
</td>
|
||||
<td className="admin-mono">
|
||||
{row.document_number || "—"}
|
||||
</td>
|
||||
<td className="fw-500">{row.item_name}</td>
|
||||
<td className="admin-mono">{row.quantity}</td>
|
||||
<td>{row.supplier_or_project || "—"}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<DataTable<MovementRow>
|
||||
columns={movementColumns}
|
||||
rows={recentMovements.map((row, i) => ({ ...row, _idx: i }))}
|
||||
rowKey={(row) => row._idx}
|
||||
empty={<EmptyState title="Žádné nedávné pohyby" />}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</Card>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user