0

我有以下反应组件:

class Statuses extends React.Component {
  constructor(props) {
    super();

    this.groups = props.groups;

    this.state = {
      statuses: [],
      editDialog: null,
      deleteDialog: null,
      editTransitionsDialog: null,
      transitions: null,
      editTransitionGroupsDialog: null,
      transition: null,
      groups: null,
      alert: null,
    };
  }

  componentDidMount() {
    this.fetchStatuses();
  }

  handleCloseAlert = () => {
    let alertType = this.props.alert.type;
    this.props.cleanCatalogsMessage();

    if (alertType == ALERT_SUCCESS) {
      this.setState({editDialog: null});
    }
  }

  TransitionRight = (props) => {
    return <Slide {...props} direction="right" />;
  }

  fetchStatuses = () => {
    this.props.fetchStatuses(this.props.currentForm.id)
  }

  handleEditClick = (id) => {
    if (id) {
      this.setState({editDialog: this.props.statuses.find(status => status.id === id)});
    } else {
      this.setState({editDialog: {id: null, name: null, description: null, color: '#808080'}})
    }
  }

  handleCloseEditDialog = (proceed) => {
    if (proceed) {
      this.saveStatus();
    } else {
      this.setState({editDialog: null});
    };
  }

  handleEditStatusChange = (e) => {
    let newEditDialog = Object.assign({}, this.state.editDialog)

    switch (e.target.name) {
      case 'status_name': {
        newEditDialog.name = e.target.value;
        break;
      }
      case 'status_description': {
        newEditDialog.description = e.target.value;
        break;
      }
      case 'status_slug': {
        newEditDialog.slug = e.target.value;
        break;
      }
      case 'status_color': {
        newEditDialog.color = e.target.value;
        break;
      }
      default: {
        alert("Error on handleEditTransitionChange");
      }
    }

    this.setState({editDialog: newEditDialog});
  }

  saveStatus = () => {
    if (this.state.editDialog.id) {
      this.updateStatus();
    } else {
      this.createStatus();
    }
  }

  updateStatus = () => {
    this.props.updateStatus(this.state.editDialog);
  }

  createStatus = () => {
    // const requestString = backendServer + 'api/general/statuses/';
    const form = {
      automat: this.props.currentForm.id,
      name: this.state.editDialog.name,
      description: this.state.editDialog.description,
      slug: this.state.editDialog.slug,
      color: this.state.editDialog.color,
    }

    this.props.createStatus(form);
  }

  handleDeleteClick = (id) => {
    this.setState({deleteDialog: this.state.statuses.find(status => status.id === id)});
  }

  handleCloseDeleteDialog = (proceed) => {
    if (proceed) {
      this.deleteStatus()
    } else {
      this.setState({deleteDialog: null});
    }
  }

  deleteStatus = () => {
    const requestString = backendServer + 'api/general/statuses/' + this.state.deleteDialog.id + '/';

    axios.delete(requestString, getAuthHeader())
      .then((Response) => {
        let newStatusesList = this.state.statuses.slice();
        let i = newStatusesList.findIndex((status) => status.id === this.state.deleteDialog.id);
        newStatusesList.splice(i, 1);

        newStatusesList.forEach((status) => {
          let j = status.transitions.findIndex((transition) => transition.id === this.state.deleteDialog.id)
          if (j > -1) {
            status.transitions.splice(j, 1);
          }
        })

        this.setState({statuses: newStatusesList, deleteDialog: null, alert: "¡El estado se ha eliminado con Éxito!"});
      })
      .catch((Error) => {
        const message = getErrorMessage(Error).message.message;

        alert(message)
      })
  }

  handleEditTransitionsClick = (id) => {
    let statusToEdit = this.props.statuses.find(status => status.id === id)

    this.setState({
      editTransitionsDialog: statusToEdit,
      transitions: statusToEdit.transitions.slice()
    });
  }

