126 lines
3.8 KiB
TypeScript
126 lines
3.8 KiB
TypeScript
"use client";
|
|
import { ColumnDef, DataTableLayout } from "ikoncomponents";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { getAllWorkingDays } from "@/app/utils/api/workingDays";
|
|
|
|
interface WorkingDaysDetailsData {
|
|
id: string;
|
|
year: string;
|
|
month: string;
|
|
workingDays: string;
|
|
}
|
|
|
|
function WorkingDaysDetailsTable() {
|
|
const [workingDaysDetails, setWorkingDaysDetails] = useState<
|
|
WorkingDaysDetailsData[]
|
|
>([]);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
const fetchWorkingDaysDetailsData = async () => {
|
|
setIsLoading(true);
|
|
try {
|
|
const workingDayData = await getAllWorkingDays();
|
|
|
|
let flatData: WorkingDaysDetailsData[] = [];
|
|
if (workingDayData?.content) {
|
|
workingDayData.content.forEach((item: any) => {
|
|
if (item.workingDaysDetails) {
|
|
Object.values(item.workingDaysDetails).forEach((yearObj: any) => {
|
|
Object.values(yearObj).forEach((monthObj: any) => {
|
|
flatData.push({
|
|
id: `${monthObj.year}-${monthObj.month}`,
|
|
year: monthObj.year,
|
|
month: monthObj.month,
|
|
workingDays: String(monthObj.workingDays),
|
|
});
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
setWorkingDaysDetails(flatData);
|
|
} catch (error) {
|
|
console.error("Error fetching WorkingDaysDetails data:", error);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
// Headers must be plain strings: DataTableLayout's grouping resolver maps the
|
|
// grouped header string back to its accessorKey, and only string headers expose
|
|
// the drag handle. Function headers (e.g. a centered <div>) can't be grouped.
|
|
const columns: ColumnDef<WorkingDaysDetailsData>[] = [
|
|
{
|
|
accessorKey: "year",
|
|
header: "Year",
|
|
},
|
|
{
|
|
accessorKey: "month",
|
|
header: "Month",
|
|
},
|
|
{
|
|
accessorKey: "workingDays",
|
|
header: "Number of working days",
|
|
},
|
|
];
|
|
|
|
// DataTableLayout keeps its grouping state internal with no prop to seed it —
|
|
// grouping is only triggered by dragging a column onto the grouping bar. To
|
|
// default-group by year, once the table has mounted we synthesise that drop
|
|
// (a "drop" event carrying columnHeader=Year) on the grouping drop zone once.
|
|
const tableContainerRef = useRef<HTMLDivElement>(null);
|
|
const groupedByYear = useRef(false);
|
|
|
|
useEffect(() => {
|
|
fetchWorkingDaysDetailsData();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (isLoading || groupedByYear.current) return;
|
|
|
|
const container = tableContainerRef.current;
|
|
if (!container) return;
|
|
|
|
// This table is list-only, so hide DataTableLayout's built-in List/Grid
|
|
// toggle (it has no prop to disable it). Hide the whole toggle group rather
|
|
// than just the grid button so a lone list button isn't left dangling.
|
|
const gridButton = container.querySelector<HTMLButtonElement>(
|
|
'button[title="Grid View"]',
|
|
);
|
|
if (gridButton?.parentElement) {
|
|
gridButton.parentElement.style.display = "none";
|
|
}
|
|
|
|
const dropZone = container.querySelector<HTMLDivElement>(
|
|
'div[class*="border-dashed"]',
|
|
);
|
|
if (!dropZone) return;
|
|
|
|
const dataTransfer = new DataTransfer();
|
|
dataTransfer.setData("columnHeader", "Year");
|
|
dropZone.dispatchEvent(
|
|
new DragEvent("drop", { bubbles: true, cancelable: true, dataTransfer }),
|
|
);
|
|
groupedByYear.current = true;
|
|
}, [isLoading]);
|
|
|
|
return (
|
|
<div ref={tableContainerRef} className="p-6 space-y-6">
|
|
<DataTableLayout
|
|
columns={columns}
|
|
data={workingDaysDetails}
|
|
extraTools={{
|
|
keyExtractor: (row: WorkingDaysDetailsData) => row.id,
|
|
totalPages: 1,
|
|
currentPage: 1,
|
|
isLoading,
|
|
onReload: fetchWorkingDaysDetailsData,
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default WorkingDaysDetailsTable;
|