va-tracker/src/ui/pages/LeaveAndAdjustments/LeaveTable.tsx

184 lines
5.5 KiB
TypeScript

import React from "react";
import { Loader2, RefreshCw } from "lucide-react";
import { DateTime } from "luxon";
interface LeaveItem {
leaveId: string;
dateFrom: string;
dateTo: string;
totalDays: number;
leaveType: string;
comment: string;
status: string;
appliedOn: string;
reviewedAt: string | null;
rejectionReason: string | null;
}
interface LeaveTableProps {
isTracking: boolean;
leaves: LeaveItem[];
loading: boolean;
lastRefreshed: Date | null;
onRefresh: () => Promise<void>;
}
const LeaveTable: React.FC<LeaveTableProps> = ({
isTracking,
leaves,
loading,
lastRefreshed,
onRefresh
}) => {
const [refreshing, setRefreshing] = React.useState(false);
// 🌍 Convert UTC → Local System Time
const toLocal = (utcString: string, format: string) => {
return DateTime.fromISO(utcString, { zone: "utc" })
.setZone(DateTime.local().zoneName)
.toFormat(format);
};
const formatDate = (d: string) => toLocal(d, "yyyy-MM-dd");
const formatDateTime = (d: string) => toLocal(d, "yyyy-MM-dd HH:mm:ss");
const handleRefresh = async () => {
setRefreshing(true);
await onRefresh();
setRefreshing(false);
};
const renderSkeletonRows = () =>
Array.from({ length: 5 }).map((_, index) => (
<tr key={`skeleton-${index}`} className="hover:bg-base-200">
<td><div className="skeleton h-4 w-6 bg-base-300"></div></td>
<td><div className="skeleton h-4 w-20 bg-base-300"></div></td>
<td><div className="skeleton h-4 w-28 bg-base-300"></div></td>
<td><div className="skeleton h-4 w-16 bg-base-300"></div></td>
<td><div className="skeleton h-4 w-10 bg-base-300"></div></td>
<td><div className="skeleton h-4 w-24 bg-base-300"></div></td>
</tr>
));
const formatLastRefreshed = () =>
lastRefreshed
? DateTime.fromJSDate(lastRefreshed)
.setZone(DateTime.local().zoneName)
.toFormat("HH:mm:ss")
: "Never";
return (
<>
{/* Table Container */}
<div
className="flex-1 overflow-y-auto rounded-box border border-base-content/10 bg-base-100 shadow-md no-scrollbar"
style={{
height: isTracking ? "calc(100vh - 200px)" : "calc(100vh - 160px)",
}}
>
<table className="table table-zebra w-full text-[11px]">
<thead className="sticky top-0 bg-base-200 z-10 text-[12px]">
<tr className="text-center">
<th>#</th>
<th>Leave Type</th>
<th>Date From → To</th>
<th>Status</th>
<th>Total Days</th>
<th>Applied On</th>
</tr>
</thead>
<tbody className="text-center">
{loading ? (
renderSkeletonRows()
) : refreshing && leaves.length === 0 ? (
renderSkeletonRows()
) : leaves.length > 0 ? (
leaves.map((leave, index) => (
<tr key={leave.leaveId}>
<td>{index + 1}</td>
<td>
<span className="badge badge-xs badge-primary">
{leave.leaveType}
</span>
</td>
<td className="whitespace-nowrap">
<span className="">{formatDate(leave.dateFrom)} </span>
→ {" "}
<span className="">{formatDate(leave.dateTo)}</span>
</td>
<td>
<span
className={`badge badge-xs ${
leave.status === "PENDING"
? "badge-warning"
: leave.status === "APPROVED"
? "badge-success"
: "badge-error"
}`}
>
{leave.status}
</span>
</td>
<td>{leave.totalDays}</td>
<td className="whitespace-nowrap">{formatDateTime(leave.appliedOn)}</td>
</tr>
))
) : (
<tr>
<td colSpan={6} className="text-center py-4 text-base-content/50">
No leaves found
</td>
</tr>
)}
{/* {!refreshing && leaves.length > 0 && (
<tr>
<td colSpan={6} className="bg-base-200/50">
<div className="flex justify-center py-2">
{renderSkeletonRows()}
</div>
</td>
</tr>
)} */}
</tbody>
</table>
</div>
{/* Footer */}
<div className="flex-none flex justify-between items-center text-xs mt-2">
<div className="text-base-content/60">
{leaves.length} leave{leaves.length !== 1 ? "s" : ""} found
</div>
<div className="flex items-center gap-4">
{lastRefreshed && (
<div className="text-xs text-base-content/60">
Last updated: {formatLastRefreshed()}
</div>
)}
<button
onClick={handleRefresh}
disabled={refreshing}
className="btn btn-xs btn-circle bg-warning"
title="Refresh Leaves"
>
{refreshing ? (
<Loader2 size={15} className="animate-spin text-base-content" />
) : (
<RefreshCw size={15} className="text-base-content" />
)}
</button>
</div>
</div>
</>
);
};
export default LeaveTable;