import '@mantine/core/styles.css';
import '@mantine/dates/styles.css';
import 'mantine-react-table/styles.css';
import { useMemo, useState } from 'react';
import {
MantineReactTable,
useMantineReactTable,
type MRT_ColumnDef,
type MRT_ColumnFiltersState,
type MRT_PaginationState,
type MRT_SortingState,
type MRT_ColumnFilterFnsState,
} from 'mantine-react-table';
import { ActionIcon, Tooltip } from '@mantine/core';
import { IconRefresh } from '@tabler/icons-react';
import {
QueryClient,
QueryClientProvider,
keepPreviousData,
useQuery,
} from '@tanstack/react-query';
type User = {
firstName: string;
lastName: string;
address: string;
state: string;
phoneNumber: string;
};
type UserApiResponse = {
data: Array<User>;
meta: {
totalRowCount: number;
};
};
interface Params {
columnFilterFns: MRT_ColumnFilterFnsState;
columnFilters: MRT_ColumnFiltersState;
globalFilter: string;
sorting: MRT_SortingState;
pagination: MRT_PaginationState;
}
const useGetUsers = ({
columnFilterFns,
columnFilters,
globalFilter,
sorting,
pagination,
}: Params) => {
const fetchURL = new URL(
'/api/data',
process.env.NODE_ENV === 'production'
? 'https://www.mantine-react-table.com'
: 'http://localhost:3001',
);
fetchURL.searchParams.set(
'start',
`${pagination.pageIndex * pagination.pageSize}`,
);
fetchURL.searchParams.set('size', `${pagination.pageSize}`);
fetchURL.searchParams.set('filters', JSON.stringify(columnFilters ?? []));
fetchURL.searchParams.set(
'filterModes',
JSON.stringify(columnFilterFns ?? {}),
);
fetchURL.searchParams.set('globalFilter', globalFilter ?? '');
fetchURL.searchParams.set('sorting', JSON.stringify(sorting ?? []));
return useQuery<UserApiResponse>({
queryKey: ['users', fetchURL.href],
queryFn: () => fetch(fetchURL.href).then((res) => res.json()),
placeholderData: keepPreviousData,
staleTime: 30_000,
});
};
const Example = () => {
const columns = useMemo<MRT_ColumnDef<User>[]>(
() => [
{
accessorKey: 'firstName',
header: 'First Name',
},
{
accessorKey: 'lastName',
header: 'Last Name',
},
{
accessorKey: 'address',
header: 'Address',
},
{
accessorKey: 'state',
header: 'State',
},
{
accessorKey: 'phoneNumber',
header: 'Phone Number',
},
],
[],
);
const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>(
[],
);
const [columnFilterFns, setColumnFilterFns] =
useState<MRT_ColumnFilterFnsState>(
Object.fromEntries(
columns.map(({ accessorKey }) => [accessorKey, 'contains']),
),
);
const [globalFilter, setGlobalFilter] = useState('');
const [sorting, setSorting] = useState<MRT_SortingState>([]);
const [pagination, setPagination] = useState<MRT_PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const { data, isError, isFetching, isLoading, refetch } = useGetUsers({
columnFilterFns,
columnFilters,
globalFilter,
pagination,
sorting,
});
const fetchedUsers = data?.data ?? [];
const totalRowCount = data?.meta?.totalRowCount ?? 0;
const table = useMantineReactTable({
columns,
data: fetchedUsers,
enableColumnFilterModes: true,
columnFilterModeOptions: ['contains', 'startsWith', 'endsWith'],
initialState: { showColumnFilters: true },
manualFiltering: true,
manualPagination: true,
manualSorting: true,
mantineToolbarAlertBannerProps: isError
? {
color: 'red',
children: 'Error loading data',
}
: undefined,
onColumnFilterFnsChange: setColumnFilterFns,
onColumnFiltersChange: setColumnFilters,
onGlobalFilterChange: setGlobalFilter,
onPaginationChange: setPagination,
onSortingChange: setSorting,
renderTopToolbarCustomActions: () => (
<Tooltip label="Refresh Data">
<ActionIcon onClick={() => refetch()}>
<IconRefresh />
</ActionIcon>
</Tooltip>
),
rowCount: totalRowCount,
state: {
columnFilterFns,
columnFilters,
globalFilter,
isLoading,
pagination,
showAlertBanner: isError,
showProgressBars: isFetching,
sorting,
},
});
return <MantineReactTable table={table} />;
};
const queryClient = new QueryClient();
const ExampleWithReactQueryProvider = () => (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
);
export default ExampleWithReactQueryProvider;