dashboard/src/components/Table/Table.tsx

204 lines
6.8 KiB
TypeScript
Raw Normal View History

2021-09-27 12:17:33 +02:00
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;
2022-02-11 12:45:22 +01:00
loading?: boolean;
2021-09-27 12:17:33 +02:00
}
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,
2022-02-11 12:45:22 +01:00
loading = false,
2021-09-27 12:17:33 +02:00
}: 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()}>
2022-02-11 12:45:22 +01:00
{!loading ? (
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>
);
})
) : (
<td colSpan={4} className="py-24">
<div className="flex flex-col justify-center items-center">
<div className="flex justify-center items-center border border-transparent text-base font-medium rounded-md text-white transition ease-in-out duration-150">
<svg
className="animate-spin h-6 w-6 text-primary"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle className="opacity-50" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path
className="opacity-100"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
</div>
<p className="text-sm text-primary-600 mt-2">Loading users</p>
</div>
</td>
)}
2021-09-27 12:17:33 +02:00
</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>
)}
</>
);
};