"use client"; import React, { FC, useEffect, useState } from "react"; import { Table } from "flowbite-react"; import { HiChevronLeft, HiChevronRight } from "react-icons/hi"; import { useLocal } from "@/lib/utils/use-local"; import { init_column } from "./lib/column"; import { toast } from "sonner"; import { Loader2, Sticker } from "lucide-react"; import { getNumber } from "@/lib/utils/getNumber"; import { formatMoney } from "@/lib/components/form/field/TypeInput"; import "react-resizable/css/styles.css"; import { Resizable } from "react-resizable"; import get from "lodash.get"; export const TableEditBetter: React.FC = ({ name, column, align = "center", onLoad, take = 20, header, disabledPagination, disabledHeader, disabledHeadTable, hiddenNoRow, disabledHoverRow, onInit, onCount, fm, mode, feature, onChange, delete_name, }) => { const [data, setData] = useState([]); const [columns, setColumns] = useState([] as any[]); const sideLeft = typeof header?.sideLeft === "function" ? header.sideLeft : null; const sideRight = typeof header?.sideRight === "function" ? header.sideRight : null; const checkbox = Array.isArray(feature) && feature?.length ? feature.includes("checkbox") : false; const local = useLocal({ table: null as any, data: [] as any[], dataForm: [] as any[], listData: [] as any[], sort: {} as any, search: null as any, count: 0 as any, addRow: (row: any) => { const data = fm.data?.[name] || []; data.push(row); fm.data[name] = data; fm.render(); local.data = fm.data[name]; local.render(); }, selection: { all: false, partial: [] as any[], }, renderRow: (row: any) => { setData((prev) => [...prev, row]); local.data = data; local.render(); }, removeRow: (row: any) => { const data = fm.data?.[name] || []; if (delete_name) { const ids: any[] = Array.isArray(fm.data?.[delete_name]) ? fm.data?.deleted_line_ids : []; if (row?.id) { ids.push(row.id); } fm.data[delete_name] = ids; } fm.data[name] = data.filter((item: any) => item !== row); fm.render(); local.data = fm.data[name]; local.render(); }, reload: async () => { toast.info( <> {"Loading..."} , { duration: Infinity, } ); try { if (Array.isArray(onLoad)) { local.data = onLoad; local.render(); setData(onLoad); } else { const res: any = onLoad({ search: local.search, sort: local.sort, take, paging: 1, }); if (res instanceof Promise) { res.then((e) => { local.data = e; local.render(); setData(e); setTimeout(() => { toast.dismiss(); }, 100); }); } else { local.data = res; local.render(); setData(res); } } } catch (ex: any) { console.error(get(ex, "response.data.meta.message") || ex.message); } setTimeout(() => { toast.dismiss(); }, 100); }, }); // const cloneListFM = (data: any[]) => { // if (mode === "form") { // local.dataForm = data.map((e: any) => cloneFM(fm, e)); // local.render(); // } // }; useEffect(() => { const defaultColumns: any[] = init_column(column); const col = defaultColumns?.length ? defaultColumns.map((e: any) => { return { ...e, width: e?.width || 150, }; }) : ([] as any[]); setColumns(col); local.data = fm?.data[name] || []; local.render(); fm.fields[name] = { name: name, type: "table", fields: [], }; fm.render(); }, []); const handleResize = (index: any, width: any) => { setColumns((prevColumns: any) => { const updatedColumns = [...prevColumns]; updatedColumns[index].width = width; return updatedColumns; }); }; return ( <>
{!disabledHeader ? (
{sideLeft ? sideLeft(local) : <>}
{sideRight ? sideRight(local) : <>}
) : ( <> )}
th:first-child { width: 20px !important; /* Atur lebar sesuai kebutuhan */ text-align: center; } .table-row-element > td:first-child { width: 20px !important; /* Atur lebar sesuai kebutuhan */ text-align: center; } ` )} > {!disabledHeadTable ? ( {columns.map((col, idx) => { return ( handleResize(idx, size.width) } >
{typeof col?.header === "function" ? col?.header() : col.header}
); })} ) : ( <> )} {local.data.map((row: any, index: any) => { if ( typeof fm.fields?.[name]?.fields?.[index]?.fields !== "object" ) { fm.fields[name].fields[index] = { fields: {}, }; } const fm_row = { ...fm, name: name, type: "table", data: row, error: fm.fields?.[name]?.fields?.[index]?.error, fields: fm.fields?.[name]?.fields?.[index]?.fields, render: () => { local.render(); fm.data[name] = local.data; fm.render(); }, }; return ( {columns.map((col, idx) => { const param = { row: row, name: col?.name, idx, tbl: local, fm_row: fm_row, onChange, }; const renderData = typeof col?.renderCell === "function" ? ( col.renderCell(param) ) : ( <>No Column ); return ( ); })} ); })}
{renderData}
{!local?.data?.length && (
No Data
)}
); }; const HeaderColumn: FC = ({ children, width, height, onResize, col }) => { const [isResizing, setIsResizing] = useState(false); const handleResizeStart = () => { setIsResizing(true); }; const handleResizeStop = () => { setIsResizing(false); }; return ( {children}
); }; export const Pagination: React.FC = ({ onNextPage, onPrevPage, disabledNextPage, disabledPrevPage, page, count, list, setPage, onChangePage, }) => { const local = useLocal({ page: 1 as any, pagination: [] as any, }); useEffect(() => { local.page = page; local.pagination = getPagination(page, Math.ceil(count / 20)); local.render(); }, [page, count]); return (
Showing {local.page * 20 - 19} to{" "} {list.data?.length >= 20 ? local.page * 20 : local.page === 1 && Math.ceil(count / 20) === 1 ? list.data?.length : local.page * 20 - 19 + list.data?.length}{" "} of {formatMoney(getNumber(count))} results
{ if (!disabledPrevPage) { onPrevPage(); } }} className={cx( "flex flex-row items-center gap-x-2 justify-center rounded p-1 ", disabledPrevPage ? "text-gray-200 border-gray-200 border px-2" : "cursor-pointer text-gray-500 hover:bg-gray-100 hover:text-gray-900 border-gray-500 border px-2" )} > Previous
{ if (!disabledNextPage) { onNextPage(); } }} className={cx( "flex flex-row items-center gap-x-2 justify-center rounded p-1 ", disabledNextPage ? "text-gray-200 border-gray-200 border px-2" : "cursor-pointer text-gray-500 hover:bg-gray-100 hover:text-gray-900 border-gray-500 border px-2" )} > Next
); }; export const PaginationPage: React.FC = ({ onNextPage, onPrevPage, disabledNextPage, disabledPrevPage, page, count, list, take, setPage, onChangePage, }) => { const local = useLocal({ page: 1 as any, pagination: [] as any, }); useEffect(() => { local.page = page; local.pagination = getPagination(page, Math.ceil(count / take)); local.render(); }, [page, count]); return (
{ if (!disabledPrevPage) { onPrevPage(); } }} className={cx( "flex flex-row items-center gap-x-2 justify-center rounded-full p-2 text-md", disabledPrevPage ? "text-gray-200 border-gray-200 border " : "cursor-pointer text-gray-500 hover:bg-gray-100 hover:text-gray-900 border-gray-500 border " )} >
{ if (!disabledNextPage) { onNextPage(); } }} className={cx( "flex flex-row items-center gap-x-2 justify-center rounded-full p-2 ", disabledNextPage ? "text-gray-200 border-gray-200 border" : "cursor-pointer text-gray-500 hover:bg-gray-100 hover:text-gray-900 border-gray-500 border " )} >
); }; const getPagination = (currentPage: number, totalPages: number) => { const pagination: { label: string; active: boolean }[] = []; const maxVisible = 5; // Jumlah maksimal elemen yang ditampilkan const halfRange = Math.floor((maxVisible - 3) / 2); if (totalPages <= maxVisible) { // Jika total halaman lebih kecil dari batas, tampilkan semua halaman for (let i = 1; i <= totalPages; i++) { pagination.push({ label: i.toString(), active: i === currentPage }); } } else { pagination.push({ label: "1", active: currentPage === 1 }); // Halaman pertama selalu ada if (currentPage > halfRange + 2) { pagination.push({ label: "...", active: false }); // Awal titik-titik } const startPage = Math.max(2, currentPage - halfRange); const endPage = Math.min(totalPages - 1, currentPage + halfRange); for (let i = startPage; i <= endPage; i++) { pagination.push({ label: i.toString(), active: i === currentPage }); } if (currentPage < totalPages - halfRange - 1) { pagination.push({ label: "...", active: false }); // Akhir titik-titik } pagination.push({ label: totalPages.toString(), active: currentPage === totalPages, }); // Halaman terakhir selalu ada } return pagination; };