import { Link as RouterLink } from "react-router-dom";
import Box from "@mui/material/Box";
import IconButton from "@mui/material/IconButton";
import {
formatDate,
formatDatetime,
formatTime,
calculateWorkMinutes,
formatMinutes,
getLeaveTypeName,
} from "../utils/attendanceHelpers";
import { DataTable, StatusChip, EmptyState, type DataColumn } from "../ui";
import type { AttendanceRecord as HookAttendanceRecord } from "../hooks/useAttendanceAdmin";
interface AttendanceRecord extends HookAttendanceRecord {
arrival_lat?: number | string | null;
arrival_lng?: number | string | null;
departure_lat?: number | string | null;
departure_lng?: number | string | null;
}
interface AttendanceShiftTableProps {
records: AttendanceRecord[];
onEdit: (record: AttendanceRecord) => void;
onDelete: (record: AttendanceRecord) => void;
}
const EditIcon = (
);
const DeleteIcon = (
);
/** Map an attendance leave_type to a StatusChip semantic color (mirrors the
* legacy getLeaveTypeBadgeClass colors): work→info, vacation→info(blue),
* sick→error(red), unpaid→default(gray). */
function leaveTypeChipColor(
type: string,
): "default" | "success" | "error" | "warning" | "info" {
switch (type) {
case "vacation":
return "info";
case "sick":
return "error";
case "unpaid":
return "default";
default:
return "info";
}
}
function formatBreak(record: AttendanceRecord): string {
if (record.break_start && record.break_end) {
return `${formatTime(record.break_start)} - ${formatTime(record.break_end)}`;
}
if (record.break_start) {
return `${formatTime(record.break_start)} - ?`;
}
return "—";
}
function renderProjectCell(record: AttendanceRecord): React.ReactNode {
if (record.project_logs && record.project_logs.length > 0) {
return (
{record.project_logs.map((log, i) => {
let h: number,
m: number,
isActive = false;
let durationValid = true;
if (log.hours !== null && log.hours !== undefined) {
h = parseInt(String(log.hours)) || 0;
m = parseInt(String(log.minutes)) || 0;
} else {
isActive = !log.ended_at;
const end = log.ended_at ? new Date(log.ended_at) : new Date();
const start = log.started_at ? new Date(log.started_at) : null;
if (start && !isNaN(start.getTime()) && !isNaN(end.getTime())) {
const mins = Math.max(
0,
Math.floor((end.getTime() - start.getTime()) / 60000),
);
h = Math.floor(mins / 60);
m = mins % 60;
} else {
durationValid = false;
h = 0;
m = 0;
}
}
return (
);
})}
);
}
if (record.project_name) {
return (
);
}
return "—";
}
export default function AttendanceShiftTable({
records,
onEdit,
onDelete,
}: AttendanceShiftTableProps) {
const columns: DataColumn[] = [
{
key: "date",
header: "Datum",
width: "9%",
mono: true,
render: (record) => formatDate(record.shift_date),
},
{
key: "user",
header: "Zaměstnanec",
width: "14%",
render: (record) => record.user_name,
},
{
key: "type",
header: "Typ",
width: "10%",
render: (record) => {
const leaveType = record.leave_type || "work";
return (
);
},
},
{
key: "arrival",
header: "Příchod",
width: "9%",
mono: true,
render: (record) => {
const isLeave = (record.leave_type || "work") !== "work";
return isLeave ? "—" : formatDatetime(record.arrival_time);
},
},
{
key: "break",
header: "Pauza",
width: "10%",
mono: true,
render: (record) => {
const isLeave = (record.leave_type || "work") !== "work";
return isLeave ? "—" : formatBreak(record);
},
},
{
key: "departure",
header: "Odchod",
width: "9%",
mono: true,
render: (record) => {
const isLeave = (record.leave_type || "work") !== "work";
return isLeave ? "—" : formatDatetime(record.departure_time);
},
},
{
key: "hours",
header: "Hodiny",
width: "9%",
mono: true,
render: (record) => {
const leaveType = record.leave_type || "work";
const isLeave = leaveType !== "work";
const workMinutes = isLeave
? (record.leave_hours != null ? Number(record.leave_hours) : 8) * 60
: calculateWorkMinutes({
...record,
notes: record.notes ?? undefined,
});
return workMinutes > 0 ? `${formatMinutes(workMinutes)} h` : "—";
},
},
{
key: "project",
header: "Projekt",
width: "13%",
render: (record) => renderProjectCell(record),
},
{
key: "gps",
header: "GPS",
width: "5%",
render: (record) => {
const hasLocation =
(record.arrival_lat && record.arrival_lng) ||
(record.departure_lat && record.departure_lng);
return hasLocation ? (
{"📍"}
) : (
"—"
);
},
},
{
key: "notes",
header: "Poznámka",
width: "9%",
render: (record) => (
{record.notes || ""}
),
},
{
key: "actions",
header: "Akce",
width: "8%",
align: "right",
render: (record) => (
onEdit(record)}
aria-label="Upravit"
title="Upravit"
>
{EditIcon}
onDelete(record)}
aria-label="Smazat"
title="Smazat"
>
{DeleteIcon}
),
},
];
return (
columns={columns}
rows={records}
rowKey={(record) => record.id}
empty={}
/>
);
}