136 lines
5.0 KiB
TypeScript
136 lines
5.0 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import { useSelector } from "react-redux";
|
|
import { RootState } from "../../store";
|
|
|
|
const PaysSlips = () => {
|
|
const { projectSummary } =
|
|
useSelector((state: any) => state.projects);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [rows, setRows] = useState<any[]>([]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
if (!projectSummary?.vaId) return;
|
|
|
|
fetchPayslips(projectSummary?.vaId);
|
|
|
|
}, [projectSummary?.vaId]);
|
|
|
|
const fetchPayslips = async (vaId: string) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
console.log("getPayslips" , vaId)
|
|
const result = await window.electron.getPayslips(vaId);
|
|
|
|
if (!result.success) {
|
|
setError(result.message || "Failed to load payslips");
|
|
return;
|
|
}
|
|
|
|
const response = result.data;
|
|
|
|
if (!response || response.length === 0) {
|
|
setRows([]);
|
|
return;
|
|
}
|
|
|
|
console.log(response , "getPayslips")
|
|
|
|
// Extract payrolls array from first index
|
|
const payrolls = response[0]?.payrolls || [];
|
|
|
|
setRows(payrolls);
|
|
} catch (err: any) {
|
|
setError("An unexpected error occurred");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div className="flex flex-col gap-2 max-h-screen">
|
|
<div className="flex items-center justify-between">
|
|
<h2 className="text-md font-bold">Payslips</h2>
|
|
</div>
|
|
|
|
<div className="overflow-y-auto rounded-box border border-base-content/10 bg-base-100 shadow-md max-h-[80vh] min-h-[83vh] no-scrollbar">
|
|
|
|
{loading && (
|
|
<div className="flex justify-center py-10">
|
|
<span className="loading loading-spinner loading-md"></span>
|
|
</div>
|
|
)}
|
|
|
|
{error && (
|
|
<div className="text-center text-red-500 py-5">{error}</div>
|
|
)}
|
|
|
|
{!loading && !error && rows.length === 0 && (
|
|
<div className="text-center py-10 text-gray-500">
|
|
No payslip data available.
|
|
</div>
|
|
)}
|
|
|
|
{!loading && !error && rows.length > 0 && (
|
|
<div className="overflow-x-auto w-full no-scrollbar">
|
|
<table className="table table-zebra w-full text-[12px] min-w-[650px]">
|
|
<thead className="sticky top-0 bg-base-200 z-10">
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Status</th>
|
|
<th>Date</th>
|
|
<th>Total Hours</th>
|
|
<th>Total Pay</th>
|
|
{/* <th>Action</th> */}
|
|
</tr>
|
|
</thead>
|
|
|
|
<tbody>
|
|
{rows.map((row, index) => (
|
|
<tr key={row.id}>
|
|
<td>{index + 1}</td>
|
|
|
|
<td>
|
|
<span
|
|
className={`badge ${
|
|
row.status === "Paid"
|
|
? "badge-success"
|
|
: "badge-warning"
|
|
}`}
|
|
>
|
|
{row.status}
|
|
</span>
|
|
</td>
|
|
|
|
<td>{row.payrollSchedule}</td>
|
|
|
|
<td>{row.totalHoursFormatted}</td>
|
|
|
|
<td>${row.totalPayAmount.toFixed(2)}</td>
|
|
|
|
{/* <td>
|
|
<button
|
|
className="btn btn-xs btn-primary"
|
|
>
|
|
View
|
|
</button>
|
|
</td> */}
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default PaysSlips;
|