pmtool / src /components /leaves /LeaveDetail.tsx
devarshia5's picture
Upload 487 files
d97b8f9 verified
Raw
History Blame Contribute Delete
6.8 kB
import React from "react";
import { format, differenceInCalendarDays } from "date-fns";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogFooter,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Leave, LeaveStatus } from "@/types";
import { Employee } from "@/services/employeeApi";
import {
Calendar,
Clock,
FileText,
User,
CheckCircle,
XCircle,
AlertCircle,
File,
Download,
} from "lucide-react";
// Helper function to get badge variant based on leave status
const getStatusBadgeVariant = (status: LeaveStatus) => {
switch (status) {
case "Approved":
return "success";
case "Rejected":
return "destructive";
case "Cancelled":
return "outline";
case "Pending":
default:
return "warning";
}
};
// Helper function to get status icon based on leave status
const getStatusIcon = (status: LeaveStatus) => {
switch (status) {
case "Approved":
return <CheckCircle className="h-4 w-4" />;
case "Rejected":
return <XCircle className="h-4 w-4" />;
case "Cancelled":
return <AlertCircle className="h-4 w-4" />;
case "Pending":
default:
return <Clock className="h-4 w-4" />;
}
};
interface LeaveDetailProps {
leave: Leave | null;
employee?: Employee | null;
approver?: Employee | null;
isOpen: boolean;
onOpenChange: (open: boolean) => void;
onDownloadDocument?: (leave: Leave) => void;
}
const LeaveDetail: React.FC<LeaveDetailProps> = ({
leave,
employee,
approver,
isOpen,
onOpenChange,
onDownloadDocument,
}) => {
if (!leave) return null;
const startDate = new Date(leave.startDate);
const endDate = new Date(leave.endDate);
const durationDays = differenceInCalendarDays(endDate, startDate) + 1;
return (
<Dialog open={isOpen} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[550px]">
<DialogHeader>
<DialogTitle className="flex items-center justify-between">
<span>{leave.type} Leave Request</span>
<Badge
variant={getStatusBadgeVariant(leave.status) as any}
className="flex items-center gap-1"
>
{getStatusIcon(leave.status)}
<span>{leave.status}</span>
</Badge>
</DialogTitle>
<DialogDescription>
Leave request details and status
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
{employee && (
<div className="grid grid-cols-4 items-center gap-4">
<div className="font-medium">Employee:</div>
<div className="col-span-3 flex items-center gap-2">
<User className="h-4 w-4" />
<span>
{employee.firstName} {employee.lastName} (ID: {employee.id})
</span>
</div>
</div>
)}
<div className="grid grid-cols-4 items-center gap-4">
<div className="font-medium">Duration:</div>
<div className="col-span-3 flex items-center gap-2">
<Calendar className="h-4 w-4" />
<span>
{format(startDate, "PPP")} to {format(endDate, "PPP")}
<span className="ml-1 text-xs text-muted-foreground">
({durationDays} {durationDays === 1 ? "day" : "days"})
</span>
</span>
</div>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<div className="font-medium">Applied On:</div>
<div className="col-span-3 flex items-center gap-2">
<Clock className="h-4 w-4" />
<span>{format(new Date(leave.appliedOn), "PPP")}</span>
</div>
</div>
<div className="grid grid-cols-4 items-start gap-4">
<div className="font-medium">Reason:</div>
<div className="col-span-3 flex items-start gap-2">
<FileText className="h-4 w-4 mt-0.5" />
<span>{leave.reason}</span>
</div>
</div>
{(leave.status === "Approved" || leave.status === "Rejected") && (
<>
{approver && (
<div className="grid grid-cols-4 items-center gap-4">
<div className="font-medium">Actioned By:</div>
<div className="col-span-3 flex items-center gap-2">
<User className="h-4 w-4" />
<span>
{approver.firstName} {approver.lastName}
</span>
</div>
</div>
)}
{leave.actionDate && (
<div className="grid grid-cols-4 items-center gap-4">
<div className="font-medium">Action Date:</div>
<div className="col-span-3 flex items-center gap-2">
<Clock className="h-4 w-4" />
<span>{format(new Date(leave.actionDate), "PPP")}</span>
</div>
</div>
)}
{leave.comments && (
<div className="grid grid-cols-4 items-start gap-4">
<div className="font-medium">Comments:</div>
<div className="col-span-3 flex items-start gap-2">
<FileText className="h-4 w-4 mt-0.5" />
<span>{leave.comments}</span>
</div>
</div>
)}
</>
)}
{leave.documents && (
<div className="grid grid-cols-4 items-center gap-4">
<div className="font-medium">Documents:</div>
<div className="col-span-3">
<Button
variant="outline"
size="sm"
className="flex items-center gap-2"
onClick={() => onDownloadDocument && onDownloadDocument(leave)}
>
<File className="h-4 w-4" />
<span>View Document</span>
<Download className="h-4 w-4 ml-1" />
</Button>
</div>
</div>
)}
</div>
<DialogFooter>
<Button type="button" onClick={() => onOpenChange(false)}>
Close
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
};
export default LeaveDetail;