Spaces:
Sleeping
Sleeping
| import React from "react"; | |
| import { format, differenceInCalendarDays } from "date-fns"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Badge } from "@/components/ui/badge"; | |
| import { Leave, LeaveStatus } from "@/types"; | |
| import { Employee } from "@/services/employeeApi"; | |
| import CustomDialog from "@/components/CustomDialog"; | |
| 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 CustomLeaveDetailDialogProps { | |
| leave: Leave | null; | |
| employee?: Employee | null; | |
| approver?: Employee | null; | |
| isOpen: boolean; | |
| onClose: () => void; | |
| onDownloadDocument?: (leave: Leave) => void; | |
| } | |
| const CustomLeaveDetailDialog: React.FC<CustomLeaveDetailDialogProps> = ({ | |
| leave, | |
| employee, | |
| approver, | |
| isOpen, | |
| onClose, | |
| onDownloadDocument, | |
| }) => { | |
| if (!leave) return null; | |
| const startDate = new Date(leave.startDate); | |
| const endDate = new Date(leave.endDate); | |
| const durationDays = leave.workingDays || (differenceInCalendarDays(endDate, startDate) + 1); | |
| return ( | |
| <CustomDialog | |
| isOpen={isOpen} | |
| onClose={onClose} | |
| title={leave.compOff ? "Comp Off Request" : `${leave.type || 'Leave'} Request`} | |
| description="Leave request details and status" | |
| > | |
| <div className="flex items-center justify-between mb-4"> | |
| <h3 className="text-lg font-semibold">{leave.compOff ? "Comp Off" : leave.type || 'Leave'} Details</h3> | |
| <Badge | |
| variant={getStatusBadgeVariant(leave.status) as any} | |
| className="flex items-center gap-1" | |
| > | |
| {getStatusIcon(leave.status)} | |
| <span>{leave.status}</span> | |
| </Badge> | |
| </div> | |
| <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> | |
| <div className="flex justify-end pt-4 border-t mt-4"> | |
| <Button onClick={onClose}>Close</Button> | |
| </div> | |
| </CustomDialog> | |
| ); | |
| }; | |
| export default CustomLeaveDetailDialog; |