simplify the Table component, the UsersPage shows some basic data
This commit is contained in:
parent
987a7b46f6
commit
970d962ca5
|
@ -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}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -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 =>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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',
|
||||||
|
},
|
||||||
|
];
|
|
@ -15,6 +15,7 @@ export const QUERY_USERS = gql`
|
||||||
displayName
|
displayName
|
||||||
email
|
email
|
||||||
role
|
role
|
||||||
|
createdAt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
import { Role } from '../../libs/graphql/types';
|
||||||
|
|
||||||
|
export const formatRole = (r: Role): string =>
|
||||||
|
r === Role.Admin ? 'Admin' : 'Użytkownik';
|
Reference in New Issue