Spaces:
Sleeping
Sleeping
| import React from "react"; | |
| import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; | |
| import { Progress } from "@/components/ui/progress"; | |
| import { LeaveBalance as LeaveBalanceType } from "@/types"; | |
| import { cn } from "@/lib/utils"; | |
| import { Loader2 } from "lucide-react"; | |
| interface LeaveBalanceDisplayProps { | |
| balances: LeaveBalanceType[]; | |
| year: number; | |
| isLoading?: boolean; | |
| } | |
| const LeaveBalance: React.FC<LeaveBalanceDisplayProps> = ({ | |
| balances, | |
| year, | |
| isLoading = false, | |
| }) => { | |
| // Function to calculate percentage used | |
| const calculatePercentage = (used: number, total: number) => { | |
| if (total === 0) return 0; | |
| return Math.min((used / total) * 100, 100); // Cap at 100% | |
| }; | |
| // Map leave master IDs to types and colors | |
| const leaveTypeMap: Record<number, { label: string, color: string }> = { | |
| 4: { label: "Annual Leave", color: "bg-blue-500" }, | |
| 5: { label: "Sick Leave", color: "bg-red-500" }, | |
| 6: { label: "Personal Leave", color: "bg-green-500" }, | |
| 7: { label: "Unpaid Leave", color: "bg-gray-500" }, | |
| 8: { label: "Maternity Leave", color: "bg-pink-500" }, | |
| 9: { label: "Paternity Leave", color: "bg-purple-500" }, | |
| 10: { label: "Compensatory Leave", color: "bg-orange-500" }, | |
| 11: { label: "Bereavement Leave", color: "bg-slate-500" }, | |
| 13: { label: "Half Day Leave", color: "bg-amber-500" }, | |
| }; | |
| if (isLoading) { | |
| return ( | |
| <Card className="w-full"> | |
| <CardHeader> | |
| <CardTitle className="text-lg">Leave Balance ({year})</CardTitle> | |
| </CardHeader> | |
| <CardContent> | |
| <div className="flex items-center justify-center py-6"> | |
| <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" /> | |
| </div> | |
| </CardContent> | |
| </Card> | |
| ); | |
| } | |
| if (!balances || balances.length === 0) { | |
| return ( | |
| <Card className="w-full"> | |
| <CardHeader> | |
| <CardTitle className="text-lg">Leave Balance ({year})</CardTitle> | |
| </CardHeader> | |
| <CardContent> | |
| <p className="text-center text-muted-foreground py-6"> | |
| No leave balance information available | |
| </p> | |
| </CardContent> | |
| </Card> | |
| ); | |
| } | |
| return ( | |
| <Card className="w-full"> | |
| <CardHeader> | |
| <CardTitle className="text-lg">Leave Balance ({year})</CardTitle> | |
| </CardHeader> | |
| <CardContent> | |
| <div className="space-y-4"> | |
| {balances.map((balance) => { | |
| const typeInfo = leaveTypeMap[balance.leavesMasterId] || | |
| { label: `Leave Type ${balance.leavesMasterId}`, color: "bg-gray-500" }; | |
| const percentage = calculatePercentage(balance.used, balance.allocated); | |
| const remaining = balance.pending; | |
| return ( | |
| <div key={balance.id} className="space-y-1"> | |
| <div className="flex justify-between text-sm"> | |
| <span>{typeInfo.label}</span> | |
| {balance.allocated === 0 ? ( | |
| <span>Unlimited</span> | |
| ) : ( | |
| <span className="font-medium"> | |
| {remaining} of {balance.allocated} days left | |
| </span> | |
| )} | |
| </div> | |
| <div className="relative h-2 w-full overflow-hidden rounded-full bg-secondary"> | |
| <div | |
| className={cn("h-full absolute left-0 top-0", typeInfo.color)} | |
| style={{ width: `${percentage}%` }} | |
| /> | |
| </div> | |
| {balance.carryForward > 0 && ( | |
| <div className="text-xs text-muted-foreground"> | |
| Includes {balance.carryForward} carried forward days | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| })} | |
| </div> | |
| </CardContent> | |
| </Card> | |
| ); | |
| }; | |
| export default LeaveBalance; |