Spaces:
Sleeping
Sleeping
| import React from "react"; | |
| import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; | |
| import { Badge } from "@/components/ui/badge"; | |
| import { Button } from "@/components/ui/button"; | |
| import { | |
| Calendar, | |
| Clock, | |
| FileText, | |
| User, | |
| CheckCircle, | |
| XCircle, | |
| AlertCircle | |
| } from "lucide-react"; | |
| import { Leave, LeaveStatus } from "@/types"; | |
| import { format, differenceInCalendarDays } from "date-fns"; | |
| // 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 LeaveCardProps { | |
| leave: Leave; | |
| employeeName?: string; | |
| leaveType?: string; | |
| isAdmin?: boolean; | |
| onViewDetails?: (leave: Leave) => void; | |
| onApprove?: (leave: Leave) => void; | |
| onReject?: (leave: Leave) => void; | |
| onCancel?: (leave: Leave) => void; | |
| } | |
| const LeaveCard: React.FC<LeaveCardProps> = ({ | |
| leave, | |
| employeeName, | |
| leaveType, | |
| isAdmin = false, | |
| onViewDetails, | |
| onApprove, | |
| onReject, | |
| onCancel, | |
| }) => { | |
| const startDate = new Date(leave.startDate); | |
| const endDate = new Date(leave.endDate); | |
| const durationDays = leave.workingDays || (differenceInCalendarDays(endDate, startDate) + 1); | |
| return ( | |
| <Card className="w-full"> | |
| <CardHeader className="pb-2"> | |
| <div className="flex justify-between items-start"> | |
| <CardTitle className="text-lg font-semibold"> | |
| {leave.compOff | |
| ? "Comp Off Request" | |
| : (leaveType || leave.type) === "Work From Home" | |
| ? "Work From Home Request" | |
| : `${leaveType || leave.type} Leave`} | |
| </CardTitle> | |
| <Badge variant={getStatusBadgeVariant(leave.status) as any} className="flex items-center gap-1"> | |
| {getStatusIcon(leave.status)} | |
| <span>{leave.status}</span> | |
| </Badge> | |
| </div> | |
| </CardHeader> | |
| <CardContent className="pb-2"> | |
| <div className="space-y-3"> | |
| {employeeName && isAdmin && ( | |
| <div className="flex items-center text-sm"> | |
| <User className="h-4 w-4 mr-2 opacity-70" /> | |
| <span>{employeeName}</span> | |
| </div> | |
| )} | |
| <div className="flex items-center text-sm"> | |
| <Calendar className="h-4 w-4 mr-2 opacity-70" /> | |
| <span> | |
| {format(startDate, "PP")} - {format(endDate, "PP")} | |
| <span className="ml-1 text-xs text-muted-foreground"> | |
| ({durationDays} {durationDays === 1 ? "day" : "days"}) | |
| </span> | |
| </span> | |
| </div> | |
| <div className="flex items-start text-sm"> | |
| <FileText className="h-4 w-4 mr-2 mt-0.5 opacity-70 flex-shrink-0" /> | |
| <span className="line-clamp-2">{leave.reason}</span> | |
| </div> | |
| {leave.actionDate && ( | |
| <div className="flex items-center text-xs text-muted-foreground"> | |
| <Clock className="h-3 w-3 mr-1 opacity-70" /> | |
| <span> | |
| {leave.status === "Approved" ? "Approved" : | |
| leave.status === "Rejected" ? "Rejected" : | |
| "Updated"} on {format(new Date(leave.actionDate), "PP")} | |
| </span> | |
| </div> | |
| )} | |
| </div> | |
| </CardContent> | |
| <CardFooter className="pt-1"> | |
| <div className="flex justify-end w-full gap-2"> | |
| {onViewDetails && ( | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={() => onViewDetails(leave)} | |
| > | |
| Details | |
| </Button> | |
| )} | |
| {isAdmin && leave.status === "Pending" && onApprove && ( | |
| <Button | |
| variant="default" | |
| size="sm" | |
| onClick={() => onApprove(leave)} | |
| > | |
| Approve | |
| </Button> | |
| )} | |
| {isAdmin && leave.status === "Pending" && onReject && ( | |
| <Button | |
| variant="destructive" | |
| size="sm" | |
| onClick={() => onReject(leave)} | |
| > | |
| Reject | |
| </Button> | |
| )} | |
| {isAdmin && leave.status === "Approved" && onCancel && ( | |
| <Button | |
| variant="destructive" | |
| size="sm" | |
| onClick={() => onCancel(leave)} | |
| > | |
| Cancel Approved | |
| </Button> | |
| )} | |
| {!isAdmin && leave.status === "Pending" && onCancel && ( | |
| <Button | |
| variant="destructive" | |
| size="sm" | |
| onClick={() => onCancel(leave)} | |
| > | |
| Cancel | |
| </Button> | |
| )} | |
| </div> | |
| </CardFooter> | |
| </Card> | |
| ); | |
| }; | |
| export default LeaveCard; |