import { useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { useAlert } from "../context/AlertContext"; import { useAuth } from "../context/AuthContext"; import Box from "@mui/material/Box"; import Forbidden from "../components/Forbidden"; import { formatDate, formatDatetime } from "../utils/attendanceHelpers"; import { leaveRequestsOptions, type LeaveRequest } from "../lib/queries/leave"; import { useApiMutation } from "../lib/queries/mutations"; import { Button, Card, DataTable, ConfirmDialog, StatusChip, PageHeader, PageEnter, EmptyState, LoadingState, type DataColumn, } from "../ui"; const API_BASE = "/api/admin"; const leaveTypeLabels: Record = { vacation: "Dovolená", sick: "Nemoc", unpaid: "Neplacené volno", }; const statusLabels: Record = { pending: "Čeká na schválení", approved: "Schváleno", rejected: "Zamítnuto", cancelled: "Zrušeno", }; // Leave type → StatusChip color const leaveTypeColor: Record< string, "info" | "error" | "default" | "success" | "warning" > = { vacation: "info", sick: "error", unpaid: "default", }; // Status → StatusChip color const statusColor: Record = { pending: "warning", approved: "success", rejected: "error", cancelled: "default", }; const CancelIcon = ( ); export default function LeaveRequests() { const alert = useAlert(); const { hasPermission } = useAuth(); const { data: requests = [], isPending } = useQuery( leaveRequestsOptions(true), ); const [cancelModal, setCancelModal] = useState<{ open: boolean; id: number | null; }>({ open: false, id: null }); const cancelMutation = useApiMutation< { id: number }, { message?: string; error?: string } >({ url: ({ id }) => `${API_BASE}/leave-requests/${id}`, method: () => "DELETE", invalidate: ["leave-requests", "leave", "attendance", "users", "dashboard"], onSuccess: (data) => { setCancelModal({ open: false, id: null }); alert.success(data?.message || "Žádost byla zrušena"); }, }); if (!hasPermission("attendance.record")) return ; const handleCancel = async () => { if (!cancelModal.id) return; try { await cancelMutation.mutateAsync({ id: cancelModal.id }); } catch (e) { alert.error(e instanceof Error ? e.message : "Chyba připojení"); } }; if (isPending) { return ; } const columns: DataColumn[] = [ { key: "leave_type", header: "Typ", width: "14%", render: (req) => ( ), }, { key: "date_from", header: "Od", width: "11%", mono: true, render: (req) => formatDate(req.date_from), }, { key: "date_to", header: "Do", width: "11%", mono: true, render: (req) => formatDate(req.date_to), }, { key: "total_days", header: "Dny", width: "7%", mono: true, render: (req) => String(req.total_days), }, { key: "total_hours", header: "Hodiny", width: "8%", mono: true, render: (req) => `${req.total_hours}h`, }, { key: "status", header: "Stav", width: "16%", render: (req) => ( ), }, { key: "notes", header: "Poznámka", width: "20%", render: (req) => { const truncate = (text: string) => text.length > 40 ? `${text.substring(0, 40)}...` : text; if (req.status === "rejected" && req.reviewer_note) { return ( {truncate(req.reviewer_note)} ); } if (req.notes) { return ( {truncate(req.notes)} ); } return ( ); }, }, { key: "created_at", header: "Podáno", width: "13%", mono: true, render: (req) => formatDatetime(req.created_at), }, { key: "actions", header: "Akce", width: "8%", align: "right", render: (req) => req.status === "pending" ? ( ) : null, }, ]; return ( columns={columns} rows={requests} rowKey={(req) => req.id} empty={ } /> setCancelModal({ open: false, id: null })} onConfirm={handleCancel} title="Zrušit žádost" message="Opravdu chcete zrušit tuto žádost o nepřítomnost?" confirmText="Zrušit žádost" loading={cancelMutation.isPending} /> ); }