  handleEditTransitionsChange = (e) => {
    let newTransitionsList = null;

    if (e.target.checked) {
      newTransitionsList = this.state.transitions.slice();
      let statusToAdd = this.props.statuses.find((status) => status.name === e.target.name);
      let transitionToAdd = {id: statusToAdd.id, name: statusToAdd.name};

      newTransitionsList.push(transitionToAdd);
    } else {
      newTransitionsList = this.props.transitions.slice();
      let i = newTransitionsList.findIndex((transition) => transition.name === e.target.name);

      if (i > -1) {
        newTransitionsList.splice(i, 1);
      }
    }

    this.setState({transitions: newTransitionsList});
  }

  handleCloseEditTransitionsDialog = (proceed) => {
    if (proceed) {
      this.updateTransitions();
    } else {
      this.setState({editTransitionsDialog: null, transitions: null});
    }
  }

  updateTransitions = () => {
    let transitionsToAdd = this.state.transitions.filter(transition => !this.state.editTransitionsDialog.transitions.includes(transition));
    let transitionsToDelete = this.state.editTransitionsDialog.transitions.filter(transition => !this.state.transitions.includes(transition));

    const requestString = backendServer + 'api/general/set_transitions/' + this.state.editTransitionsDialog.id + '/';
    axios.post(requestString, {add: transitionsToAdd, delete: transitionsToDelete}, getAuthHeader())
      .then((Response) => {
        let newEditTransitionsDialog = Object.assign({}, this.state.editTransitionsDialog);

        transitionsToAdd.forEach((transition) => {
          newEditTransitionsDialog.transitions.push({id: transition.id, name: transition.name, groups: []});
        })

        transitionsToDelete.forEach((transition) => {
          let i = newEditTransitionsDialog.transitions.findIndex((transitionToEval) => transitionToEval.id === transition.id);
          newEditTransitionsDialog.transitions.splice(i, 1);
        })

        let newStatusesList = this.state.statuses.slice();
        let j = newStatusesList.findIndex((status) => status.id === this.state.editTransitionsDialog.id);

        newStatusesList[j] = newEditTransitionsDialog;

        this.setState({statuses: newStatusesList, editTransitionsDialog: null, transitions: null, alert: "¡Las transiciones se modificaron con éxito!"});
      })
      .catch((Error) => {
        const message = getErrorMessage(Error).message.message;

        alert(message)
      })
  }

  handleEditTransitionGroupsClick = (id, transition) => {
    let newEditTransitionGroupsDialog = Object.assign({}, this.props.statuses.find((status) => status.id === id));
    let newTransition = Object.assign({}, newEditTransitionGroupsDialog.transitions.find((transitionToEval) => transitionToEval.id === transition));

    this.setState({editTransitionGroupsDialog: newEditTransitionGroupsDialog, transition: newTransition, groups: newTransition.groups.slice()});
  }

  handleEditTransitionGroupsChange = (e) => {
    let newGroupsList = this.state.groups.slice();

    if (e.target.checked) {
      let newGroup = this.groups.find((group) => group.name === e.target.name);
      newGroupsList.push({id: newGroup.id, name: newGroup.name});
    } else {
      let i = this.groups.findIndex((group) => group.name === e.target.name);
      newGroupsList.splice(i, 1);
    }

    this.setState({groups: newGroupsList});
  }

  handleCloseEditTransitionGroupsDialog = (proceed) => {
    if (proceed) {
      this.updateGroups();
    } else {
      this.setState({editTransitionGroupsDialog: null, transition: null, groups: null});
    }
  }

