feat(mui): consistent staggered page entrance across all 43 route pages

Adopt the PageEnter wrapper as every page's outermost render element and remove the ad-hoc per-page entrance motion.div wrappers. Every page now enters the same way — all top-level sections rise+fade in, staggered — so nothing appears instantly and the motion is identical app-wide. Presentation-only: no data/logic/hooks/invalidate/permissions touched. Embedded sub-tabs (CompanySettings, ReceivedInvoices), Login (auth shell) and the dev UiKit are intentionally excluded. Gates: tsc -b --noEmit=0, build=0, vitest 152/152.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-07 10:13:06 +02:00
parent b273614128
commit 39fe84ce99
43 changed files with 4956 additions and 5709 deletions

View File

@@ -3,7 +3,6 @@ import { useQuery } from "@tanstack/react-query";
import { useAlert } from "../context/AlertContext";
import { useAuth } from "../context/AuthContext";
import { Navigate, useSearchParams } from "react-router-dom";
import { motion } from "framer-motion";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import IconButton from "@mui/material/IconButton";
@@ -27,6 +26,7 @@ import {
Tabs,
TabPanel,
LoadingState,
PageEnter,
type DataColumn,
type TabDef,
} from "../ui";
@@ -780,23 +780,17 @@ export default function Settings() {
};
return (
<Box>
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25 }}
>
<Box sx={{ mb: 3 }}>
<Typography variant="h4">Nastavení</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mt: 0.5 }}>
{activeTab === "system"
? "Systémová nastavení"
: activeTab === "firma"
? "Informace o firmě"
: "Role"}
</Typography>
</Box>
</motion.div>
<PageEnter>
<Box sx={{ mb: 3 }}>
<Typography variant="h4">Nastavení</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mt: 0.5 }}>
{activeTab === "system"
? "Systémová nastavení"
: activeTab === "firma"
? "Informace o firmě"
: "Role"}
</Typography>
</Box>
{tabDefs.length > 0 && (
<Tabs
@@ -808,43 +802,32 @@ export default function Settings() {
{/* Roles tab */}
<TabPanel value="roles" current={activeTab}>
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25, delay: 0.06 }}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
mb: 2,
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
mb: 2,
}}
>
<Typography variant="h6">Role</Typography>
<Button startIcon={PlusIcon} size="small" onClick={openCreateModal}>
Přidat roli
</Button>
</Box>
<Card>
<DataTable<Role>
columns={roleColumns}
rows={roles}
rowKey={(role) => role.id}
/>
</Card>
</motion.div>
<Typography variant="h6">Role</Typography>
<Button startIcon={PlusIcon} size="small" onClick={openCreateModal}>
Přidat roli
</Button>
</Box>
<Card>
<DataTable<Role>
columns={roleColumns}
rows={roles}
rowKey={(role) => role.id}
/>
</Card>
</TabPanel>
{/* System settings tab */}
<TabPanel value="system" current={activeTab}>
{canManageSystem && (
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25, delay: 0.06 }}
style={{ marginBottom: "1.5rem" }}
>
<Box sx={{ mb: "1.5rem" }}>
<Card>
<Typography variant="h6" sx={{ mb: 2 }}>
Zabezpečení
@@ -908,16 +891,11 @@ export default function Settings() {
)}
</Box>
</Card>
</motion.div>
</Box>
)}
{canManageSystem && (
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25, delay: 0.08 }}
style={{ marginBottom: "1.5rem" }}
>
<Box sx={{ mb: "1.5rem" }}>
<Card>
<Typography variant="h6" sx={{ mb: 2 }}>
Přihlašování
@@ -968,7 +946,7 @@ export default function Settings() {
</Button>
</Box>
</Card>
</motion.div>
</Box>
)}
{sysSettingsLoading && !sysFormInitialized ? (
@@ -976,12 +954,7 @@ export default function Settings() {
) : (
<>
{/* Section 1: Docházka */}
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25, delay: 0.06 }}
style={{ marginBottom: "1.5rem" }}
>
<Box sx={{ mb: "1.5rem" }}>
<Card>
<Typography variant="h6" sx={{ mb: 2 }}>
Docházka
@@ -1051,15 +1024,10 @@ export default function Settings() {
</Field>
</Box>
</Card>
</motion.div>
</Box>
{/* Section 2: Emailové notifikace */}
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25, delay: 0.12 }}
style={{ marginBottom: "1.5rem" }}
>
<Box sx={{ mb: "1.5rem" }}>
<Card>
<Typography variant="h6" sx={{ mb: 2 }}>
Emailové notifikace
@@ -1124,15 +1092,10 @@ export default function Settings() {
</Field>
</Box>
</Card>
</motion.div>
</Box>
{/* Section 4: Omezení požadavků */}
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25, delay: 0.24 }}
style={{ marginBottom: "1.5rem" }}
>
<Box sx={{ mb: "1.5rem" }}>
<Card>
<Typography variant="h6" sx={{ mb: 2 }}>
Omezení požadavků
@@ -1154,39 +1117,26 @@ export default function Settings() {
/>
</Field>
</Card>
</motion.div>
</Box>
{/* Section 5: Informace o aplikaci */}
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25, delay: 0.36 }}
style={{ marginBottom: "1.5rem" }}
>
<Box sx={{ mb: "1.5rem" }}>
<Card>
<Typography variant="h6" sx={{ mb: 2 }}>
Informace o aplikaci
</Typography>
{renderSystemInfo()}
</Card>
</motion.div>
</Box>
{/* Save button */}
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25, delay: 0.42 }}
<Button
fullWidth
onClick={handleSaveSystemSettings}
disabled={saveSystemSettingsMutation.isPending}
>
<Button
fullWidth
onClick={handleSaveSystemSettings}
disabled={saveSystemSettingsMutation.isPending}
>
{saveSystemSettingsMutation.isPending
? "Ukládání..."
: "Uložit"}
</Button>
</motion.div>
{saveSystemSettingsMutation.isPending ? "Ukládání..." : "Uložit"}
</Button>
</>
)}
</TabPanel>
@@ -1399,6 +1349,6 @@ export default function Settings() {
confirmVariant="danger"
loading={deleteRoleMutation.isPending}
/>
</Box>
</PageEnter>
);
}