diff options
| author | Dayana31 <[email protected]> | 2022-04-21 17:27:08 -0500 | 
|---|---|---|
| committer | Dayana31 <[email protected]> | 2022-04-21 17:27:08 -0500 | 
| commit | 67c50667678dd0ce4709b29a854f6a47093a1ac5 (patch) | |
| tree | b6f9f39092ad54bf6b815984d32b37d7c7ca67ab /front/odiparpack/app/components/Tables | |
| parent | 91140b24f0d49a9f89a080ee063e9eb023a4b73a (diff) | |
| parent | e13e630cd6e4fc0b1ff92098a28a770794c7bb9a (diff) | |
| download | DP1_project-67c50667678dd0ce4709b29a854f6a47093a1ac5.tar.gz DP1_project-67c50667678dd0ce4709b29a854f6a47093a1ac5.tar.bz2 DP1_project-67c50667678dd0ce4709b29a854f6a47093a1ac5.zip | |
Merge branch 'gabshr' into dayana
Diffstat (limited to 'front/odiparpack/app/components/Tables')
18 files changed, 1614 insertions, 0 deletions
| diff --git a/front/odiparpack/app/components/Tables/AdvTable.js b/front/odiparpack/app/components/Tables/AdvTable.js new file mode 100644 index 0000000..acb2803 --- /dev/null +++ b/front/odiparpack/app/components/Tables/AdvTable.js @@ -0,0 +1,206 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import classNames from 'classnames'; +import tableStyles from 'ba-styles/Table.scss'; +import { Table, TableBody, TableCell, TableRow, TablePagination, Paper, Checkbox } from '@material-ui/core'; +import EnhancedTableHead from './tableParts/TableHeader'; +import EnhancedTableToolbar from './tableParts/TableToolbar'; + + +const styles = theme => ({ +  root: { +    width: '100%', +    marginTop: theme.spacing(3), +  }, +  table: { +    minWidth: 1020, +  }, +  tableWrapper: { +    overflowX: 'auto', +  }, +}); + +class AdvTable extends React.Component { +  constructor(props, context) { +    super(props, context); + +    this.state = { +      order: this.props.order, +      orderBy: this.props.orderBy, +      selected: this.props.selected, +      data: this.props.data.sort((a, b) => (a.calories < b.calories ? -1 : 1)), +      page: this.props.page, +      rowsPerPage: this.props.rowsPerPage, +      defaultPerPage: this.props.defaultPerPage, +      filterText: this.props.filterText, +    }; +  } + +  handleRequestSort = (event, property) => { +    const orderBy = property; +    let order = 'desc'; + +    if (this.state.orderBy === property && this.state.order === 'desc') { +      order = 'asc'; +    } + +    const data = order === 'desc' +      ? this.state.data.sort((a, b) => (b[orderBy] < a[orderBy] ? -1 : 1)) +      : this.state.data.sort((a, b) => (a[orderBy] < b[orderBy] ? -1 : 1)); + +    this.setState({ data, order, orderBy }); +  }; + +  handleSelectAllClick = (event, checked) => { +    if (checked) { +      this.setState({ selected: this.state.data.map(n => n.id) }); +      return; +    } +    this.setState({ selected: [] }); +  }; + +  handleClick = (event, id) => { +    const { selected } = this.state; +    const selectedIndex = selected.indexOf(id); +    let newSelected = []; + +    if (selectedIndex === -1) { +      newSelected = newSelected.concat(selected, id); +    } else if (selectedIndex === 0) { +      newSelected = newSelected.concat(selected.slice(1)); +    } else if (selectedIndex === selected.length - 1) { +      newSelected = newSelected.concat(selected.slice(0, -1)); +    } else if (selectedIndex > 0) { +      newSelected = newSelected.concat( +        selected.slice(0, selectedIndex), +        selected.slice(selectedIndex + 1), +      ); +    } + +    this.setState({ selected: newSelected }); +  }; + +  handleChangePage = (event, page) => { +    this.setState({ page }); +  }; + +  handleChangeRowsPerPage = event => { +    this.setState({ rowsPerPage: event.target.value }); +  }; + +  isSelected = id => this.state.selected.indexOf(id) !== -1; + +  handleUserInput(value) { +    // Show all item first +    if (value !== '') { +      this.setState({ rowsPerPage: this.state.data.length }); +    } else { +      this.setState({ rowsPerPage: this.state.defaultPerPage }); +    } + +    // Show result base on keyword +    this.setState({ filterText: value.toLowerCase() }); +  } + +  render() { +    const { classes } = this.props; +    const { +      data, +      order, +      orderBy, +      selected, +      rowsPerPage, +      page, +      filterText +    } = this.state; +    const { columnData } = this.props; +    const checkcell = true; +    const emptyRows = rowsPerPage - Math.min(rowsPerPage, data.length - (page * rowsPerPage)); +    const renderCell = (dataArray, keyArray) => keyArray.map((itemCell, index) => ( +      <TableCell align={itemCell.numeric ? 'right' : 'left'} key={index.toString()}>{dataArray[itemCell.id]}</TableCell> +    )); +    return ( +      <Paper className={classes.root}> +        <EnhancedTableToolbar +          numSelected={selected.length} +          filterText={filterText} +          onUserInput={(event) => this.handleUserInput(event)} +        /> +        <div className={classes.tableWrapper}> +          <Table className={classNames(classes.table, tableStyles.stripped)}> +            <EnhancedTableHead +              numSelected={selected.length} +              order={order} +              orderBy={orderBy} +              onSelectAllClick={this.handleSelectAllClick} +              onRequestSort={this.handleRequestSort} +              rowCount={data.length} +              columnData={columnData} +              checkcell={checkcell} +            /> +            <TableBody> +              {data.slice(page * rowsPerPage, (page * rowsPerPage) + rowsPerPage).map(n => { +                const isSelected = this.isSelected(n.id); +                if (n.name.toLowerCase().indexOf(filterText) === -1) { +                  return false; +                } +                return ( +                  <TableRow +                    hover +                    onClick={event => this.handleClick(event, n.id)} +                    role="checkbox" +                    aria-checked={isSelected} +                    tabIndex={-1} +                    key={n.id} +                    selected={isSelected} +                  > +                    <TableCell padding="checkbox"> +                      <Checkbox checked={isSelected} /> +                    </TableCell> +                    {renderCell(n, columnData)} +                  </TableRow> +                ); +              })} +              {emptyRows > 0 && ( +                <TableRow style={{ height: 49 * emptyRows }}> +                  <TableCell colSpan={6} /> +                </TableRow> +              )} +            </TableBody> +          </Table> +        </div> +        <TablePagination +          component="div" +          rowsPerPageOptions={[5, 10, 25]} +          count={data.length} +          rowsPerPage={rowsPerPage} +          page={page} +          backIconButtonProps={{ +            'aria-label': 'Previous Page', +          }} +          nextIconButtonProps={{ +            'aria-label': 'Next Page', +          }} +          onChangePage={this.handleChangePage} +          onChangeRowsPerPage={this.handleChangeRowsPerPage} +        /> +      </Paper> +    ); +  } +} + +AdvTable.propTypes = { +  classes: PropTypes.object.isRequired, +  data: PropTypes.array.isRequired, +  order: PropTypes.string.isRequired, +  orderBy: PropTypes.string.isRequired, +  selected: PropTypes.array.isRequired, +  rowsPerPage: PropTypes.number.isRequired, +  page: PropTypes.number.isRequired, +  defaultPerPage: PropTypes.number.isRequired, +  filterText: PropTypes.string.isRequired, +  columnData: PropTypes.array.isRequired, +}; + +export default withStyles(styles)(AdvTable); diff --git a/front/odiparpack/app/components/Tables/CrudTable.js b/front/odiparpack/app/components/Tables/CrudTable.js new file mode 100644 index 0000000..d3dd164 --- /dev/null +++ b/front/odiparpack/app/components/Tables/CrudTable.js @@ -0,0 +1,52 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import MainTable from './tableParts/MainTable'; + +class CrudTable extends React.Component { +  componentDidMount() { +    this.props.fetchData(this.props.dataInit, this.props.branch); +  } + +  render() { +    const { +      title, +      dataTable, +      addEmptyRow, +      removeRow, +      updateRow, +      editRow, +      finishEditRow, +      anchor, +      branch +    } = this.props; +    return ( +      <MainTable +        title={title} +        addEmptyRow={addEmptyRow} +        items={dataTable} +        removeRow={removeRow} +        updateRow={updateRow} +        editRow={editRow} +        finishEditRow={finishEditRow} +        anchor={anchor} +        branch={branch} +      /> +    ); +  } +} + +CrudTable.propTypes = { +  title: PropTypes.string.isRequired, +  anchor: PropTypes.array.isRequired, +  dataInit: PropTypes.array.isRequired, +  dataTable: PropTypes.object.isRequired, +  fetchData: PropTypes.func.isRequired, +  addEmptyRow: PropTypes.func.isRequired, +  removeRow: PropTypes.func.isRequired, +  updateRow: PropTypes.func.isRequired, +  editRow: PropTypes.func.isRequired, +  finishEditRow: PropTypes.func.isRequired, +  branch: PropTypes.string.isRequired, +}; + +export default CrudTable; diff --git a/front/odiparpack/app/components/Tables/CrudTableForm.js b/front/odiparpack/app/components/Tables/CrudTableForm.js new file mode 100644 index 0000000..d2d2ea8 --- /dev/null +++ b/front/odiparpack/app/components/Tables/CrudTableForm.js @@ -0,0 +1,70 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Form from './tableParts/Form'; +import MainTableForm from './tableParts/MainTableForm'; +import FloatingPanel from './../Panel/FloatingPanel'; + +class CrudTableForm extends React.Component { +  componentDidMount() { +    this.props.fetchData(this.props.dataInit, this.props.branch); +  } + +  sendValues = (values) => { +    setTimeout(() => { +      this.props.submit(values, this.props.branch); +    }, 500); +  } + +  render() { +    const { +      title, +      dataTable, +      openForm, +      closeForm, +      removeRow, +      addNew, +      editRow, +      anchor, +      children, +      branch, +      initValues +    } = this.props; +    return ( +      <div> +        <FloatingPanel openForm={openForm} branch={branch} closeForm={closeForm}> +          <Form onSubmit={this.sendValues} initValues={initValues} branch={branch}> +            {children} +          </Form> +        </FloatingPanel> +        <MainTableForm +          title={title} +          addNew={addNew} +          items={dataTable} +          removeRow={removeRow} +          editRow={editRow} +          anchor={anchor} +          branch={branch} +        /> +      </div> +    ); +  } +} + +CrudTableForm.propTypes = { +  title: PropTypes.string.isRequired, +  anchor: PropTypes.array.isRequired, +  dataInit: PropTypes.array.isRequired, +  dataTable: PropTypes.object.isRequired, +  fetchData: PropTypes.func.isRequired, +  submit: PropTypes.func.isRequired, +  addNew: PropTypes.func.isRequired, +  openForm: PropTypes.bool.isRequired, +  closeForm: PropTypes.func.isRequired, +  removeRow: PropTypes.func.isRequired, +  editRow: PropTypes.func.isRequired, +  children: PropTypes.node.isRequired, +  initValues: PropTypes.object.isRequired, +  branch: PropTypes.string.isRequired, +}; + +export default CrudTableForm; diff --git a/front/odiparpack/app/components/Tables/EmptyData.js b/front/odiparpack/app/components/Tables/EmptyData.js new file mode 100644 index 0000000..a59c3d6 --- /dev/null +++ b/front/odiparpack/app/components/Tables/EmptyData.js @@ -0,0 +1,14 @@ +import React from 'react'; +import tableStyles from 'ba-styles/Table.scss'; +import TableIcon from '@material-ui/icons/Apps'; + +function EmptyData() { +  return ( +    <div className={tableStyles.nodata}> +      <TableIcon /> +      No Data +    </div> +  ); +} + +export default EmptyData; diff --git a/front/odiparpack/app/components/Tables/TreeTable.js b/front/odiparpack/app/components/Tables/TreeTable.js new file mode 100644 index 0000000..12eeb19 --- /dev/null +++ b/front/odiparpack/app/components/Tables/TreeTable.js @@ -0,0 +1,190 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import ExpandLess from '@material-ui/icons/KeyboardArrowRight'; +import ExpandMore from '@material-ui/icons/ExpandMore'; +import Add from '@material-ui/icons/AddCircle'; +import Remove from '@material-ui/icons/RemoveCircleOutline'; + +import { Table, TableBody, TableCell, TableHead, TableRow } from '@material-ui/core'; + +const styles = theme => ({ +  root: { +    width: '100%', +    marginTop: theme.spacing(3), +    overflowX: 'auto', +  }, +  table: { +    minWidth: 700, +  }, +  hideRow: { +    display: 'none' +  }, +  anchor: { +    cursor: 'pointer' +  }, +  icon: { +    top: 5, +    position: 'relative', +    left: -5 +  } +}); + +let RenderRow = props => { +  const { +    classes, +    toggleTree, +    treeOpen, +    item, +    parent, +    arrowMore, +    icon, +    branch +  } = props; + +  const keyID = item.id; +  const dataBody = Object.keys(item); +  const dataBodyVal = Object.values(item); + +  const renderIconMore = (iconName) => { +    if (iconName === 'arrow') { +      return <ExpandMore className={classes.icon} />; +    } +    return <Remove className={classes.icon} />; +  }; + +  const renderIconLess = (iconName) => { +    if (iconName === 'arrow') { +      return <ExpandLess className={classes.icon} />; +    } +    return <Add className={classes.icon} />; +  }; + +  const renderCell = (dataArray, parentCell) => dataArray.map((itemCell, index) => { +    if (index < 1) { +      if (parentCell) { +        return ( +          <TableCell key={index.toString()} style={{ paddingLeft: (keyID.split('_').length) * 20 }}> +            {arrowMore.indexOf(keyID) > -1 ? renderIconMore(icon) : renderIconLess(icon)} +            {keyID} +          </TableCell> +        ); +      } +      return ( +        <TableCell key={index.toString()} style={{ paddingLeft: (keyID.split('_').length) * 20 }}>{keyID}</TableCell> +      ); +    } + +    if (itemCell !== 'child') { +      return ( +        <TableCell key={index.toString()}>{dataBodyVal[index]}</TableCell> +      ); +    } + +    return false; +  }); + +  const row = parent ? ( +    <TableRow +      key={keyID} +      className={treeOpen.indexOf(keyID) < 0 && keyID.indexOf('_') > -1 ? classes.hideRow : classes.anchor} +      onClick={() => toggleTree(keyID, item.child, branch)} +    > +      {renderCell(dataBody, true)} +    </TableRow> +  ) : ( +    <TableRow +      key={keyID} +      className={treeOpen.indexOf(keyID) < 0 && keyID.indexOf('_') > -1 ? classes.hideRow : ''} +    > +      {renderCell(dataBody, false)} +    </TableRow> +  ); + +  return [row]; +}; + +RenderRow.propTypes = { +  classes: PropTypes.object.isRequired, +  item: PropTypes.object.isRequired, +  parent: PropTypes.bool.isRequired, +  toggleTree: PropTypes.func.isRequired, +  treeOpen: PropTypes.object.isRequired, +  arrowMore: PropTypes.object.isRequired, +  branch: PropTypes.string.isRequired, +  icon: PropTypes.string.isRequired +}; + +RenderRow = withStyles(styles)(RenderRow); + +class TreeTable extends React.Component { +  render() { +    const { +      classes, +      dataTable, +      icon, +      treeOpen, +      arrowMore, +      toggleTree, +      branch +    } = this.props; +    const parentRow = true; +    const getData = dataArray => dataArray.map((item, index) => { +      if (item.child) { +        return [ +          <RenderRow +            icon={icon} +            treeOpen={treeOpen} +            arrowMore={arrowMore} +            toggleTree={toggleTree} +            item={item} +            key={index.toString()} +            parent={parentRow} +            branch={branch} +          />, +          getData(item.child) +        ]; +      } +      return ( +        <RenderRow +          icon={icon} +          item={item} +          treeOpen={treeOpen} +          arrowMore={arrowMore} +          toggleTree={toggleTree} +          key={index.toString()} +          branch={branch} +          parent={false} +        /> +      ); +    }); + +    const getHead = dataArray => dataArray.map((item, index) => <TableCell key={index.toString()}>{item.label}</TableCell> +    ); + +    return ( +      <Table className={classes.table}> +        <TableHead> +          <TableRow> +            { getHead(dataTable.head) } +          </TableRow> +        </TableHead> +        <TableBody> +          { getData(dataTable.body) } +        </TableBody> +      </Table> +    ); +  } +} + +TreeTable.propTypes = { +  classes: PropTypes.object.isRequired, +  dataTable: PropTypes.object.isRequired, +  treeOpen: PropTypes.object.isRequired, +  toggleTree: PropTypes.func.isRequired, +  arrowMore: PropTypes.object.isRequired, +  branch: PropTypes.string.isRequired, +  icon: PropTypes.string.isRequired +}; + +export default withStyles(styles)(TreeTable); diff --git a/front/odiparpack/app/components/Tables/tableParts/DatePickerCell.js b/front/odiparpack/app/components/Tables/tableParts/DatePickerCell.js new file mode 100644 index 0000000..161d0eb --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/DatePickerCell.js @@ -0,0 +1,59 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { KeyboardDatePicker, MuiPickersUtilsProvider } from '@material-ui/pickers'; +import MomentUtils from '@date-io/moment'; +import css from 'ba-styles/Table.scss'; +import { TableCell } from '@material-ui/core'; + +class DatePickerCell extends React.Component { +  state = { +    event: { +      target: { +        name: this.props.cellData.type, // eslint-disable-line +        value: this.props.cellData.value, // eslint-disable-line +      } +    } +  } + +  handleDateChange = date => { +    const { event } = this.state; +    const { branch, updateRow } = this.props; +    event.target.value = date; +    updateRow(event, branch); +  } + +  render() { +    const { +      edited, +      cellData +    } = this.props; +    const { event } = this.state; +    return ( +      <TableCell padding="none" className="text-center" textalign="center"> +        <MuiPickersUtilsProvider utils={MomentUtils}> +          <KeyboardDatePicker +            clearable +            name={cellData.type} +            className={css.crudInput} +            format="DD/MM/YYYY" +            placeholder="10/10/2018" +            mask={[/\d/, /\d/, '/', /\d/, /\d/, '/', /\d/, /\d/, /\d/, /\d/]} +            value={event.target.value} +            disabled={!edited} +            onChange={this.handleDateChange} +            animateYearScrolling={false} +          /> +        </MuiPickersUtilsProvider> +      </TableCell> +    ); +  } +} + +DatePickerCell.propTypes = { +  cellData: PropTypes.object.isRequired, +  updateRow: PropTypes.func.isRequired, +  edited: PropTypes.bool.isRequired, +  branch: PropTypes.string.isRequired, +}; + +export default DatePickerCell; diff --git a/front/odiparpack/app/components/Tables/tableParts/EditableCell.js b/front/odiparpack/app/components/Tables/tableParts/EditableCell.js new file mode 100644 index 0000000..2c7ba8f --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/EditableCell.js @@ -0,0 +1,86 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import css from 'ba-styles/Table.scss'; + +import { TableCell, Input, TextField } from '@material-ui/core'; + +class EditableCell extends React.Component { +  handleUpdate(event) { +    event.persist(); +    this.props.updateRow(event, this.props.branch); +  } + +  render() { +    const { +      cellData, +      edited, +      inputType +    } = this.props; +    switch (inputType) { +      case 'text': +        return ( +          <TableCell padding="none"> +            <Input +              placeholder={cellData.type} +              name={cellData.type} +              className={css.crudInput} +              id={cellData.id.toString()} +              value={cellData.value} +              onChange={(event) => this.handleUpdate(event)} +              disabled={!edited} +              margin="none" +              inputProps={{ +                'aria-label': 'Description', +              }} +            /> +          </TableCell> +        ); +      case 'number': +        return ( +          <TableCell padding="none"> +            <TextField +              id={cellData.id.toString()} +              name={cellData.type} +              className={css.crudInput} +              value={cellData.value} +              onChange={(event) => this.handleUpdate(event)} +              type="number" +              InputLabelProps={{ +                shrink: true, +              }} +              margin="none" +              disabled={!edited} +            /> +          </TableCell> +        ); +      default: +        return ( +          <TableCell padding="none"> +            <Input +              placeholder={cellData.type} +              name={cellData.type} +              className={css.crudInput} +              id={cellData.id.toString()} +              value={cellData.value} +              onChange={(event) => this.handleUpdate(event)} +              disabled={!edited} +              margin="none" +              inputProps={{ +                'aria-label': 'Description', +              }} +            /> +          </TableCell> +        ); +    } +  } +} + +EditableCell.propTypes = { +  inputType: PropTypes.string.isRequired, +  cellData: PropTypes.object.isRequired, +  updateRow: PropTypes.func.isRequired, +  edited: PropTypes.bool.isRequired, +  branch: PropTypes.string.isRequired, +}; + +export default EditableCell; diff --git a/front/odiparpack/app/components/Tables/tableParts/Form.js b/front/odiparpack/app/components/Tables/tableParts/Form.js new file mode 100644 index 0000000..da66966 --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/Form.js @@ -0,0 +1,71 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { reduxForm } from 'redux-form/immutable'; +import css from 'ba-styles/Form.scss'; +import { Button } from '@material-ui/core'; + +class Form extends Component { +  componentDidMount() { +    // this.ref // the Field +    //   .getRenderedComponent() // on Field, returns ReduxFormMaterialUITextField +    //   .getRenderedComponent() // on ReduxFormMaterialUITextField, returns TextField +    //   .focus() // on TextField +    // console.log(this.props.initValues); +  } + +  render() { +    const { +      handleSubmit, +      children, +      reset, +      pristine, +      submitting, +    } = this.props; + +    return ( +      <div> +        <form onSubmit={handleSubmit}> +          <section className={css.bodyForm}> +            {children} +          </section> +          <div className={css.buttonArea}> +            <Button variant="contained" color="secondary" type="submit" disabled={submitting}> +              Submit +            </Button> +            <Button +              type="button" +              disabled={pristine || submitting} +              onClick={reset} +            > +              Reset +            </Button> +          </div> +        </form> +      </div> +    ); +  } +} + +Form.propTypes = { +  children: PropTypes.node.isRequired, +  handleSubmit: PropTypes.func.isRequired, +  reset: PropTypes.func.isRequired, +  pristine: PropTypes.bool.isRequired, +  submitting: PropTypes.bool.isRequired, +}; + +const FormMapped = reduxForm({ +  form: 'immutableExample', +  enableReinitialize: true, +})(Form); + + +const FormMappedInit = connect( +  state => ({ +    initialValues: state.getIn(['crudTableForm', 'formValues']) +  }) +)(FormMapped); + + +export default FormMappedInit; diff --git a/front/odiparpack/app/components/Tables/tableParts/MainTable.js b/front/odiparpack/app/components/Tables/tableParts/MainTable.js new file mode 100644 index 0000000..973bccf --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/MainTable.js @@ -0,0 +1,104 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import classNames from 'classnames'; +import AddIcon from '@material-ui/icons/Add'; +import css from 'ba-styles/Table.scss'; +import { +  Table, +  TableBody, +  TableCell, +  TableHead, +  TableRow, +  Toolbar, +  Typography, +  Tooltip, +  Button, +} from '@material-ui/core'; +import Row from './Row'; +import styles from './tableStyle-jss'; + + +class MainTable extends React.Component { +  render() { +    const { +      classes, +      items, +      addEmptyRow, +      removeRow, +      updateRow, +      editRow, +      finishEditRow, +      anchor, +      branch, +      title +    } = this.props; + +    const getItems = dataArray => dataArray.map(item => ( +      <Row +        anchor={anchor} +        updateRow={(event) => updateRow(event, item, branch)} +        item={item} +        removeRow={() => removeRow(item, branch)} +        key={item.get('id')} +        editRow={() => editRow(item, branch)} +        finishEditRow={() => finishEditRow(item, branch)} +        branch={branch} +      /> +    )); + +    const getHead = dataArray => dataArray.map((item, index) => { +      if (!item.hidden) { +        return ( +          <TableCell padding="none" key={index.toString()} width={item.width}>{item.label}</TableCell> +        ); +      } +      return false; +    }); +    return ( +      <div> +        <Toolbar className={classes.toolbar}> +          <div className={classes.title}> +            <Typography variant="h6">{title}</Typography> +          </div> +          <div className={classes.spacer} /> +          <div className={classes.actions}> +            <Tooltip title="Add Item"> +              <Button variant="contained" onClick={() => addEmptyRow(anchor, branch)} color="secondary" className={classes.button}> +                <AddIcon className={classNames(classes.leftIcon, classes.iconSmall)} /> +                Add New +              </Button> +            </Tooltip> +          </div> +        </Toolbar> +        <div className={classes.rootTable}> +          <Table className={classNames(css.tableCrud, classes.table, css.stripped)}> +            <TableHead> +              <TableRow> +                { getHead(anchor) } +              </TableRow> +            </TableHead> +            <TableBody> +              {getItems(items)} +            </TableBody> +          </Table> +        </div> +      </div> +    ); +  } +} + +MainTable.propTypes = { +  title: PropTypes.string.isRequired, +  classes: PropTypes.object.isRequired, +  items: PropTypes.object.isRequired, +  anchor: PropTypes.array.isRequired, +  addEmptyRow: PropTypes.func.isRequired, +  removeRow: PropTypes.func.isRequired, +  updateRow: PropTypes.func.isRequired, +  editRow: PropTypes.func.isRequired, +  finishEditRow: PropTypes.func.isRequired, +  branch: PropTypes.string.isRequired +}; + +export default withStyles(styles)(MainTable); diff --git a/front/odiparpack/app/components/Tables/tableParts/MainTableForm.js b/front/odiparpack/app/components/Tables/tableParts/MainTableForm.js new file mode 100644 index 0000000..ccf0e4a --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/MainTableForm.js @@ -0,0 +1,97 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import classNames from 'classnames'; +import AddIcon from '@material-ui/icons/Add'; +import css from 'ba-styles/Table.scss'; +import { +  Table, +  TableBody, +  TableCell, +  TableHead, +  TableRow, +  Toolbar, +  Typography, +  Tooltip, +  Button, +} from '@material-ui/core'; +import RowReadOnly from './RowReadOnly'; +import styles from './tableStyle-jss'; + + +class MainTableForm extends React.Component { +  render() { +    const { +      title, +      classes, +      items, +      removeRow, +      editRow, +      addNew, +      anchor, +      branch +    } = this.props; +    const getItems = dataArray => dataArray.map(item => ( +      <RowReadOnly +        item={item} +        removeRow={() => removeRow(item, branch)} +        key={item.get('id')} +        editRow={() => editRow(item, branch)} +        anchor={anchor} +        branch={branch} +      /> +    )); + +    const getHead = dataArray => dataArray.map((item, index) => { +      if (!item.hidden) { +        return ( +          <TableCell padding="none" key={index.toString()} width={item.width}>{item.label}</TableCell> +        ); +      } +      return false; +    }); +    return ( +      <div> +        <Toolbar className={classes.toolbar}> +          <div className={classes.title}> +            <Typography variant="h6">{title}</Typography> +          </div> +          <div className={classes.spacer} /> +          <div className={classes.actions}> +            <Tooltip title="Add Item"> +              <Button variant="contained" onClick={() => addNew(anchor, branch)} color="secondary" className={classes.button}> +                <AddIcon className={classNames(classes.leftIcon, classes.iconSmall)} /> +                Add New +              </Button> +            </Tooltip> +          </div> +        </Toolbar> +        <div className={classes.rootTable}> +          <Table className={classNames(css.tableCrud, classes.table, css.stripped)}> +            <TableHead> +              <TableRow> +                { getHead(anchor) } +              </TableRow> +            </TableHead> +            <TableBody> +              {getItems(items)} +            </TableBody> +          </Table> +        </div> +      </div> +    ); +  } +} + +MainTableForm.propTypes = { +  title: PropTypes.string.isRequired, +  classes: PropTypes.object.isRequired, +  items: PropTypes.object.isRequired, +  anchor: PropTypes.array.isRequired, +  addNew: PropTypes.func.isRequired, +  removeRow: PropTypes.func.isRequired, +  editRow: PropTypes.func.isRequired, +  branch: PropTypes.string.isRequired, +}; + +export default withStyles(styles)(MainTableForm); diff --git a/front/odiparpack/app/components/Tables/tableParts/Row.js b/front/odiparpack/app/components/Tables/tableParts/Row.js new file mode 100644 index 0000000..67e7a4d --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/Row.js @@ -0,0 +1,167 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import classNames from 'classnames'; +import DeleteIcon from '@material-ui/icons/Delete'; +import EditIcon from '@material-ui/icons/BorderColor'; +import DoneIcon from '@material-ui/icons/Done'; +import css from 'ba-styles/Table.scss'; +import { TableCell, IconButton } from '@material-ui/core'; +import EditableCell from './EditableCell'; +import SelectableCell from './SelectableCell'; +import ToggleCell from './ToggleCell'; +import DatePickerCell from './DatePickerCell'; +import TimePickerCell from './TimePickerCell'; + + +const styles = theme => ({ +  button: { +    margin: theme.spacing(1), +  }, +}); + +class Row extends React.Component { +  render() { +    const { +      classes, +      anchor, +      item, +      removeRow, +      updateRow, +      editRow, +      finishEditRow, +      branch +    } = this.props; +    const eventDel = () => { +      removeRow(item, branch); +    }; +    const eventEdit = () => { +      editRow(item, branch); +    }; +    const eventDone = () => { +      finishEditRow(item, branch); +    }; +    const renderCell = dataArray => dataArray.map((itemCell, index) => { +      if (itemCell.name !== 'action' && !itemCell.hidden) { +        const inputType = anchor[index].type; +        switch (inputType) { +          case 'selection': +            return ( +              <SelectableCell +                updateRow={(event) => updateRow(event, branch)} +                cellData={{ +                  type: itemCell.name, +                  value: item.get(itemCell.name), +                  id: item.get('id'), +                }} +                edited={item.get('edited')} +                key={index.toString()} +                options={anchor[index].options} +                branch={branch} +              /> +            ); +          case 'toggle': +            return ( +              <ToggleCell +                updateRow={(event) => updateRow(event, branch)} +                cellData={{ +                  type: itemCell.name, +                  value: item.get(itemCell.name), +                  id: item.get('id'), +                }} +                edited={item.get('edited')} +                key={index.toString()} +                branch={branch} +              /> +            ); +          case 'date': +            return ( +              <DatePickerCell +                updateRow={(event) => updateRow(event, branch)} +                cellData={{ +                  type: itemCell.name, +                  value: item.get(itemCell.name), +                  id: item.get('id'), +                }} +                edited={item.get('edited')} +                key={index.toString()} +                branch={branch} +              /> +            ); +          case 'time': +            return ( +              <TimePickerCell +                updateRow={(event) => updateRow(event, branch)} +                cellData={{ +                  type: itemCell.name, +                  value: item.get(itemCell.name), +                  id: item.get('id'), +                }} +                edited={item.get('edited')} +                key={index.toString()} +                branch={branch} +              /> +            ); +          default: +            return ( +              <EditableCell +                updateRow={(event) => updateRow(event, branch)} +                cellData={{ +                  type: itemCell.name, +                  value: item.get(itemCell.name), +                  id: item.get('id'), +                }} +                edited={item.get('edited')} +                key={index.toString()} +                inputType={inputType} +                branch={branch} +              /> +            ); +        } +      } +      return false; +    }); +    return ( +      <tr className={item.get('edited') ? css.editing : ''}> +        {renderCell(anchor)} +        <TableCell padding="none"> +          <IconButton +            onClick={() => eventEdit(this)} +            className={classNames((item.get('edited') ? css.hideAction : ''), classes.button)} +            aria-label="Edit" +          > +            <EditIcon /> +          </IconButton> +          <IconButton +            onClick={() => eventDone(this)} +            color="secondary" +            className={classNames((!item.get('edited') ? css.hideAction : ''), classes.button)} +            aria-label="Done" +          > +            <DoneIcon /> +          </IconButton> +          <IconButton +            onClick={() => eventDel(this)} +            className={classes.button} +            aria-label="Delete" +          > +            <DeleteIcon /> +          </IconButton> +        </TableCell> +      </tr> +    ); +  } +} + +Row.propTypes = { +  classes: PropTypes.object.isRequired, +  anchor: PropTypes.array.isRequired, +  item: PropTypes.object.isRequired, +  removeRow: PropTypes.func.isRequired, +  updateRow: PropTypes.func.isRequired, +  editRow: PropTypes.func.isRequired, +  finishEditRow: PropTypes.func.isRequired, +  branch: PropTypes.string.isRequired +}; + +export default withStyles(styles)(Row); diff --git a/front/odiparpack/app/components/Tables/tableParts/RowReadOnly.js b/front/odiparpack/app/components/Tables/tableParts/RowReadOnly.js new file mode 100644 index 0000000..7da655f --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/RowReadOnly.js @@ -0,0 +1,76 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import classNames from 'classnames'; +import css from 'ba-styles/Table.scss'; +import DeleteIcon from '@material-ui/icons/Delete'; +import EditIcon from '@material-ui/icons/BorderColor'; + +import { TableCell, IconButton } from '@material-ui/core'; + +const styles = theme => ({ +  button: { +    margin: theme.spacing(1), +  }, +}); + +class RowReadOnly extends React.Component { +  render() { +    const { +      anchor, +      classes, +      item, +      removeRow, +      editRow, +      branch +    } = this.props; +    const eventDel = () => { +      removeRow(item, branch); +    }; +    const eventEdit = () => { +      editRow(item, branch); +    }; +    const renderCell = dataArray => dataArray.map((itemCell, index) => { +      if (itemCell.name !== 'action' && !itemCell.hidden) { +        return ( +          <TableCell padding="none" key={index.toString()}> +            {item.get(itemCell.name) !== undefined ? item.get(itemCell.name).toString() : ''} +          </TableCell> +        ); +      } +      return false; +    }); +    return ( +      <tr> +        {renderCell(anchor)} +        <TableCell padding="none"> +          <IconButton +            onClick={() => eventEdit(this)} +            className={classNames((item.get('edited') ? css.hideAction : ''), classes.button)} +            aria-label="Edit" +          > +            <EditIcon /> +          </IconButton> +          <IconButton +            onClick={() => eventDel(this)} +            className={classes.button} +            aria-label="Delete" +          > +            <DeleteIcon /> +          </IconButton> +        </TableCell> +      </tr> +    ); +  } +} + +RowReadOnly.propTypes = { +  anchor: PropTypes.array.isRequired, +  classes: PropTypes.object.isRequired, +  item: PropTypes.object.isRequired, +  removeRow: PropTypes.func.isRequired, +  editRow: PropTypes.func.isRequired, +  branch: PropTypes.string.isRequired, +}; + +export default withStyles(styles)(RowReadOnly); diff --git a/front/odiparpack/app/components/Tables/tableParts/SelectableCell.js b/front/odiparpack/app/components/Tables/tableParts/SelectableCell.js new file mode 100644 index 0000000..66fde97 --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/SelectableCell.js @@ -0,0 +1,46 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import css from 'ba-styles/Table.scss'; + +import { Select, MenuItem, TableCell } from '@material-ui/core'; + +class SelectableCell extends React.Component { +  handleChange = event => { +    this.props.updateRow(event, this.props.branch); +    this.setState({ [event.target.name]: event.target.value }); +  }; + +  render() { +    const { +      cellData, +      edited, +      options, +    } = this.props; +    return ( +      <TableCell padding="none"> +        <Select +          name={cellData.type} +          id={cellData.id.toString()} +          className={css.crudInput} +          value={cellData.value} +          onChange={this.handleChange} +          displayEmpty +          disabled={!edited} +          margin="none" +        > +          {options.map((option, index) => <MenuItem value={option} key={index.toString()}>{option}</MenuItem>)} +        </Select> +      </TableCell> +    ); +  } +} + +SelectableCell.propTypes = { +  options: PropTypes.array.isRequired, +  cellData: PropTypes.object.isRequired, +  updateRow: PropTypes.func.isRequired, +  edited: PropTypes.bool.isRequired, +  branch: PropTypes.string.isRequired, +}; + +export default SelectableCell; diff --git a/front/odiparpack/app/components/Tables/tableParts/TableHeader.js b/front/odiparpack/app/components/Tables/tableParts/TableHeader.js new file mode 100644 index 0000000..4ef6b0d --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/TableHeader.js @@ -0,0 +1,74 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { TableCell, TableHead, TableRow, TableSortLabel, Checkbox, Tooltip } from '@material-ui/core'; + +class TableHeader extends React.Component { +  createSortHandler = property => event => { +    this.props.onRequestSort(event, property); +  }; + +  render() { +    const { +      onSelectAllClick, +      order, +      orderBy, +      numSelected, +      rowCount, +      columnData, +      checkcell +    } = this.props; + +    return ( +      <TableHead> +        <TableRow> +          {checkcell +            && ( +              <TableCell padding="checkbox" width="80"> +                <Checkbox +                  indeterminate={numSelected > 0 && numSelected < rowCount} +                  checked={numSelected === rowCount} +                  onChange={onSelectAllClick} +                /> +              </TableCell> +            ) +          } +          {columnData.map(column => ( +            <TableCell +              key={column.id} +              align={column.numeric ? 'right' : 'left'} +              padding={column.disablePadding ? 'none' : 'default'} +              sortDirection={orderBy === column.id ? order : false} +            > +              <Tooltip +                title="Sort" +                placement={column.numeric ? 'bottom-end' : 'bottom-start'} +                enterDelay={300} +              > +                <TableSortLabel +                  active={orderBy === column.id} +                  direction={order} +                  onClick={this.createSortHandler(column.id)} +                > +                  {column.label} +                </TableSortLabel> +              </Tooltip> +            </TableCell> +          ), this)} +        </TableRow> +      </TableHead> +    ); +  } +} + +TableHeader.propTypes = { +  numSelected: PropTypes.number.isRequired, +  onRequestSort: PropTypes.func.isRequired, +  onSelectAllClick: PropTypes.func.isRequired, +  order: PropTypes.string.isRequired, +  orderBy: PropTypes.string.isRequired, +  rowCount: PropTypes.number.isRequired, +  columnData: PropTypes.array.isRequired, +  checkcell: PropTypes.bool.isRequired, +}; + +export default TableHeader; diff --git a/front/odiparpack/app/components/Tables/tableParts/TableToolbar.js b/front/odiparpack/app/components/Tables/tableParts/TableToolbar.js new file mode 100644 index 0000000..940a82c --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/TableToolbar.js @@ -0,0 +1,123 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { withStyles } from '@material-ui/core/styles'; +import DeleteIcon from '@material-ui/icons/Delete'; +import ArchiveIcon from '@material-ui/icons/Archive'; +import BookmarkIcon from '@material-ui/icons/Bookmark'; +import FilterListIcon from '@material-ui/icons/FilterList'; +import SearchIcon from '@material-ui/icons/Search'; +import { +  Toolbar, +  Typography, +  IconButton, +  Tooltip, +  FormControl, +  Input, +  InputAdornment, +} from '@material-ui/core'; +import styles from './tableStyle-jss'; + + +class TableToolbar extends React.Component { +  state = { +    showSearch: false, +  } + +  toggleSearch() { +    this.setState({ showSearch: !this.state.showSearch }); +  } + +  handleChange(event) { +    event.persist(); +    this.props.onUserInput(event.target.value); +  } + +  render() { +    const { numSelected, classes, filterText } = this.props; +    const { showSearch } = this.state; + +    return ( +      <Toolbar +        className={classNames(classes.root, { +          [classes.highlight]: numSelected > 0, +        })} +      > +        <div className={classes.titleToolbar}> +          {numSelected > 0 ? ( +            <Typography color="inherit" variant="subtitle1"> +              {numSelected} +              {' '} +selected +            </Typography> +          ) : ( +            <Typography variant="h6">Nutrition</Typography> +          )} +        </div> +        <div className={classes.spacer} /> +        <div className={classes.actionsToolbar}> +          {numSelected > 0 ? ( +            <div> +              <Tooltip title="Bookmark"> +                <IconButton aria-label="Bookmark"> +                  <BookmarkIcon /> +                </IconButton> +              </Tooltip> +              <Tooltip title="Archive"> +                <IconButton aria-label="Archive"> +                  <ArchiveIcon /> +                </IconButton> +              </Tooltip> +              <Tooltip title="Delete"> +                <IconButton aria-label="Delete"> +                  <DeleteIcon /> +                </IconButton> +              </Tooltip> +            </div> +          ) : ( +            <div className={classes.actions}> +              {showSearch +                && ( +                  <FormControl className={classNames(classes.textField)}> +                    <Input +                      id="search_filter" +                      type="text" +                      placeholder="Search Desert" +                      value={filterText} +                      onChange={(event) => this.handleChange(event)} +                      endAdornment={( +                        <InputAdornment position="end"> +                          <IconButton aria-label="Search filter"> +                            <SearchIcon /> +                          </IconButton> +                        </InputAdornment> +                      )} +                    /> +                  </FormControl> +                ) +              } +              <Tooltip title="Filter list"> +                <IconButton +                  aria-label="Filter list" +                  className={classes.filterBtn} +                  onClick={() => this.toggleSearch()} +                > +                  <FilterListIcon /> +                </IconButton> +              </Tooltip> +            </div> +          )} +        </div> +      </Toolbar> +    ); +  } +} + +TableToolbar.propTypes = { +  classes: PropTypes.object.isRequired, +  filterText: PropTypes.string.isRequired, +  onUserInput: PropTypes.func.isRequired, +  numSelected: PropTypes.number.isRequired, +}; + +export default withStyles(styles)(TableToolbar); diff --git a/front/odiparpack/app/components/Tables/tableParts/TimePickerCell.js b/front/odiparpack/app/components/Tables/tableParts/TimePickerCell.js new file mode 100644 index 0000000..941df31 --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/TimePickerCell.js @@ -0,0 +1,66 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { TimePicker, MuiPickersUtilsProvider } from '@material-ui/pickers'; +import MomentUtils from '@date-io/moment'; +import css from 'ba-styles/Table.scss'; + +import { TableCell, InputAdornment, Icon, IconButton } from '@material-ui/core'; + +class TimePickerCell extends React.Component { +  state = { +    event: { +      target: { +        name: this.props.cellData.type, // eslint-disable-line +        value: this.props.cellData.value, // eslint-disable-line +      } +    } +  } + +  handleTimeChange = date => { +    const { event } = this.state; +    const { updateRow, branch } = this.props; +    event.target.value = date; +    updateRow(event, branch); +  } + +  render() { +    const { +      edited, +      cellData +    } = this.props; +    const { event } = this.state; +    return ( +      <TableCell padding="none"> +        <MuiPickersUtilsProvider utils={MomentUtils}> +          <TimePicker +            name={cellData.type} +            className={css.crudInput} +            mask={[/\d/, /\d/, ':', /\d/, /\d/, ' ', /a|p/i, 'M']} +            placeholder="08:00 AM" +            value={event.target.value} +            disabled={!edited} +            InputProps={{ +              endAdornment: ( +                <InputAdornment position="end"> +                  <IconButton> +                    <Icon>access_time</Icon> +                  </IconButton> +                </InputAdornment> +              ), +            }} +            onChange={this.handleTimeChange} +          /> +        </MuiPickersUtilsProvider> +      </TableCell> +    ); +  } +} + +TimePickerCell.propTypes = { +  cellData: PropTypes.object.isRequired, +  updateRow: PropTypes.func.isRequired, +  edited: PropTypes.bool.isRequired, +  branch: PropTypes.string.isRequired, +}; + +export default TimePickerCell; diff --git a/front/odiparpack/app/components/Tables/tableParts/ToggleCell.js b/front/odiparpack/app/components/Tables/tableParts/ToggleCell.js new file mode 100644 index 0000000..dc0af89 --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/ToggleCell.js @@ -0,0 +1,50 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import css from 'ba-styles/Table.scss'; + +import { TableCell, FormControlLabel, Switch } from '@material-ui/core'; + +class ToggleCell extends React.Component { +  state = { +    isChecked: this.props.cellData.value +  }; + +  handleChange = event => { +    this.setState({ isChecked: event.target.checked }); +    this.props.updateRow(event, this.props.branch); +  }; + +  render() { +    const { +      cellData, +      edited, +    } = this.props; +    return ( +      <TableCell className={css.toggleCell} padding="none" textalign="center"> +        <div className={classNames(css.coverReadonly, !edited ? css.show : '')} /> +        <FormControlLabel +          control={( +            <Switch +              name={cellData.type} +              id={cellData.id.toString()} +              className={css.crudInput} +              checked={this.state.isChecked} +              onChange={this.handleChange} +              value={cellData.value.toString()} +            /> +          )} +        /> +      </TableCell> +    ); +  } +} + +ToggleCell.propTypes = { +  cellData: PropTypes.object.isRequired, +  updateRow: PropTypes.func.isRequired, +  edited: PropTypes.bool.isRequired, +  branch: PropTypes.string.isRequired, +}; + +export default ToggleCell; diff --git a/front/odiparpack/app/components/Tables/tableParts/tableStyle-jss.js b/front/odiparpack/app/components/Tables/tableParts/tableStyle-jss.js new file mode 100644 index 0000000..bede0b8 --- /dev/null +++ b/front/odiparpack/app/components/Tables/tableParts/tableStyle-jss.js @@ -0,0 +1,63 @@ +import { lighten } from '@material-ui/core/styles/colorManipulator'; +const styles = theme => ({ +  root: { +    paddingRight: theme.spacing(1), +  }, +  rootTable: { +    width: '100%', +    marginTop: theme.spacing(3), +    overflowX: 'auto', +  }, +  highlight: +    theme.palette.type === 'light' ? { +      color: theme.palette.secondary.main, +      backgroundColor: lighten(theme.palette.secondary.light, 0.85), +    } : { +      color: theme.palette.text.primary, +      backgroundColor: theme.palette.secondary.dark, +    }, +  spacer: { +    flex: '1 1 100%', +  }, +  actionsToolbar: { +    color: theme.palette.text.secondary, +    flex: '1 0 auto', +  }, +  titleToolbar: { +    flex: '0 0 auto', +  }, +  filterBtn: { +    top: -5, +  }, +  textField: { +    flexBasis: 200, +    width: 300 +  }, +  table: { +    minWidth: 900, +  }, +  actions: { +    color: theme.palette.text.secondary, +    margin: 10 +  }, +  toolbar: { +    backgroundColor: theme.palette.grey[800], +  }, +  title: { +    flex: '0 0 auto', +    '& h6': { +      color: theme.palette.common.white +    } +  }, +  button: { +    margin: theme.spacing(1), +  }, +  iconSmall: { +    fontSize: 20, +  }, +  leftIcon: { +    marginRight: theme.spacing(1), +  }, +}); + +export default styles; | 