  updateGroups = () => {
    let groupsToAdd = this.state.groups.filter(group => !this.state.transition.groups.includes(group));
    let groupsToDelete =this.state.transition.groups.filter(group => !this.state.groups.includes(group));
    
    const requestString = backendServer + 'api/general/set_groups/' + this.state.transition.id + '/';
    axios.post(requestString, {automat: this.props.currentForm.id, init_status: this.state.editTransitionGroupsDialog.id, final_status: this.state.transition.id, add: groupsToAdd, delete: groupsToDelete}, getAuthHeader())
      .then((Response) => {
        let newTransition = Object.assign({}, this.state.transition);
        newTransition.groups = this.state.groups.slice()

        let newStatus = Object.assign({}, this.state.editTransitionGroupsDialog);
        let i = newStatus.transitions.findIndex(transition => transition.id === newTransition.id);
        newStatus.transitions[i] = newTransition;

        let newStatusesList = this.state.statuses.slice();
        i = newStatusesList.findIndex(status => status.id === newStatus.id);
        newStatusesList[i] = newStatus;

        this.setState({
          statuses: newStatusesList, 
          editTransitionGroupsDialog: null, 
          transition: null, 
          groups: null,
          alert: "¡Los Grupos se modificaron con éxito!"
        });
      })
      .catch((Error) => {
        const message = getErrorMessage(Error).message.message;

        alert(message);
      })
  }

  StatusSnackbars = () => {
    const classes = useStylesStatusSnackBars();
    const [open, setOpen] = React.useState(false);
  
    const handleClick = () => {
      setOpen(true);
    };
  
    const handleClose = (event, reason) => {
      if (reason === 'clickaway') {
        return;
      }
  
      setOpen(false);
    };
  
    return (
      <div className={classes.root}>
        <Button variant="outlined" onClick={handleClick}>
          Open success snackbar
        </Button>
        <Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
          <Alert onClose={handleClose} severity="success">
            This is a success message!
          </Alert>
        </Snackbar>
        <Alert severity="error">This is an error message!</Alert>
        <Alert severity="warning">This is a warning message!</Alert>
        <Alert severity="info">This is an information message!</Alert>
        <Alert severity="success">This is a success message!</Alert>
      </div>
    );
  }
  
  StatusesTable = () => {
    return (
      <div width="100%">
        {this.props.statuses && this.props.statuses.map((status) => {
          return (<this.StatusEntry status={status} />)
        })}
      </div>
    )
  }

  StatusEntry = (status) => {
    const classes = useStylesStatusEntry();

    return (
      <Accordion>
        <AccordionSummary
          expandIcon={<ExpandMoreIcon />}
          aria-controls="panel1bh-content"
          id="panel1bh-header"
        >
          <div style={{paddingRight: "5px"}}>
            <Chip label={"[" + status.status.id + "]" + status.status.name} size="large" style={{color: "white", backgroundColor: status.status.color}}/>
          </div>
          <Typography className={classes.secondaryHeading}>{status.status.description}</Typography>
        </AccordionSummary>
        <AccordionDetails>
          <div>
            <div style={{display: "flex", alignContent: "center", paddingBottom: "10px"}}>
              <div style={{paddingRight: "5px"}}><Button color="primary" variant="contained" size="small" onClick={() => this.handleEditClick(status.status.id)}>Editar</Button></div>
              <div style={{paddingRight: "5px"}}><Button color="primary" variant="contained" size="small" onClick={() => this.handleEditTransitionsClick(status.status.id)}>Transiciones</Button></div>
              <div style={{paddingRight: "5px"}}><Button color="secondary" variant="contained" size="small" onClick={() => this.handleDeleteClick(status.status.id)}>Eliminar</Button></div>
            </div>
            <div>
              {status.status.transitions.map((transition) => (
                <div>
                  <IconButton aria-label="groups" size="small" color="primary" onClick={() => this.handleEditTransitionGroupsClick(status.status.id, transition.id)}>
                    <EditIcon fontSize="inherit" />
                  </IconButton>
                  <Chip label={transition.name} size="small" style={{color: transition.color}} variant="outlined"/>
                  {transition.groups.map((group => (
                    <Chip label={group.name} size="small" variant="outlined" />
                  )))}
                  <div fullwidth style={{paddingBottom: "5px", paddingTop: "5px"}}><Divider /></div>
                </div>
              ))}
            </div>
          </div>
        </AccordionDetails>
      </Accordion>
    )
  }

