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={} /> ); }