dashboard/src/components/Table/Table.tsx

179 lines
5.6 KiB
TypeScript

import { ArrowSmDownIcon, ArrowSmUpIcon } from '@heroicons/react/solid';
import React, { useEffect } from 'react';
import { useTable, useRowSelect, Column, IdType, useSortBy } from 'react-table';
export interface ReactTableProps<T extends Record<string, unknown>> {
columns: Column<T>[];
data: T[];
onRowClick?(row: T): void;
pagination?: boolean;
getSelectedRowIds?(rows: Record<IdType<T>, boolean>): void;
selectable?: boolean;
}
const IndeterminateCheckbox = React.forwardRef(({ indeterminate, ...rest }: any, ref) => {
const defaultRef = React.useRef(null);
const resolvedRef: any = ref || defaultRef;
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate;
}, [resolvedRef, indeterminate]);
return (
<>
<input
type="checkbox"
ref={resolvedRef}
{...rest}
className="focus:ring-primary-800 h-4 w-4 text-primary-700 border-gray-300 rounded"
/>
</>
);
});
export const Table = <T extends Record<string, unknown>>({
columns,
data,
pagination = false,
onRowClick,
getSelectedRowIds,
selectable = false,
}: ReactTableProps<T>) => {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
pageCount,
state: { selectedRowIds },
} = useTable(
{
columns,
data,
},
useSortBy,
useRowSelect,
selectable
? (hooks) => {
hooks.visibleColumns.push((columns2) => [
{
id: 'selection',
Header: ({ getToggleAllRowsSelectedProps }: { getToggleAllRowsSelectedProps: any }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
Cell: ({ row }: { row: any }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
width: 16,
},
...columns2,
]);
}
: () => {},
);
useEffect(() => {
if (selectedRowIds && getSelectedRowIds) {
getSelectedRowIds(selectedRowIds);
}
}, [selectedRowIds, getSelectedRowIds]);
return (
<>
<table className="min-w-full divide-y divide-gray-200 table-auto" {...getTableProps()}>
<thead className="bg-gray-50">
{headerGroups.map((headerGroup: any, index: any) => (
<tr {...headerGroup.getHeaderGroupProps()} key={index!}>
{headerGroup.headers.map((column: any) => (
<th
key={column}
{...column.getHeaderProps([
{
style: {
width: column.width ? column.width : 'auto !important',
},
},
column.getSortByToggleProps(),
])}
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
<div className="flex items-center">
<span>{column.render('Header')}</span>
{(column as any).isSorted ? (
(column as any).isSortedDesc ? (
<ArrowSmDownIcon className="w-4 h-4 text-gray-400 ml-1" />
) : (
<ArrowSmUpIcon className="w-4 h-4 text-gray-400 ml-1" />
)
) : (
''
)}
</div>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row: any, rowIndex) => {
prepareRow(row);
return (
<tr
key={row}
{...row.getRowProps()}
className={rowIndex % 2 === 0 ? 'bg-white group' : 'bg-gray-50 group'}
onClick={onRowClick ? () => onRowClick(row.original as T) : () => {}}
>
{row.cells.map((cell: any) => {
return (
<td
key={cell}
{...cell.getCellProps()}
className="px-6 py-4 whitespace-nowrap text-sm text-gray-500"
>
{cell.render('Cell')}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
{pagination && pageCount > 1 && (
<div className="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-100 sm:px-6">
<div className="flex-1 flex justify-between sm:hidden">
<a
href="#"
className="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
>
Previous
</a>
<a
href="#"
className="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
>
Next
</a>
</div>
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<p className="text-sm text-gray-700">
Showing <span className="font-medium">1</span> to <span className="font-medium">3</span> of{' '}
<span className="font-medium">3</span> results
</p>
</div>
</div>
</div>
)}
</>
);
};