@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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
/**
 * @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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
  )
}