|
|
@@ -8,160 +8,171 @@ import TableCell from "@mui/material/TableCell"; |
|
|
|
import TableContainer from "@mui/material/TableContainer"; |
|
|
|
import TableHead from "@mui/material/TableHead"; |
|
|
|
import TablePagination, { |
|
|
|
TablePaginationProps, |
|
|
|
TablePaginationProps, |
|
|
|
} from "@mui/material/TablePagination"; |
|
|
|
import TableRow from "@mui/material/TableRow"; |
|
|
|
import IconButton, { IconButtonOwnProps } from "@mui/material/IconButton"; |
|
|
|
import IconButton, {IconButtonOwnProps} from "@mui/material/IconButton"; |
|
|
|
|
|
|
|
export interface ResultWithId { |
|
|
|
id: string | number; |
|
|
|
id: string | number; |
|
|
|
} |
|
|
|
|
|
|
|
interface BaseColumn<T extends ResultWithId> { |
|
|
|
name: keyof T; |
|
|
|
label: string; |
|
|
|
name: keyof T; |
|
|
|
label: string; |
|
|
|
} |
|
|
|
|
|
|
|
interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> { |
|
|
|
onClick: (item: T) => void; |
|
|
|
buttonIcon: React.ReactNode; |
|
|
|
buttonColor?: IconButtonOwnProps["color"]; |
|
|
|
onClick: (item: T) => void; |
|
|
|
buttonIcon: React.ReactNode; |
|
|
|
buttonColor?: IconButtonOwnProps["color"]; |
|
|
|
} |
|
|
|
|
|
|
|
export type Column<T extends ResultWithId> = |
|
|
|
| BaseColumn<T> |
|
|
|
| ColumnWithAction<T>; |
|
|
|
| BaseColumn<T> |
|
|
|
| ColumnWithAction<T>; |
|
|
|
|
|
|
|
interface Props<T extends ResultWithId> { |
|
|
|
items: T[]; |
|
|
|
columns: Column<T>[]; |
|
|
|
noWrapper?: boolean; |
|
|
|
items: T[], |
|
|
|
columns: Column<T>[], |
|
|
|
noWrapper?: boolean, |
|
|
|
setPagingController: (value: (((prevState: { pageNum: number; pageSize: number; totalCount: number }) => { |
|
|
|
pageNum: number; |
|
|
|
pageSize: number; |
|
|
|
totalCount: number |
|
|
|
}) | { pageNum: number; pageSize: number; totalCount: number })) => void, |
|
|
|
pagingController: { pageNum: number; pageSize: number; totalCount: number }, |
|
|
|
isAutoPaging: boolean |
|
|
|
} |
|
|
|
|
|
|
|
function isActionColumn<T extends ResultWithId>( |
|
|
|
column: Column<T>, |
|
|
|
column: Column<T>, |
|
|
|
): column is ColumnWithAction<T> { |
|
|
|
return Boolean((column as ColumnWithAction<T>).onClick); |
|
|
|
return Boolean((column as ColumnWithAction<T>).onClick); |
|
|
|
} |
|
|
|
|
|
|
|
function SearchResults<T extends ResultWithId>({ |
|
|
|
items, |
|
|
|
columns, |
|
|
|
noWrapper, |
|
|
|
pagingController, |
|
|
|
setPagingController, |
|
|
|
isAutoPaging = true, |
|
|
|
}: Props<T>) { |
|
|
|
const [page, setPage] = React.useState(0); |
|
|
|
const [rowsPerPage, setRowsPerPage] = React.useState(10); |
|
|
|
items, |
|
|
|
columns, |
|
|
|
noWrapper, |
|
|
|
pagingController, |
|
|
|
setPagingController, |
|
|
|
isAutoPaging = true, |
|
|
|
}: Props<T>) { |
|
|
|
const [page, setPage] = React.useState(0); |
|
|
|
const [rowsPerPage, setRowsPerPage] = React.useState(10); |
|
|
|
|
|
|
|
const handleChangePage: TablePaginationProps["onPageChange"] = ( |
|
|
|
_event, |
|
|
|
newPage, |
|
|
|
) => { |
|
|
|
setPage(newPage); |
|
|
|
setPagingController({ |
|
|
|
...pagingController, |
|
|
|
pageNum: newPage+1, |
|
|
|
}) |
|
|
|
}; |
|
|
|
const handleChangePage: TablePaginationProps["onPageChange"] = ( |
|
|
|
_event, |
|
|
|
newPage, |
|
|
|
) => { |
|
|
|
setPage(newPage); |
|
|
|
if (setPagingController) { |
|
|
|
setPagingController({ |
|
|
|
...pagingController, |
|
|
|
pageNum: newPage + 1, |
|
|
|
}) |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
const handleChangeRowsPerPage: TablePaginationProps["onRowsPerPageChange"] = ( |
|
|
|
event, |
|
|
|
) => { |
|
|
|
setRowsPerPage(+event.target.value); |
|
|
|
setPage(0); |
|
|
|
setPagingController({ |
|
|
|
...pagingController, |
|
|
|
pageNum: +event.target.value, |
|
|
|
}) |
|
|
|
}; |
|
|
|
const handleChangeRowsPerPage: TablePaginationProps["onRowsPerPageChange"] = ( |
|
|
|
event, |
|
|
|
) => { |
|
|
|
setRowsPerPage(+event.target.value); |
|
|
|
setPage(0); |
|
|
|
if (setPagingController) { |
|
|
|
setPagingController({ |
|
|
|
...pagingController, |
|
|
|
pageNum: +event.target.value, |
|
|
|
}) |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
const table = ( |
|
|
|
<> |
|
|
|
<TableContainer sx={{ maxHeight: 440 }}> |
|
|
|
<Table stickyHeader> |
|
|
|
<TableHead> |
|
|
|
<TableRow> |
|
|
|
{columns.map((column, idx) => ( |
|
|
|
<TableCell key={`${column.name.toString()}${idx}`}> |
|
|
|
{column.label} |
|
|
|
</TableCell> |
|
|
|
))} |
|
|
|
</TableRow> |
|
|
|
</TableHead> |
|
|
|
<TableBody> |
|
|
|
{ |
|
|
|
isAutoPaging? |
|
|
|
items |
|
|
|
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) |
|
|
|
.map((item) => { |
|
|
|
return ( |
|
|
|
<TableRow hover tabIndex={-1} key={item.id}> |
|
|
|
{columns.map((column, idx) => { |
|
|
|
const columnName = column.name; |
|
|
|
const table = ( |
|
|
|
<> |
|
|
|
<TableContainer sx={{maxHeight: 440}}> |
|
|
|
<Table stickyHeader> |
|
|
|
<TableHead> |
|
|
|
<TableRow> |
|
|
|
{columns.map((column, idx) => ( |
|
|
|
<TableCell key={`${column.name.toString()}${idx}`}> |
|
|
|
{column.label} |
|
|
|
</TableCell> |
|
|
|
))} |
|
|
|
</TableRow> |
|
|
|
</TableHead> |
|
|
|
<TableBody> |
|
|
|
{ |
|
|
|
isAutoPaging ? |
|
|
|
items |
|
|
|
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) |
|
|
|
.map((item) => { |
|
|
|
return ( |
|
|
|
<TableRow hover tabIndex={-1} key={item.id}> |
|
|
|
{columns.map((column, idx) => { |
|
|
|
const columnName = column.name; |
|
|
|
|
|
|
|
return ( |
|
|
|
<TableCell key={`${columnName.toString()}-${idx}`}> |
|
|
|
{isActionColumn(column) ? ( |
|
|
|
<IconButton |
|
|
|
color={column.buttonColor ?? "primary"} |
|
|
|
onClick={() => column.onClick(item)} |
|
|
|
> |
|
|
|
{column.buttonIcon} |
|
|
|
</IconButton> |
|
|
|
) : ( |
|
|
|
<>{item[columnName] as string}</> |
|
|
|
)} |
|
|
|
</TableCell> |
|
|
|
); |
|
|
|
})} |
|
|
|
</TableRow> |
|
|
|
); |
|
|
|
}) |
|
|
|
: |
|
|
|
items |
|
|
|
.map((item) => { |
|
|
|
return ( |
|
|
|
<TableRow hover tabIndex={-1} key={item.id}> |
|
|
|
{columns.map((column, idx) => { |
|
|
|
const columnName = column.name; |
|
|
|
return ( |
|
|
|
<TableCell key={`${columnName.toString()}-${idx}`}> |
|
|
|
{isActionColumn(column) ? ( |
|
|
|
<IconButton |
|
|
|
color={column.buttonColor ?? "primary"} |
|
|
|
onClick={() => column.onClick(item)} |
|
|
|
> |
|
|
|
{column.buttonIcon} |
|
|
|
</IconButton> |
|
|
|
) : ( |
|
|
|
<>{item[columnName] as string}</> |
|
|
|
)} |
|
|
|
</TableCell> |
|
|
|
); |
|
|
|
})} |
|
|
|
</TableRow> |
|
|
|
); |
|
|
|
}) |
|
|
|
: |
|
|
|
items |
|
|
|
.map((item) => { |
|
|
|
return ( |
|
|
|
<TableRow hover tabIndex={-1} key={item.id}> |
|
|
|
{columns.map((column, idx) => { |
|
|
|
const columnName = column.name; |
|
|
|
|
|
|
|
return ( |
|
|
|
<TableCell key={`${columnName.toString()}-${idx}`}> |
|
|
|
{isActionColumn(column) ? ( |
|
|
|
<IconButton |
|
|
|
color={column.buttonColor ?? "primary"} |
|
|
|
onClick={() => column.onClick(item)} |
|
|
|
> |
|
|
|
{column.buttonIcon} |
|
|
|
</IconButton> |
|
|
|
) : ( |
|
|
|
<>{item[columnName] as string}</> |
|
|
|
)} |
|
|
|
</TableCell> |
|
|
|
); |
|
|
|
})} |
|
|
|
</TableRow> |
|
|
|
); |
|
|
|
}) |
|
|
|
} |
|
|
|
</TableBody> |
|
|
|
</Table> |
|
|
|
</TableContainer> |
|
|
|
<TablePagination |
|
|
|
rowsPerPageOptions={[10, 25, 100]} |
|
|
|
component="div" |
|
|
|
count={pagingController.totalCount == 0 ? items.length : pagingController.totalCount} |
|
|
|
rowsPerPage={rowsPerPage} |
|
|
|
page={page} |
|
|
|
onPageChange={handleChangePage} |
|
|
|
onRowsPerPageChange={handleChangeRowsPerPage} |
|
|
|
/> |
|
|
|
</> |
|
|
|
); |
|
|
|
return ( |
|
|
|
<TableCell key={`${columnName.toString()}-${idx}`}> |
|
|
|
{isActionColumn(column) ? ( |
|
|
|
<IconButton |
|
|
|
color={column.buttonColor ?? "primary"} |
|
|
|
onClick={() => column.onClick(item)} |
|
|
|
> |
|
|
|
{column.buttonIcon} |
|
|
|
</IconButton> |
|
|
|
) : ( |
|
|
|
<>{item[columnName] as string}</> |
|
|
|
)} |
|
|
|
</TableCell> |
|
|
|
); |
|
|
|
})} |
|
|
|
</TableRow> |
|
|
|
); |
|
|
|
}) |
|
|
|
} |
|
|
|
</TableBody> |
|
|
|
</Table> |
|
|
|
</TableContainer> |
|
|
|
<TablePagination |
|
|
|
rowsPerPageOptions={[10, 25, 100]} |
|
|
|
component="div" |
|
|
|
count={pagingController.totalCount == 0 ? items.length : pagingController.totalCount} |
|
|
|
rowsPerPage={rowsPerPage} |
|
|
|
page={page} |
|
|
|
onPageChange={handleChangePage} |
|
|
|
onRowsPerPageChange={handleChangeRowsPerPage} |
|
|
|
/> |
|
|
|
</> |
|
|
|
); |
|
|
|
|
|
|
|
return noWrapper ? table : <Paper sx={{ overflow: "hidden" }}>{table}</Paper>; |
|
|
|
return noWrapper ? table : <Paper sx={{overflow: "hidden"}}>{table}</Paper>; |
|
|
|
} |
|
|
|
|
|
|
|
export default SearchResults; |