  render() {
    const getFinalStatusChip = () => {
      let finalStatus = this.props.statuses.find((status) => status.id === this.state.transition.id)

      return (
        <Chip label={finalStatus.name} size="large" style={{color: "white", backgroundColor: finalStatus.color}} />
      )
    }

    return (
      <div>
        <div style={{display: 'flex', paddingBottom: '5px'}}>
          <div className="col-10" style={{paddingTop: '5px'}}>
            <h1>Estados: {this.props.currentForm.name}</h1>
          </div>
          <div className="col-2">
            <Fab size="small" color="primary" aria-label="add" onClick={() => this.handleEditClick(null)}>
              <AddIcon />
            </Fab>
          </div>
        </div>
        <this.StatusesTable/>
        {this.state.editDialog && !this.props.showMessage &&
          <Dialog open={this.state.editDialog !== null} aria-labelledby="edit-dialog-title">
            {this.state.editDialog.id?
              <DialogTitle id="edit-dialog-title">Editar Estado: [{this.state.editDialog.id}]{this.state.editDialog.name}</DialogTitle>:
              <DialogTitle id="edit-dialog-title">Crear Estado: [ ] Nuevo Estado</DialogTitle>
            }
            <DialogContent>
              <TextField
                autoFocus
                margin="dense"
                id="status-name"
                name="status_name"
                label="Nombre"
                fullWidth
                value={this.state.editDialog.name}
                onChange={this.handleEditStatusChange}
              />
              <TextField
                margin="dense"
                id="status-description"
                name="status_description"
                label="Descripción"
                fullWidth
                multiline={true}
                rows={4}
                value={this.state.editDialog.description}
                onChange={this.handleEditStatusChange}
              />
              <TextField
                margin="dense"
                id="status_slug"
                name="status_slug"
                label="Slug"
                fullWidth
                multiline={false}
                value={this.state.editDialog.slug}
                onChange={this.handleEditStatusChange}
              />
              <div style={{paddingTop: "10px"}}>
                <p style={{color: "gray"}}>Color</p>
                <CompactPicker 
                  color={this.state.editDialog.color}
                  onChangeComplete={(color) => this.handleEditStatusChange({target: {name: "status_color", value: color.hex}})
                  }
                />
              </div>
            </DialogContent>
            <DialogActions>
              <Button onClick={() => this.handleCloseEditDialog(false)} color="primary">
                Cancelar
              </Button>
              <Button onClick={() => this.handleCloseEditDialog(true)} color="primary">
                Aceptar
              </Button>
            </DialogActions>
          </Dialog>
        }
        {this.state.deleteDialog && 
          <Dialog open={this.state.deleteDialog !== null} aria-labelledby="delete-dialog-title">
            <DialogTitle id="delete-dialog-title">Eliminar Estado: [{this.state.deleteDialog.id}]{this.state.deleteDialog.name}</DialogTitle>
            <DialogContent>
              <DialogContentText id="alert-dialog-description">
                <div style={{color: 'black'}}>
                  <span>¿Está seguro de que desea eliminar este Estado:?</span>
                  <div>
                    <Chip label={this.state.deleteDialog.name} size="large" style={{color: "white", backgroundColor: this.state.deleteDialog.color}} />
                  </div>
                </div>
              </DialogContentText>
            </DialogContent>
            <DialogActions>
              <Button color="primary" onClick={() => this.handleCloseDeleteDialog(true)}>
                Aceptar
              </Button>
              <Button color="primary" autoFocus onClick={() => this.handleCloseDeleteDialog(false)}>
                Cancelar
              </Button>
            </DialogActions>
          </Dialog>
        }
        {this.state.editTransitionsDialog &&
          <Dialog aria-labelledby="edit-transitions-dialog-title" open={this.state.editTransitionsDialog !== null}>
            <DialogTitle id="edit-transitions-dialog-title">Editar Transiciones</DialogTitle>
            <DialogContent dividers>
              <div>
                <Chip label={this.state.editTransitionsDialog.name} size="large" style={{color: "white", backgroundColor: this.state.editTransitionsDialog.color}} />
              </div>
              <div>
                <FormGroup row>
                  {this.props.statuses.map((status) => {
                    return (
                      <FormControlLabel
                        control={
                          <Checkbox
                            checked={this.state.transitions.find((transition) => transition.id === status.id)}
                            name={status.name}
                            color="primary"
                            onChange={this.handleEditTransitionsChange}
                          />
                        }
                        label={status.name}
                      />
                    )
                  })}
                </FormGroup>
              </div>
            </DialogContent>
            <DialogActions>
              <Button color="primary" onClick={() => this.handleCloseEditTransitionsDialog(true)}>
                Aceptar
              </Button>
              <Button color="primary" autoFocus onClick={() => this.handleCloseEditTransitionsDialog(false)}>
                Cancelar
              </Button>
            </DialogActions>
          </Dialog>
        }
        {this.state.editTransitionGroupsDialog &&
          <Dialog aria-labelledby="edit-transition-groups-dialog-title" open={this.state.editTransitionGroupsDialog !== null}>
            <DialogTitle id="edit-transition-groups-dialog-title">Editar Grupos</DialogTitle>
            <DialogContent dividers>
              <div>
                <Chip label={this.state.editTransitionGroupsDialog.name} size="large" style={{color: "white", backgroundColor: this.state.editTransitionGroupsDialog.color}} />
                <ArrowRightIcon />
                {getFinalStatusChip()}
              </div>
              <div>
              <FormGroup row>
                {this.groups.map((group) => {
                  return (
                    <FormControlLabel
                      control={
                        <Checkbox
                          name={group.name}
                          color="primary"
                          checked={this.state.groups.find((groupToEval) => groupToEval.id === group.id)}
                          onChange={this.handleEditTransitionGroupsChange}
                        />
                      }
                      label={group.name}
                    />
                  )
                })}
              </FormGroup>
              </div>
            </DialogContent>
            <DialogActions>
              <Button color="primary" onClick={() => this.handleCloseEditTransitionGroupsDialog(true)}>
                Aceptar
              </Button>
              <Button color="primary" autoFocus onClick={() => this.handleCloseEditTransitionGroupsDialog(false)}>
                Cancelar
              </Button>
            </DialogActions>
          </Dialog>
        }
        {this.props.showMessage &&
          <AttrAlert
            displayCase="alert_dialog"
            type={this.props.alert.type}
            message={this.props.alert.message}
            handleCloseAlert={this.handleCloseAlert}
          />}
      </div>
    )
  }
}

const mapStateToProps = ({auth, catalogs}) => {
  const {groups} = auth;
  const {statuses, alert, showMessage} = catalogs;

  return {groups, statuses, alert, showMessage};
}

const mapDispatchToProps = {
  fetchStatuses,
  createStatus,
  updateStatus,
  cleanCatalogsMessage
}

export default connect(mapStateToProps, mapDispatchToProps)(Statuses);

组件中出现错误StatusesTable。我已经调试并发现它this.StatusEntry永远不会执行,因为我在其中设置了一个断点,并且它永远不会到达,即使总是到达调用它的行中的断点也是如此。

所以StatusEntry永远不会执行,但在地图循环结束时会引发错误。这是我在检查器控制台中遇到的错误:

Error: Minified React error #130; visit https://reactjs.org/docs/error-decoder.html?invariant=130&args[]=undefined&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings.

这是错误的完整信息:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.

只有在节点版本为 10.19.0 的服务器中从缩小代码运行应用程序时才会出现此错误,但当从常规 JS 代码和节点版本 14.15.3 在本地运行时,它可以完美运行。

4

0 回答 0