feat(mui): migrate Dashboard (Přehled) onto MUI kit

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-07 01:19:49 +02:00
parent 5ca03bd662
commit 5459d8c325
7 changed files with 1205 additions and 968 deletions

View File

@@ -1,9 +1,9 @@
import { Link } from "react-router-dom";
import {
LEAVE_TYPE_LABELS,
STATUS_DOT_CLASS,
STATUS_LABELS,
} from "../../utils/dashboardHelpers";
import { Link as RouterLink } from "react-router-dom";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Avatar from "@mui/material/Avatar";
import { Card, Button, StatusChip, EmptyState } from "../../ui";
import { LEAVE_TYPE_LABELS, STATUS_LABELS } from "../../utils/dashboardHelpers";
interface AttendanceUser {
user_id: number | string;
@@ -22,6 +22,19 @@ interface DashAttendanceTodayProps {
attendance: AttendanceData | null;
}
// Maps the attendance status to the StatusChip / avatar tint color.
// Mirrors the legacy dash-status-* dot classes: in→success, away→warning,
// out→default, leave→error.
const STATUS_COLOR: Record<
string,
"default" | "success" | "warning" | "error"
> = {
in: "success",
away: "warning",
out: "default",
leave: "error",
};
export default function DashAttendanceToday({
attendance,
}: DashAttendanceTodayProps) {
@@ -30,42 +43,96 @@ export default function DashAttendanceToday({
}
return (
<div className="admin-card dash-attendance-card">
<div className="admin-card-header flex-between">
<h2 className="admin-card-title">Docházka dnes</h2>
<Link
<Card sx={{ display: "flex", flexDirection: "column" }}>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
mb: 2,
}}
>
<Typography variant="h6">Docházka dnes</Typography>
<Button
component={RouterLink}
to="/attendance/admin"
className="admin-btn admin-btn-primary admin-btn-sm"
size="small"
sx={{ flexShrink: 0 }}
>
Detail &rarr;
</Link>
</div>
<div className="admin-card-body" style={{ padding: 0 }}>
{attendance.users.map((u, i) => (
<div key={`${u.user_id}-${i}`} className="dash-presence-row">
<div
className={`dash-presence-avatar ${STATUS_DOT_CLASS[u.status]}`}
>
{u.initials || "?"}
</div>
<div className="dash-presence-name">{u.name}</div>
<div className="dash-presence-end">
<span
className={`dash-presence-label ${STATUS_DOT_CLASS[u.status]}`}
</Button>
</Box>
{attendance.users.length === 0 ? (
<EmptyState title="Žádná docházka" />
) : (
<Box sx={{ display: "flex", flexDirection: "column" }}>
{attendance.users.map((u, i) => {
const color = STATUS_COLOR[u.status] ?? "default";
const isDefault = color === "default";
return (
<Box
key={`${u.user_id}-${i}`}
sx={{
display: "flex",
alignItems: "center",
gap: 1.5,
py: 1.25,
borderBottom: 1,
borderColor: "divider",
"&:last-of-type": { borderBottom: 0 },
}}
>
{u.status === "leave"
? LEAVE_TYPE_LABELS[u.leave_type || ""] || "Nepřítomen"
: STATUS_LABELS[u.status]}
</span>
{u.arrived_at && (
<span className="admin-mono dash-presence-time">
{u.arrived_at}
</span>
)}
</div>
</div>
))}
</div>
</div>
<Avatar
sx={{
width: 36,
height: 36,
fontSize: "0.8rem",
fontWeight: 700,
bgcolor: isDefault ? "action.hover" : `${color}.light`,
color: isDefault ? "text.secondary" : `${color}.main`,
}}
>
{u.initials || "?"}
</Avatar>
<Typography
variant="body2"
sx={{ fontWeight: 500, flex: 1, minWidth: 0 }}
noWrap
>
{u.name}
</Typography>
<Box
sx={{
display: "flex",
alignItems: "center",
gap: 1,
flexShrink: 0,
}}
>
<StatusChip
color={color}
label={
u.status === "leave"
? LEAVE_TYPE_LABELS[u.leave_type || ""] || "Nepřítomen"
: STATUS_LABELS[u.status]
}
/>
{u.arrived_at && (
<Typography
variant="caption"
color="text.secondary"
sx={{ fontFamily: "'DM Mono', Menlo, monospace" }}
>
{u.arrived_at}
</Typography>
)}
</Box>
</Box>
);
})}
</Box>
)}
</Card>
);
}