simplify the Table component, the UsersPage shows some basic data

This commit is contained in:
Dawid Wysokiński 2021-03-11 20:29:56 +01:00
parent 987a7b46f6
commit 970d962ca5
10 changed files with 100 additions and 44 deletions

View File

@ -6,7 +6,6 @@ import {
Table as MUITable, Table as MUITable,
TableBody, TableBody,
TableProps as MUITableProps, TableProps as MUITableProps,
TableBodyProps,
TableContainer, TableContainer,
} from '@material-ui/core'; } from '@material-ui/core';
import TableHead from './TableHead'; import TableHead from './TableHead';
@ -23,18 +22,15 @@ export interface TableProps<T> {
orderDirection?: OrderDirection; orderDirection?: OrderDirection;
selection?: boolean; selection?: boolean;
idFieldName?: string; idFieldName?: string;
getRowKey?: (row: T, index: number) => string | number | null | undefined;
onRequestSort?: ( onRequestSort?: (
orderBy: string, orderBy: string,
orderDirection: OrderDirection orderDirection: OrderDirection
) => void | Promise<void>; ) => void | Promise<void>;
onSelect?: (rows: T[]) => void; onSelect?: (rows: T[]) => void;
loading?: boolean; loading?: boolean;
tableProps?: MUITableProps;
tableBodyProps?: TableBodyProps;
footerProps?: TableFooterProps; footerProps?: TableFooterProps;
hideFooter?: boolean; hideFooter?: boolean;
size?: 'medium' | 'small'; size?: MUITableProps['size'];
selected?: T[]; selected?: T[];
} }
@ -48,19 +44,12 @@ function Table<T>({
selection = false, selection = false,
loading = false, loading = false,
actions = [], actions = [],
tableBodyProps = {},
tableProps = {},
hideFooter = false, hideFooter = false,
footerProps = {}, footerProps = {},
size, size,
selected, selected,
onSelect, onSelect,
getRowKey,
}: TableProps<T>) { }: TableProps<T>) {
const headColumns =
actions.length > 0
? [...columns, { field: 'action', label: 'Akcje' }]
: columns;
const preparedFooterProps = { const preparedFooterProps = {
page: 0, page: 0,
rowsPerPage: validateRowsPerPage( rowsPerPage: validateRowsPerPage(
@ -86,11 +75,12 @@ function Table<T>({
return ( return (
<TableContainer> <TableContainer>
<MUITable size={size} {...tableProps}> <MUITable size={size}>
<TableHead <TableHead
columns={headColumns} columns={columns}
selection={selection} selection={selection}
orderBy={orderBy} orderBy={orderBy}
hasActions={actions.length > 0}
orderDirection={orderDirection} orderDirection={orderDirection}
onRequestSort={onRequestSort} onRequestSort={onRequestSort}
size={size} size={size}
@ -101,10 +91,9 @@ function Table<T>({
}} }}
allSelected={selected?.length === data.length} allSelected={selected?.length === data.length}
/> />
<TableBody {...tableBodyProps}> <TableBody>
{loading ? ( {loading ? (
<TableLoading <TableLoading
columns={headColumns}
size={size} size={size}
rowsPerPage={preparedFooterProps.rowsPerPage} rowsPerPage={preparedFooterProps.rowsPerPage}
/> />
@ -113,11 +102,7 @@ function Table<T>({
return ( return (
<TableRow <TableRow
key={ key={
getRowKey isObjKey(item, idFieldName) ? item[idFieldName] + '' : index
? getRowKey(item, index)
: isObjKey(item, idFieldName)
? item[idFieldName] + ''
: index
} }
index={index} index={index}
row={item} row={item}

View File

@ -4,6 +4,7 @@ import {
TablePagination, TablePagination,
TableRow, TableRow,
TableFooter as MUITableFooter, TableFooter as MUITableFooter,
TablePaginationProps as MUITablePaginationProps,
} from '@material-ui/core'; } from '@material-ui/core';
export interface TableFooterProps { export interface TableFooterProps {
@ -12,8 +13,8 @@ export interface TableFooterProps {
onChangePage?: (page: number) => void; onChangePage?: (page: number) => void;
rowsPerPage?: number; rowsPerPage?: number;
onChangeRowsPerPage?: (limit: number) => void; onChangeRowsPerPage?: (limit: number) => void;
rowsPerPageOptions?: Array<number | { value: number; label: string }>; rowsPerPageOptions?: MUITablePaginationProps['rowsPerPageOptions'];
size?: 'small' | 'medium'; size?: MUITablePaginationProps['size'];
} }
export const ROWS_PER_PAGE_DEFAULT = 25; export const ROWS_PER_PAGE_DEFAULT = 25;

View File

@ -22,6 +22,7 @@ export interface TableHeadProps {
property: string, property: string,
orderDirection: OrderDirection orderDirection: OrderDirection
) => void | Promise<void>; ) => void | Promise<void>;
hasActions: boolean;
} }
function TableHead({ function TableHead({
@ -33,6 +34,7 @@ function TableHead({
allSelected = false, allSelected = false,
onRequestSort, onRequestSort,
size = 'medium', size = 'medium',
hasActions = false,
}: TableHeadProps) { }: TableHeadProps) {
const createSortHandler = (property: string) => () => { const createSortHandler = (property: string) => () => {
if (onRequestSort) { if (onRequestSort) {
@ -85,6 +87,7 @@ function TableHead({
</TableCell> </TableCell>
); );
})} })}
{hasActions && <TableCell size={size}>Akcje</TableCell>}
</TableRow> </TableRow>
</MUITableHead> </MUITableHead>
); );

View File

@ -1,30 +1,22 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import { Column } from './types';
import { TableRow, TableCell } from '@material-ui/core'; import { TableRow, TableCell } from '@material-ui/core';
import { Skeleton } from '@material-ui/lab'; import { Skeleton } from '@material-ui/lab';
export interface TableLoadingProps { export interface TableLoadingProps {
rowsPerPage: number; rowsPerPage: number;
columns: Column[];
size?: 'small' | 'medium'; size?: 'small' | 'medium';
} }
function TableLoading({ function TableLoading({ rowsPerPage, size = 'medium' }: TableLoadingProps) {
rowsPerPage,
columns,
size = 'medium',
}: TableLoadingProps) {
return ( return (
<Fragment> <Fragment>
{new Array(rowsPerPage).fill(0).map((_, index) => { {new Array(rowsPerPage).fill(0).map((_, index) => {
return ( return (
<TableRow key={index}> <TableRow key={index}>
{columns.map(col => ( <TableCell size={size} colSpan={100}>
<TableCell size={size} key={col.field}> <Skeleton variant="text" />
<Skeleton variant="text" /> </TableCell>
</TableCell>
))}
</TableRow> </TableRow>
); );
})} })}

View File

@ -1,13 +1,12 @@
import { import {
ROWS_PER_PAGE_DEFAULT, ROWS_PER_PAGE_DEFAULT,
ROWS_PER_PAGE_OPTIONS_DEFAULT, ROWS_PER_PAGE_OPTIONS_DEFAULT,
TableFooterProps,
} from './TableFooter'; } from './TableFooter';
export const validateRowsPerPage = ( export const validateRowsPerPage = (
rowsPerPage: number | null = ROWS_PER_PAGE_DEFAULT, rowsPerPage: number | null = ROWS_PER_PAGE_DEFAULT,
rowsPerPageOptions: Array< rowsPerPageOptions: TableFooterProps['rowsPerPageOptions'] = ROWS_PER_PAGE_OPTIONS_DEFAULT
number | { value: number; label: string }
> = ROWS_PER_PAGE_OPTIONS_DEFAULT
) => { ) => {
const opt = const opt =
rowsPerPageOptions.find(opt => rowsPerPageOptions.find(opt =>

View File

@ -2,20 +2,52 @@ import useUsers from './UsersPage.useUsers';
import { NumberParam, useQueryParams, withDefault } from 'use-query-params'; import { NumberParam, useQueryParams, withDefault } from 'use-query-params';
import SortParam, { decodeSort } from 'libs/serialize-query-params/SortParam'; import SortParam, { decodeSort } from 'libs/serialize-query-params/SortParam';
import { validateRowsPerPage } from 'common/Table/helpers'; import { validateRowsPerPage } from 'common/Table/helpers';
import { DEFAULT_SORT, COLUMNS } from './constants';
const DEFAULT_SORT = decodeSort('id DESC'); import { Container, Paper } from '@material-ui/core';
import Table from 'common/Table/Table';
const UsersPage = () => { const UsersPage = () => {
const [{ page, sort, ...rest }, setQuery] = useQueryParams({ const [{ page, sort, ...rest }, setQueryParams] = useQueryParams({
limit: NumberParam, limit: NumberParam,
page: withDefault(NumberParam, 0), page: withDefault(NumberParam, 0),
sort: withDefault(SortParam, DEFAULT_SORT), sort: withDefault(SortParam, DEFAULT_SORT),
}); });
const limit = validateRowsPerPage(rest.limit); const limit = validateRowsPerPage(rest.limit);
const data = useUsers(page, limit, sort.toString()); const { users, total, loading } = useUsers(page, limit, sort.toString());
console.log(data); console.log(users);
return <div>UsersPage</div>; return (
<Container>
<Paper>
<Table
selection
columns={COLUMNS}
data={users}
loading={loading}
orderBy={sort.orderBy}
orderDirection={sort.orderDirection}
onRequestSort={(orderBy, orderDirection) => {
setQueryParams({
page: 0,
sort: decodeSort(orderBy + ' ' + orderDirection),
});
}}
footerProps={{
count: total,
page,
onChangePage: page => {
setQueryParams({ page });
},
onChangeRowsPerPage: limit => {
setQueryParams({ page: 0, limit });
},
rowsPerPage: limit,
}}
/>
</Paper>
</Container>
);
}; };
export default UsersPage; export default UsersPage;

View File

@ -18,7 +18,7 @@ const useUsers = (page: number, limit: number, sort: string) => {
return { return {
users: data?.users.items ?? [], users: data?.users.items ?? [],
get loading() { get loading() {
return this.users.length === 0 || loading; return this.users.length === 0 && loading;
}, },
total: data?.users.total ?? 0, total: data?.users.total ?? 0,
}; };

View File

@ -0,0 +1,39 @@
import { decodeSort } from 'libs/serialize-query-params/SortParam';
import { formatRole } from './utils';
import { Column } from 'common/Table/types';
import { User } from 'libs/graphql/types';
export const DEFAULT_SORT = decodeSort('id DESC');
export const COLUMNS: Column<User>[] = [
{
field: 'id',
sortable: true,
label: 'ID',
},
{
field: 'displayName',
sortable: true,
label: 'Użytkownik',
valueFormatter: v => {
return `${v.displayName} (${v.email})`;
},
},
{
field: 'role',
sortable: false,
label: 'Rola',
valueFormatter: v => formatRole(v.role),
},
{
field: 'activated',
sortable: false,
label: 'Aktywowany',
valueFormatter: v => (v.activated ? 'Tak' : 'Nie'),
},
{
field: 'createdAt',
sortable: true,
label: 'Data utworzenia',
type: 'datetime',
},
];

View File

@ -15,6 +15,7 @@ export const QUERY_USERS = gql`
displayName displayName
email email
role role
createdAt
} }
} }
} }

View File

@ -0,0 +1,4 @@
import { Role } from '../../libs/graphql/types';
export const formatRole = (r: Role): string =>
r === Role.Admin ? 'Admin' : 'Użytkownik';