@material-ui/core#TableSortLabel JavaScript Examples
The following examples show how to use
@material-ui/core#TableSortLabel.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: UserListHead.js From course-manager with MIT License | 5 votes |
export default function UserListHead({
order,
orderBy,
rowCount,
headLabel,
numSelected,
onRequestSort,
onSelectAllClick
}) {
const createSortHandler = (property) => (event) => {
onRequestSort(event, property);
};
return (
<TableHead>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
indeterminate={numSelected > 0 && numSelected < rowCount}
checked={rowCount > 0 && numSelected === rowCount}
onChange={onSelectAllClick}
/>
</TableCell>
{headLabel.map((headCell) => (
<TableCell
key={headCell.id}
align={headCell.alignRight ? 'right' : 'left'}
sortDirection={orderBy === headCell.id ? order : false}
>
<TableSortLabel
hideSortIcon
active={orderBy === headCell.id}
direction={orderBy === headCell.id ? order : 'asc'}
onClick={createSortHandler(headCell.id)}
>
{headCell.label}
{orderBy === headCell.id ? (
<Box sx={{ ...visuallyHidden }}>
{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
</Box>
) : null}
</TableSortLabel>
</TableCell>
))}
</TableRow>
</TableHead>
);
}
Example #2
Source File: SortableTable.js From covid-19 with MIT License | 5 votes |
SortableTable = (props) => {
const classes = useStyles();
const theme = useTheme();
const squish = useMediaQuery(theme.breakpoints.down('xs'));
const {columns, rows, defaultSortColumn} = props;
const [orderingBy, setOrderingBy] = React.useState(defaultSortColumn);
const [direction, setDirection] = React.useState(orderingBy.defaultDirection);
const sortFn = (a, b) =>
compareStable(
a, b, orderingBy.key, columns, direction === orderingBy.defaultDirection);
const sorted = [...rows].sort((a, b) =>
direction === 'asc' ? sortFn(a, b) : sortFn(b, a));
const createUpdateSort = (column) => () => {
setOrderingBy(column);
setDirection(
orderingBy === column
? opposite(direction) : column.defaultDirection);
};
return (
<Table size="small" className={squish ? classes.squishText : ''}>
<TableHead>
<TableRow>
{columns.map((column) =>
<TableCell key={column.key}>
<TableSortLabel
active={orderingBy.key === column.key}
direction={
orderingBy === column ? direction : column.defaultDirection}
hideSortIcon={squish}
onClick={createUpdateSort(column)}
>
{squish ? column.shortLabel || column.label : column.label}
</TableSortLabel>
</TableCell>
)}
</TableRow>
</TableHead>
<TableBody>
{sorted.map((row) =>
<TableRow key={row.id}>
{columns.map(({key, contextKey, renderShortNumber}) =>
<TableCell key={key}>
{render(row[key], renderShortNumber)}
{row[contextKey] && ` (${row[contextKey]})`}
</TableCell>
)}
</TableRow>
)}
</TableBody>
</Table>
);
}
Example #3
Source File: CaptureTable.js From treetracker-admin-client with GNU Affero General Public License v3.0 | 4 votes |
CaptureTable = () => {
const {
filter,
rowsPerPage,
page,
order,
orderBy,
captures,
capture,
captureCount,
isLoading,
setPage,
setRowsPerPage,
setOrder,
setOrderBy,
setCapture,
getCaptureAsync,
} = useContext(CapturesContext);
const speciesContext = useContext(SpeciesContext);
const tagsContext = useContext(TagsContext);
const [isDetailsPaneOpen, setIsDetailsPaneOpen] = useState(false);
const [speciesLookup, setSpeciesLookup] = useState({});
const [tagLookup, setTagLookup] = useState({});
const [captureTagLookup, setCaptureTagLookup] = useState({});
const [isOpenExport, setOpenExport] = useState(false);
const [disableHoverListener, setDisableHoverListener] = useState(false);
const classes = useStyle();
useEffect(() => {
populateSpeciesLookup();
}, [speciesContext.speciesList]);
useEffect(() => {
populateTagLookup();
}, [tagsContext.tagList]);
const getCaptureTags = async () => {
// Don't do anything if there are no captures
if (!captures?.length) {
return;
}
// Get the capture tags for all of the displayed captures
const captureTags = await api.getCaptureTags({
captureIds: captures.map((c) => c.id),
});
// Populate a lookup for quick access when rendering the table
let lookup = {};
captureTags.forEach((captureTag) => {
if (!lookup[captureTag.treeId]) {
lookup[captureTag.treeId] = [];
}
lookup[captureTag.treeId].push(tagLookup[captureTag.tagId]);
});
setCaptureTagLookup(lookup);
};
useEffect(() => {
getCaptureTags();
}, [captures, tagLookup]);
const populateSpeciesLookup = async () => {
let species = {};
speciesContext.speciesList.forEach((s) => {
species[s.id] = s.name;
});
setSpeciesLookup(species);
};
const populateTagLookup = async () => {
let tags = {};
tagsContext.tagList.forEach((t) => {
tags[t.id] = t.tagName;
});
setTagLookup(tags);
};
const toggleDrawer = (id) => {
getCaptureAsync(id);
setIsDetailsPaneOpen(!isDetailsPaneOpen);
};
const createToggleDrawerHandler = (id) => {
return () => {
toggleDrawer(id);
};
};
const closeDrawer = () => {
setIsDetailsPaneOpen(false);
setDisableHoverListener(false);
setCapture({});
};
const handleOpenExport = () => {
setOpenExport(true);
};
const handlePageChange = (e, page) => {
setPage(page);
};
const handleRowsPerPageChange = (e) => {
setRowsPerPage(parseInt(e.target.value));
};
const createSortHandler = (attr) => {
return () => {
const newOrder = orderBy === attr && order === 'asc' ? 'desc' : 'asc';
const newOrderBy = attr;
setOrder(newOrder);
setOrderBy(newOrderBy);
};
};
const tablePagination = () => {
return (
<TablePagination
rowsPerPageOptions={[25, 50, 100, 250, 500]}
component="div"
count={captureCount || 0}
page={page}
rowsPerPage={rowsPerPage}
onChangePage={handlePageChange}
onChangeRowsPerPage={handleRowsPerPageChange}
/>
);
};
const enableTooltips = process.env.REACT_APP_ENABLE_TOOLTIPS === 'true';
return (
<Grid style={{ height: '100%', overflow: 'auto', textAlign: 'center' }}>
<Grid
container
direction="row"
justify="space-between"
alignItems="center"
>
<Typography variant="h5" className={classes.title}>
Captures
</Typography>
<Grid className={classes.cornerTable}>
<Button
variant="outlined"
color="primary"
startIcon={<GetApp />}
className={classes.buttonCsv}
onClick={handleOpenExport}
>
Export Captures
</Button>
<ExportCaptures
isOpen={isOpenExport}
handleClose={() => setOpenExport(false)}
columns={columns}
filter={filter}
speciesLookup={speciesLookup}
captureTagLookup={captureTagLookup}
/>
{tablePagination()}
</Grid>
</Grid>
<Table data-testid="captures-table">
<TableHead>
<TableRow>
{columns.map(({ attr, label, noSort }) => (
<TableCell
key={attr}
sortDirection={orderBy === attr ? order : false}
>
<TableSortLabel
active={orderBy === attr}
direction={orderBy === attr ? order : 'asc'}
onClick={createSortHandler(attr)}
disabled={noSort}
>
{label}
</TableSortLabel>
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody data-testid="captures-table-body">
{isLoading && !captures?.length ? (
<TableRow className={classes.loadingIndicator}>
<TableCell className={classes.loadingIndicator}>
<CircularProgress />
</TableCell>
</TableRow>
) : (
<>
{captures &&
captures.map((capture) => (
<Tooltip
key={capture.id}
placement="top"
arrow={true}
interactive={!disableHoverListener}
enterDelay={500}
enterNextDelay={500}
disableFocusListener={true}
disableHoverListener={disableHoverListener}
classes={{
tooltipPlacementTop: classes.tooltipTop,
arrow: classes.arrow,
}}
title={
enableTooltips ? (
<CaptureTooltip
capture={capture}
toggleDrawer={createToggleDrawerHandler}
/>
) : (
''
)
}
>
<TableRow
key={capture.id}
onClick={createToggleDrawerHandler(capture.id)}
className={classes.tableRow}
>
{columns.map(({ attr, renderer }, i) => (
<TableCell key={`${attr}_${i}`}>
{formatCell(
capture,
speciesLookup,
captureTagLookup[capture.id] || [],
attr,
renderer
)}
</TableCell>
))}
</TableRow>
</Tooltip>
))}
</>
)}
</TableBody>
</Table>
{tablePagination()}
<CaptureDetailProvider>
<CaptureDetailDialog
open={isDetailsPaneOpen}
capture={capture}
onClose={closeDrawer}
/>
</CaptureDetailProvider>
</Grid>
);
}
Example #4
Source File: CustomTable.js From treetracker-admin-client with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function
* @name CustomTable
* @description displays table containing rows with data
*
* @param {Object} props - properties passed to component
* @param {Object} props.sortBy - current sort by field and sort order
* @param {Object} props.selectedRow - selected row
* @param {Object[]} props.tableMetaData - meta data of the table (carries infomation about table columns etc..)
* @param {function} props.handleGetData - handler function that triggers get data to be displayed in table
* @param {function} props.openDateFilter - opens date filter
* @param {function} props.openMainFilter - opens main filter
* @param {function} props.setPage - sets current page number
* @param {function} props.setRowsPerPage - sets number of rows per page number
* @param {function} props.setSortBy - sets sort by field and sort order
* @param {function} props.onSelectFile - callback function to be called when file is selected
* @param {function} props.setSelectedRow - sets selected/clicked row
* @param {string} props.headerTitle - title of the table header
* @param {string} props.actionButtonType - determines which action button to render(value can either be 'export' or 'upload')
* @param {string} props.activeDateRage - string representing the active date range (i.e. 'Oct 1 - Oct 5') in the date filter button
* @param {boolean} props.isLoading - shows loading spinner when true
* @param {number} props.page - current page number
* @param {number} props.rowsPerPage - current number of rows per page
* @param {number} props.totalCount - total number of rows to be displayed
* @param {number} props.activeFiltersCount - number of active filters
* @param {Array} props.rows - rows to be displayed in table
* @param {React.Component} props.rowDetails - row component to display details of a selected row
* @param {React.Component} props.mainFilterComponent - renders main filter component
* @param {React.Component} props.dateFilterComponent - renders date filter component
*
* @returns {React.Component} custom table
*/
function CustomTable({
tableMetaData,
mainFilterComponent,
dateFilterComponent,
headerTitle,
actionButtonType,
exportDataFetch,
setSelectedRow,
selectedRow,
sortBy,
rows,
totalCount,
rowDetails,
openDateFilter,
openMainFilter,
setPage,
setRowsPerPage,
rowsPerPage,
setSortBy,
isLoading,
activeDateRange,
onSelectFile,
page,
activeFiltersCount,
}) {
// managing custom table state
const classes = useStyles();
const [sortableColumnsObject, setSortableColumnsObject] = useState({});
const [growerDetail, setGrowerDetail] = useState({
isOpen: false,
grower: {},
});
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
const handleOpenRowDetails = (row) => {
setSelectedRow(row);
};
const handleSortableColumns = (column) => {
const sortableColumns = {
...sortableColumnsObject,
[column.name]: sortableColumnsObject[column.name]
? sortableColumnsObject[column.name] === 'asc'
? 'desc'
: 'asc'
: 'asc',
};
setSortableColumnsObject(sortableColumns);
setSortBy({ field: column.name, order: sortableColumns[column.name] });
};
const handleShowGrowerDetail = (e, grower) => {
e.preventDefault();
e.stopPropagation();
setGrowerDetail({
isOpen: true,
growerId: grower.worker_id,
});
};
function handleCloseGrowerDetail() {
setGrowerDetail({
isOpen: false,
growerId: null,
});
}
const isRowSelected = (id) => id === selectedRow?.id;
const tablePagination = () => {
return (
<TablePagination
rowsPerPageOptions={[20, 50, 100]}
component="div"
count={totalCount || 0}
page={page}
rowsPerPage={rowsPerPage}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
aria-label="rows per page"
/>
);
};
return (
<Paper className={classes.customTable}>
<CustomTableHeader
openDateFilter={openDateFilter}
openMainFilter={openMainFilter}
data={rows}
headerTitle={headerTitle}
activeDateRange={activeDateRange}
actionButtonType={actionButtonType}
onSelectFile={onSelectFile}
activeFiltersCount={activeFiltersCount}
exportDataFetch={exportDataFetch}
/>
{tablePagination()}
<TableContainer className={classes.tableHeight}>
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow className={classes.customTableHeader}>
{tableMetaData.map((column, i) => (
<TableCell
key={`${i}-${column.description}`}
sortDirection={
sortableColumnsObject[column.name] || column.sortDirection
}
style={{
textAlign: column.align === 'right' ? 'right' : 'inherit',
}}
>
{column?.sortable ? (
<TableSortLabel
active={sortBy?.field === column.name}
onClick={() => handleSortableColumns(column)}
direction={sortableColumnsObject[column.name]}
classes={{ icon: classes.customTableHeadSortIcon }}
IconComponent={ArrowDropDownIcon}
>
<Typography
variant="h6"
align={column.align === 'right' ? 'right' : 'inherit'}
>
{column.description}
{column?.showInfoIcon && (
<Tooltip title={column.showInfoIcon}>
<InfoOutlinedIcon className={classes.infoIcon} />
</Tooltip>
)}
</Typography>
</TableSortLabel>
) : (
<Typography
variant="h6"
align={column.align === 'right' ? 'right' : 'inherit'}
>
{column.description}
{column?.showInfoIcon && (
<Tooltip title={column.showInfoIcon}>
<InfoOutlinedIcon className={classes.infoIcon} />
</Tooltip>
)}
</Typography>
)}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{isLoading ? (
<TableRow>
<TableCell>
<Grid item container className={classes.progressContainer}>
<CircularProgress />
</Grid>
</TableCell>
</TableRow>
) : rows.length > 0 ? (
<>
{rows.map((row, i) => (
<TableRow
key={`${i}-${row.id}`}
onClick={() => handleOpenRowDetails(row)}
className={
isRowSelected(row.id) ? classes.selectedRow : null
}
>
{tableMetaData.map((column, j) => (
<TableCell key={`${i}-${j}-${column.name}`}>
{column.name === 'grower' ? (
<Grid item>
<Typography
variant="body1"
style={{ textTransform: 'capitalize' }}
>
{row[column.name]}
<IconButton
onClick={(e) => {
handleShowGrowerDetail(e, row);
}}
aria-label={`View/Edit Grower details`}
title={`View/Edit Grower details`}
style={{ padding: '0 2px 2px 0' }}
disabled
>
<Person color="disabled" />
</IconButton>
</Typography>
</Grid>
) : (
<Typography
variant="body1"
style={{
textTransform: 'capitalize',
textAlign:
column.align === 'right' ? 'right' : 'inherit',
}}
>
{row[column.name]}
</Typography>
)}
</TableCell>
))}
</TableRow>
))}
</>
) : (
<TableRow>
<TableCell>
<Typography
variant="body1"
className={classes.noDataToDisplay}
>
No data to display
</Typography>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
{tablePagination()}
<GrowerProvider>
<GrowerDetail
open={growerDetail.isOpen}
growerId={growerDetail.growerId}
onClose={() => handleCloseGrowerDetail()}
/>
</GrowerProvider>
{/* start table main filter */}
{mainFilterComponent}
{/* end table main filter */}
{/* start table date filter */}
{dateFilterComponent}
{/* end table date filter */}
{/* start table row details */}
{rowDetails}
{/* end table row details */}
</Paper>
);
}
Example #5
Source File: AgentsTable.js From voicemail-for-amazon-connect with Apache License 2.0 | 4 votes |
render() {
let classes = this.props.classes;
return (
<div className={this.props.className}>
<Paper className={classes.root}>
<div className={classes.topBar}>
<Grid container justify={"space-between"} alignItems={"flex-end"} direction={"row"}>
<Grid item className={classes.searchBox}>
<SearchTextField
ref={(c) => this.searchTextField = c }
showClearButton={this.props.searchFilter !== ""}
searchChangeFunc={this.handleSearchChange}/>
</Grid>
<Grid item>
<Button color="secondary" className={classes.syncButton} onClick={() => this.setState({syncOpen: true})}>
Sync Agents
</Button>
<AsyncButton loading={this.props.loading} color={"primary"} onClick={() => {
this.props.getAgents();
if (this.searchTextField) {
this.searchTextField.updateSearch("")
}
}} >Refresh</AsyncButton>
</Grid>
</Grid>
</div>
<Dialog
open={this.state.syncOpen}
onClose={() => this.setState({syncOpen: false})}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Sync Amazon Connect Agents?</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
This process will sync all users in Amazon Connect to the VM portal.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() => this.setState({syncOpen: false})} color="primary">
Cancel
</Button>
<Button onClick={this.handleSync} color="primary" autoFocus>
Sync
</Button>
</DialogActions>
</Dialog>
<Table className={classes.table} stickyHeader aria-label="sticky table" size="small">
<TableHead>
<TableRow>
{headerCells.map(headerCell => (
<TableCell className={classes.tableCell}
key={headerCell.id}
align={headerCell.numeric ? 'right' : 'left'}
padding={headerCell.disablePadding ? 'none' : 'default'}>
<TableSortLabel
onClick={() => this.sortBy(headerCell.id)}
key={headerCell.id}
hideSortIcon={!headerCell.sortable}
active={this.props.sortKey === headerCell.id}
direction={this.props.sortOrder}
IconComponent={ArrowDropDown}>
{headerCell.label}
</TableSortLabel>
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{this.props.agents.map(agent => (
<TableRow key={agent.userId} hover onClick={() => {this.showAgent(agent)}}>
<TableCell align="left">{agent.username}</TableCell>
<TableCell align="left">{agent.extension}</TableCell>
<TableCell align="left">{
this.props.encryptVoicemail ?
<Check fontSize="inherit"/> :
( agent.encryptVoicemail ?
<Check fontSize="inherit"/> : null ) }
</TableCell>
<TableCell align="left">{
agent.transcribeVoicemail ?
<Check className={this.props.transcribeVoicemail ? null : classes.checkDisable} fontSize="inherit"/> :
null}
</TableCell>
<TableCell align="left">
<span
className={classes.delivery}>{agent.deliverEmail ? "Email" : ""}</span>
<span
className={classes.delivery}>{agent.deliverSMS ? `SMS: ${agent.deliverSMSPhoneNumber}` : ""}</span>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<div className={classes.navigationBar}>
<Button disabled={this.props.page.prev.length === 0} onClick={() => {
this.props.getAgents(this.props.page.prev[this.props.page.prev.length - 1]);
}}><KeyboardArrowLeft className={classes.navButton}/></Button>
<Button disabled={this.props.page.next.length === 0} onClick={() => {
this.props.getAgents(this.props.page.next[0]);
}}><KeyboardArrowRight className={classes.navButton}/></Button>
</div>
</Paper>
</div>
)
}
Example #6
Source File: LatestOrders.js From EMP with MIT License | 4 votes |
LatestOrders = () => {
// const classes = useStyles();
const [orders] = useState(data);
return (
<Card>
<CardHeader title="Latest Orders" />
<Divider />
<PerfectScrollbar>
<Box minWidth={800}>
<Table>
<TableHead>
<TableRow>
<TableCell>
Order Ref
</TableCell>
<TableCell>
Customer
</TableCell>
<TableCell sortDirection="desc">
<Tooltip
enterDelay={300}
title="Sort"
>
<TableSortLabel
active
direction="desc"
>
Date
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell>
Status
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{orders.map((order) => (
<TableRow
hover
key={order.id}
>
<TableCell>
{order.ref}
</TableCell>
<TableCell>
{order.customer.name}
</TableCell>
<TableCell>
{moment(order.createdAt).format('DD/MM/YYYY')}
</TableCell>
<TableCell>
<Chip
color="primary"
label={order.status}
size="small"
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Box>
</PerfectScrollbar>
<Box
display="flex"
justifyContent="flex-end"
p={2}
>
<Button
color="primary"
endIcon={<ArrowRightIcon />}
size="small"
variant="text"
>
View all
</Button>
</Box>
</Card>
);
}
Example #7
Source File: UserList.js From willow-grandstack with Apache License 2.0 | 4 votes |
function UserList(props) {
const { classes } = props
const [order, setOrder] = React.useState('asc')
const [orderBy, setOrderBy] = React.useState('name')
const [page] = React.useState(0)
const [rowsPerPage] = React.useState(10)
const [filterState, setFilterState] = React.useState({ usernameFilter: '' })
const getFilter = () => {
return filterState.usernameFilter.length > 0
? { name_contains: filterState.usernameFilter }
: {}
}
const { loading, data, error } = useQuery(GET_USER, {
variables: {
first: rowsPerPage,
offset: rowsPerPage * page,
orderBy: orderBy + '_' + order,
filter: getFilter(),
},
})
const handleSortRequest = (property) => {
const newOrderBy = property
let newOrder = 'desc'
if (orderBy === property && order === 'desc') {
newOrder = 'asc'
}
setOrder(newOrder)
setOrderBy(newOrderBy)
}
const handleFilterChange = (filterName) => (event) => {
const val = event.target.value
setFilterState((oldFilterState) => ({
...oldFilterState,
[filterName]: val,
}))
}
return (
<Paper className={classes.root}>
<Title>User List</Title>
<TextField
id="search"
label="User Name Contains"
className={classes.textField}
value={filterState.usernameFilter}
onChange={handleFilterChange('usernameFilter')}
margin="normal"
variant="outlined"
type="text"
InputProps={{
className: classes.input,
}}
/>
{loading && !error && <p>Loading...</p>}
{error && !loading && <p>Error</p>}
{data && !loading && !error && (
<Table className={classes.table}>
<TableHead>
<TableRow>
<TableCell
key="name"
sortDirection={orderBy === 'name' ? order : false}
>
<Tooltip title="Sort" placement="bottom-start" enterDelay={300}>
<TableSortLabel
active={orderBy === 'name'}
direction={order}
onClick={() => handleSortRequest('name')}
>
Name
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell
key="avgStars"
sortDirection={orderBy === 'avgStars' ? order : false}
>
<Tooltip title="Sort" placement="bottom-end" enterDelay={300}>
<TableSortLabel
active={orderBy === 'avgStars'}
direction={order}
onClick={() => handleSortRequest('avgStars')}
>
Average Stars
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell
key="numReviews"
sortDirection={orderBy === 'numReviews' ? order : false}
>
<Tooltip title="Sort" placement="bottom-start" enterDelay={300}>
<TableSortLabel
active={orderBy === 'numReviews'}
direction={order}
onClick={() => handleSortRequest('numReviews')}
>
Number of Reviews
</TableSortLabel>
</Tooltip>
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.User.map((n) => {
return (
<TableRow key={n.id}>
<TableCell component="th" scope="row">
{n.name}
</TableCell>
<TableCell>
{n.avgStars ? n.avgStars.toFixed(2) : '-'}
</TableCell>
<TableCell>{n.numReviews}</TableCell>
</TableRow>
)
})}
</TableBody>
</Table>
)}
</Paper>
)
}