"use client"; import { makeData } from "@/lib/utils/makeData"; import { ColumnDef, ColumnResizeDirection, ColumnResizeMode, flexRender, getCoreRowModel, getPaginationRowModel, getSortedRowModel, PaginationState, SortingState, useReactTable, } from "@tanstack/react-table"; import React, { FC, useCallback, useEffect, useState } from "react"; import { Breadcrumb, Button, Checkbox, Label, Modal, Table, TextInput, } from "flowbite-react"; import { HiChevronLeft, HiChevronRight, HiHome, HiOutlinePencilAlt, HiPlus, HiSearch, HiTrash, } from "react-icons/hi"; import classNames from "classnames"; import { useLocal } from "@/lib/utils/use-local"; import { debouncedHandler } from "@/lib/utils/debounceHandler"; import { FaArrowDownLong, FaArrowUp, FaChevronUp } from "react-icons/fa6"; import Link from "next/link"; import { init_column } from "./lib/column"; import { toast } from "sonner"; import { Check, Loader2, Sticker } from "lucide-react"; import { InputSearch } from "../ui/input-search"; import { Input } from "../ui/input"; import { FaChevronDown } from "react-icons/fa"; import get from "lodash.get"; export const TableList: React.FC = ({ name, column, onLoad, take = 50, header, disabledPagination, disabledHeader, disabledHeadTable, hiddenNoRow, disabledHoverRow, onInit, }) => { const [data, setData] = useState([]); const sideLeft = typeof header?.sideLeft === "function" ? header.sideLeft : null; const sideRight = typeof header?.sideRight === "function" ? header.sideRight : null; type Person = { firstName: string; lastName: string; age: number; visits: number; status: string; progress: number; }; const local = useLocal({ table: null as any, data: [] as any[], sort: {} as any, search: null as any, addRow: (row: any) => { setData((prev) => [...prev, row]); local.data.push(row); local.render(); }, renderRow: (row: any) => { setData((prev) => [...prev, row]); local.data = data; local.render(); }, removeRow: (row: any) => { setData((prev) => prev.filter((item) => item !== row)); // Update state lokal local.data = local.data.filter((item: any) => item !== row); // Hapus row dari local.data local.render(); // Panggil render untuk memperbarui UI }, reload: async () => { toast.info( <> {"Loading..."} ); 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(); }, 2000); }); } else { local.data = res; local.render(); setData(res); setTimeout(() => { toast.dismiss(); }, 2000); } } }, }); useEffect(() => { if (typeof onInit === "function") { onInit(local); } toast.info( <> {"Loading..."} ); 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(); }, 2000); }); } else { local.data = res; local.render(); setData(res); setTimeout(() => { toast.dismiss(); }, 2000); } } }, []); const defaultColumns: ColumnDef[] = init_column(column); const [sorting, setSorting] = React.useState([]); const [columns] = React.useState(() => [ ...defaultColumns, ]); const [columnResizeMode, setColumnResizeMode] = React.useState("onChange"); const [columnResizeDirection, setColumnResizeDirection] = React.useState("ltr"); // Create the table and pass your options useEffect(() => { setData(local.data); }, [local.data.length]); const paginationConfig = disabledPagination ? {} : { getPaginationRowModel: getPaginationRowModel(), }; const table = useReactTable({ data: data, columnResizeMode, columnResizeDirection, columns, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), onSortingChange: setSorting, initialState: { pagination: { pageIndex: 0, //custom initial page index pageSize: 25, //custom default page size }, }, state: { pagination: { pageIndex: 0, pageSize: 50, }, sorting, }, ...paginationConfig, }); local.table = table; // Manage your own state const [state, setState] = React.useState(table.initialState); // Override the state managers for the table to your own table.setOptions((prev) => ({ ...prev, state, onStateChange: setState, debugTable: state.pagination.pageIndex > 2, })); const handleSearch = useCallback( debouncedHandler(() => { local.reload(); }, 1000), // 1 detik jeda [] ); return ( <>
{!disabledHeader ? (
{false ? (

All {name ? `${name}s` : ``}

) : ( <> )}
{sideLeft ? ( sideLeft(local) ) : ( <> )}
{ e.preventDefault(); await local.reload(); }} >
{ const value = e.target.value; local.search = value; local.render(); handleSearch(); }} />
{sideRight ? sideRight(local) : <>}
) : ( <> )}
{!disabledHeadTable ? ( {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header, index) => { const name = header.column.id; const col = column.find( (e: any) => e?.name === name ); const isSort = typeof col?.sortable === "boolean" ? col.sortable : true; return ( ); })} ))} ) : ( <> )} {table.getRowModel().rows.map((row, idx) => ( {row.getVisibleCells().map((cell) => { const ctx = cell.getContext(); const param = { row: row.original, name: get(ctx, "column.columnDef.accessorKey"), cell, idx, tbl: local, }; const head = column.find( (e: any) => e?.name === get(ctx, "column.columnDef.accessorKey") ); const renderData = typeof head?.renderCell === "function" ? head.renderCell(param) : flexRender( cell.column.columnDef.cell, cell.getContext() ); return ( {renderData} ); })} ))}
{ if (isSort) { const sort = local?.sort?.[name]; const mode = sort === "desc" ? null : sort === "asc" ? "desc" : "asc"; local.sort = mode ? { [name]: mode, } : {}; local.render(); local.reload(); } }} className={cx( "flex flex-grow flex-row flex-grow select-none items-center flex-row text-base text-nowrap", isSort ? " cursor-pointer" : "" )} >
{header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )}
{isSort ? (
) : ( <> )}
{headerGroup.headers.length !== index + 1 ? (
header.column.resetSize(), onMouseDown: header.getResizeHandler(), onTouchStart: header.getResizeHandler(), className: `resizer w-0.5 bg-gray-300 ${ table.options.columnResizeDirection } ${ header.column.getIsResizing() ? "isResizing" : "" }`, style: { transform: columnResizeMode === "onEnd" && header.column.getIsResizing() ? `translateX(${ (table.options .columnResizeDirection === "rtl" ? -1 : 1) * (table.getState() .columnSizingInfo .deltaOffset ?? 0) }px)` : "", }, }} >
) : null}
{!hiddenNoRow && !table.getRowModel().rows?.length && (
No Data
)}
table.nextPage()} onPrevPage={() => table.previousPage()} disabledNextPage={!table.getCanNextPage()} disabledPrevPage={!table.getCanPreviousPage()} page={table.getState().pagination.pageIndex + 1} countPage={table.getPageCount()} countData={local.data.length} take={take} onChangePage={(page: number) => { table.setPageIndex(page); }} />
); }; export const Pagination: React.FC = ({ onNextPage, onPrevPage, disabledNextPage, disabledPrevPage, page, countPage, countData, take, onChangePage, }) => { const local = useLocal({ page: 1 as any, }); useEffect(() => { local.page = page; local.render(); }, [page]); return (
{ if (!disabledPrevPage) { onPrevPage(); } }} className={classNames( "inline-flex justify-center rounded p-1 ", disabledPrevPage ? "text-gray-200" : "cursor-pointer text-gray-500 hover:bg-gray-100 hover:text-gray-900" )} > Previous page
{ if (!disabledNextPage) { onNextPage(); } }} className={classNames( "inline-flex justify-center rounded p-1 ", disabledNextPage ? "text-gray-200" : "cursor-pointer text-gray-500 hover:bg-gray-100 hover:text-gray-900" )} > Next page
Page  {page}  of  {countPage} | Go to page:
{ e.preventDefault(); const page = Number(local.page); if (!page) { local.page = 0; } else if (page > countPage) { local.page = countPage; } local.render(); onChangePage(local.page - 1); }} > { local.page = e.target.value; local.render(); debouncedHandler(() => { const page = Number(local.page); if (!page) { local.page = 0; } else if (page > countPage) { local.page = countPage; } local.render(); onChangePage(local.page - 1); }, 1500); }} />
{!disabledPrevPage ? ( <>
{ if (!disabledPrevPage) { onPrevPage(); } }} className={classNames( "cursor-pointer inline-flex flex-1 items-center justify-center rounded-lg bg-primary px-3 py-2 text-center text-md font-medium text-white hover:bg-primary focus:ring-4 focus:ring-primary-300" )} > Previous
) : ( <> )} {!disabledNextPage ? ( <>
{ if (!disabledNextPage) { onNextPage(); } }} className={classNames( "cursor-pointer inline-flex flex-1 items-center justify-center rounded-lg bg-primary px-3 py-2 text-center text-md font-medium text-white hover:bg-primary focus:ring-4 focus:ring-primary-300" )} > Next
) : ( <> )}
); };