Click here to Skip to main content
15,867,704 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hello, I am trying to implement a loading spinner into my React app, but I have a problem with changing its state. It is supposed to appear when the data to display is being downloaded through Axios and then disappear. But right now it's just spinning forever. What am I doing wrong?

JavaScript
import React, { useState } from "react";
import customInstance from "../../api/axiosConfig";
import Grid from "@material-ui/core/Grid";
import Card from "@material-ui/core/Card";
import Box from "@material-ui/core/Box";
import Container from "@material-ui/core/Container";
import CardHeader from "@material-ui/core/CardHeader";
import TextField from "@material-ui/core/TextField";
import Moment from "moment";
import CheckOutlinedIcon from "@material-ui/icons/CheckOutlined";
import NotInterestedOutlinedIcon from "@material-ui/icons/NotInterestedOutlined";
import HourglassEmptyOutlinedIcon from "@material-ui/icons/HourglassEmptyOutlined";
import Button from "@material-ui/core/Button";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import GetAppIcon from "@material-ui/icons/GetApp";
import Modal from "@material-ui/core/Modal";
import Switch from "@material-ui/core/Switch";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import { Chip, FormControl, InputLabel, Typography } from "@material-ui/core";
import LoadingComponent from "../StatusPages/LoadingComponent";

function ProjectDetailsView(props) {
  const [project, setProject] = useState();
  const [ebit, setEbit] = useState();
  const [ebitPlus, setEbitPlus] = useState();
  const [ovi, setOvi] = useState();
  const [bussinessCFO, setBussinessCFO] = useState();
  const [bussinessController, setBussinessController] = useState();
  const [bussinessOwner, setBussinessOwner] = useState();
  const [backdropVisible, setBackdrop] = useState();
  const [modalOpen, setModalOpen] = useState(false);
  const [loading, setLoading] = useState(true);

  let additionalProjectEntities = props.additionalEntities.map((entity) => ({
    code: entity.entityCode,
    name: entity.entityName,
    
  }));

  function handleSend(projectId, approver) {
    let SendForApprovalCommand = {
      ProjectId: projectId,
      FirstApprover: approver,
    };
    customInstance
      .post("Approval", SendForApprovalCommand)
      .then((response) => {
        alert("Approval sent");
      })
      .catch((error) => {
        console.log(error);
        alert("First Level Approval Needed");
      });
  }

  function handleCancellation(project) {
    project.isCanceled = true;
    customInstance
      .put("Project/" + project.projectId, project)
      .then((res) => {
        alert("Project has been Canceled");
      })
      .then(setModalOpen(false));
  }

  return loading ? <LoadingComponent /> : (

    <div>
      <Container maxWidth="lg">
        <Modal
          open={modalOpen}
          onClose={() => setModalOpen(false)}
          aria-labelledby="child-modal-title"
          aria-describedby="child-modal-description"
        >
          <Box
            sx={{
              position: "absolute",
              top: "50%",
              left: "50%",
              transform: "translate(-50%, -50%)",
              width: 400,
              bgcolor: "background.paper",
              border: "2px solid #000",
              boxShadow: 24,
              pt: 2,
              px: 4,
              pb: 3,
              width: 600,
            }}
          >
            <h2 id="child-modal-title">Confirmation</h2>
            <p id="child-modal-description">
              Are you sure you want to cancel this project?
            </p>
            <Button
              variant="outlined"
              style={{ color: "#6fbf73", borderColor: "#6fbf73" }}
              onClick={() => handleCancellation(props.project)}
            >
              Yes, Cancel the Project
            </Button>
            <Button
              variant="outlined"
              onClick={() => setModalOpen(false)}
              style={{ color: "#f50057", borderColor: "#f50057" }}
            >
              No, Don't Cancel the Project
            </Button>
          </Box>
        </Modal>
        <fieldset disabled>
          <Grid container fluid="true" spacing={3}>
            <Grid item xs={12}>
              <h1 align="center">GP Project Sign-Off Approver Form</h1>
            </Grid>
            <Grid item xs={12} md={6}>
              <Card>
                <CardHeader
                  title="Project information"
                  align="center"
                  style={{ backgroundColor: "#002B45", color: "white" }}
                />
                <Box p={3}>
                  <Grid item xs={12}>
                    <TextField
                      name="projectName"
                      label="Project Name"
                      variant="outlined"
                      fullWidth
                      margin="normal"
                      value={props.project.projectName || ""}
                    />
                  </Grid>
                  <Grid item xs={12}>
                    <TextField
                      name="legalEntity"
                      label="Legal Entity Relevant for the Contract"
                      variant="outlined"
                      fullWidth
                      margin="normal"
                      value={props.project.entityName || ""}
                    />
                  </Grid>
                  <Grid item xs={12}>
                    <TextField
                      variant="outlined"
                      label="Additional Entities (if any)"
                      fullWidth
                      margin="normal"
                      InputProps={{
                        startAdornment: (
                          <Box  sx={{ pt: 1 }}>
                            {additionalProjectEntities.map((entity) => {
                              return (
                                <ListItem key={entity.code}>
                                  <Chip
                                    label={entity.code + " - " + entity.name}
                                  />
                                </ListItem>
                              );
                            })}
                          </Box>
                        ),
                      }}
                    />
                  </Grid>
                  <Grid item xs={12}>
                    <TextField
                      name="valueImprovementType"
                      label="Value Improvement Type"
                      variant="outlined"
                      fullWidth
                      margin="normal"
                      value={props.project.valueImprovementTypeName || ""}
                    />
                  </Grid>
                  <Grid item xs={12}>
                    <TextField
                      name="overallImprovementType"
                      label="Overall Improvement Type"
                      variant="outlined"
                      fullWidth
                      margin="normal"
                      value={props.project.overallImprovementTypeName || ""}
                    />
                  </Grid>
                  <Grid item xs={12}>
                    <TextField
                      name="nameOfSuplier"
                      id="outlined-read-only-input"
                      label="Name of Selected Supplier"
                      variant="outlined"
                      fullWidth
                      margin="normal"
                      value={props.project.nameOfSuplier || ""}
                    />
                  </Grid>
                  <Grid item xs={12}>
                    <Grid item xs={12} md={12}>
                      <TextField
                        name="contractStartDate"
                        id="date"
                        variant="outlined"
                        label="Start Date"
                        fullWidth
                        margin="normal"
                        value={
                          Moment(props.project.contractStartDate).format(
                            "YYYY-MM-DD"
                          ) || ""
                        }
                      />
                    </Grid>
                    <Grid item xs={12} md={12}>
                      <TextField
                        name="contractEndDate"
                        id="date"
                        variant="outlined"
                        label="End Date"
                        fullWidth
                        margin="normal"
                        value={
                          Moment(props.project.contractEndDate).format(
                            "YYYY-MM-DD"
                          ) || ""
                        }
                      />
                    </Grid>
                  </Grid>
                </Box>
              </Card>
              <Card>
                <CardHeader
                  title="Files"
                  align="center"
                  style={{ backgroundColor: "#002B45", color: "white" }}
                />
                <Box p={3}>
                  <Grid item xs={12} md={6}>
                    <FileList files={props.files} />
                  </Grid>
                </Box>
              </Card>
            </Grid>
            <Grid item xs={12} md={6}>
              <Grid item xs={12}>
                <Card>
                  <CardHeader
                    title="Group Procurement Information"
                    align="center"
                    style={{ backgroundColor: "#002B45", color: "white" }}
                  />
                  <Box p={3}>
                    <Grid item xs={12}>
                      <TextField
                        name="gpCategory"
                        label="GP Category"
                        variant="outlined"
                        fullWidth
                        margin="normal"
                        value={props.project.categoryName || ""}
                      />
                    </Grid>
                    <Grid item xs={12}>
                      <TextField
                        name="gpSubCategory"
                        label="GP Sub-Category"
                        variant="outlined"
                        fullWidth
                        margin="normal"
                        value={props.project.subCategoryName || ""}
                      />
                    </Grid>
                    <Grid item xs={12}>
                      <TextField
                        name="projectResponsible"
                        label="Project Responsible"
                        variant="outlined"
                        fullWidth
                        margin="normal"
                        value={props.project.projectResponsibleName || ""}
                      />
                    </Grid>
                    <Grid item xs={12}>
                      <TextField
                        label="Project number"
                        variant="outlined"
                        fullWidth
                        margin="normal"
                        value={props.project.fullProjectNumber || ""}
                      />
                    </Grid>
                    <Grid item xs={12}>
                      <FormControlLabel
                        control={
                          <Switch
                            id="isEbitda"
                            name="isEbitda"
                            checked={props.project.isEbitda || 0}
                            color="primary"
                          />
                        }
                        label="EBITDA"
                      />
                    </Grid>
                  </Box>
                </Card>
              </Grid>
              <Grid>
                <Card>
                  <CardHeader
                    title="Sign-Off Information"
                    align="center"
                    style={{ backgroundColor: "#002B45", color: "white" }}
                  />
                  <Box p={3}>
                    <Grid container item xs={12}>
                      <Grid item xs={6}>
                        <TextField
                          name="bussinessController"
                          label="Bussiness Controller"
                          variant="outlined"
                          fullWidth
                          margin="normal"
                          value={props.bussinessController.approverName || ""}
                        />
                      </Grid>
                      <Grid item xs={3}>
                        <Button disabled>
                          <IconBar
                            approvalStatusId={
                              props.bussinessController.approvalStatusId
                            }
                          />
                        </Button>
                      </Grid>
                      <Grid
                        item
                        xs={3}
                        className="item_styles_button"
                        alignItems="stretch"
                        style={{ display: "flex" }}
                      >
                        <Button
                          variant="outlined"
                          color="primary"
                          style={{ fontWeight: "bold", border: "2px solid" }}
                          onClick={() =>
                            handleSend(
                              props.project.projectId,
                              props.bussinessController.approverId
                            )
                          }
                        >
                          SEND
                        </Button>
                      </Grid>
                    </Grid>
                    <Grid container item xs={12}>
                      <Grid item xs={6}>
                        <TextField
                          name="bussinessOwner"
                          label="Bussiness Owner"
                          variant="outlined"
                          fullWidth
                          margin="normal"
                          value={props.bussinessOwner.approverName || ""}
                        />
                      </Grid>
                      <Grid item xs={3}>
                        <Button disabled>
                          <IconBar
                            approvalStatusId={
                              props.bussinessOwner.approvalStatusId
                            }
                          />
                        </Button>
                      </Grid>
                      <Grid
                        item
                        xs={3}
                        className="item_styles_button"
                        alignItems="stretch"
                        style={{ display: "flex" }}
                      >
                        <Button
                          variant="outlined"
                          color="primary"
                          style={{ fontWeight: "bold", border: "2px solid" }}
                          onClick={() =>
                            handleSend(
                              props.project.projectId,
                              props.bussinessOwner.approverId
                            )
                          }
                        >
                          SEND
                        </Button>
                      </Grid>
                    </Grid>
                    <Grid container item xs={12}>
                      <Grid item xs={6}>
                        <TextField
                          name="bussinessCFO"
                          label="Bussiness Divisional CFO/CFO"
                          variant="outlined"
                          fullWidth
                          margin="normal"
                          value={props.bussinessCFO.approverName || ""}
                        />
                      </Grid>
                      <Grid item xs={3}>
                        <Button disabled>
                          <IconBar
                            approvalStatusId={
                              props.bussinessCFO.approvalStatusId
                            }
                          />
                        </Button>
                      </Grid>
                      <Grid
                        item
                        xs={3}
                        className="item_styles_button"
                        alignItems="stretch"
                        style={{ display: "flex" }}
                      >
                        <Button
                          variant="outlined"
                          color="primary"
                          style={{ fontWeight: "bold", border: "2px solid" }}
                          onClick={() =>
                            handleSend(
                              props.project.projectId,
                              props.bussinessCFO.approverId
                            )
                          }
                        >
                          SEND
                        </Button>
                      </Grid>
                    </Grid>
                  </Box>
                </Card>
              </Grid>
            </Grid>
            <Grid item xs={12}>
              <h2 align="center">Improvement Calculation</h2>
            </Grid>
            <Grid item xs={12} md={4} lg={4}>
              <Card>
                <Box p={3}>
                  <CardHeader
                    title="EBIT"
                    align="center"
                    style={{ backgroundColor: "#002B45", color: "white" }}
                  />
                  <TextField
                    id="ebitTotalSpend"
                    label="Total spend / Baseline (DKK)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ebit.baseline || ""}
                  />
                  <TextField
                    id="ebitTotalSpendNewContract"
                    label="Total spend new contract (DKK)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ebit.totalSpend || ""}
                  />
                  <TextField
                    id="ebitImpactValue"
                    label="Impact (DKK)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ebit.impactValue || ""}
                  />
                  <TextField
                    id="ImpactPercentage"
                    label="Impact (%)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ebit.impactPercentage || ""}
                  />
                  <TextField
                    id="ebitdaDKK"
                    label="Ebitda (DKK)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ebit.ebitda || ""}
                  />
                </Box>
              </Card>
            </Grid>
            <Grid item xs={12} md={4} lg={4}>
              <Card>
                <Box p={3}>
                  <CardHeader
                    title="EBIT+"
                    align="center"
                    style={{ backgroundColor: "#002B45", color: "white" }}
                  />
                  <TextField
                    id="ebitPlusBaseline"
                    label="Total spend / Baseline (DKK)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ebitPlus.baseline || ""}
                  />
                  <TextField
                    id="ebitPlusTotalSpend"
                    label="Total spend new contract (DKK)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ebitPlus.totalSpend || ""}
                  />
                  <TextField
                    id="ebitPlusImpactValue"
                    label="Impact (DKK)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ebitPlus.impactValue || ""}
                  />
                  <TextField
                    id="ebitPlusImpactPercentage"
                    label="Impact (%)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ebitPlus.impactPercentage || ""}
                  />
                </Box>
              </Card>
            </Grid>
            <Grid item xs={12} md={4} lg={4}>
              <Card>
                <Box p={3}>
                  <CardHeader
                    title="OVI"
                    align="center"
                    style={{ backgroundColor: "#002B45", color: "white" }}
                  />
                  <TextField
                    id="oviBaseline"
                    label="Total spend / Baseline (DKK)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ovi.baseline || ""}
                  />
                  <TextField
                    id="oviTotalSpend"
                    label="Total spend new contract (DKK)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ovi.totalSpend || ""}
                  />
                  <TextField
                    id="oviImpactValue"
                    label="Impact (DKK)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ovi.impactValue || ""}
                  />
                  <TextField
                    id="oviImpactPercentage"
                    label="Impact (%)"
                    variant="outlined"
                    fullWidth
                    margin="normal"
                    value={props.ovi.impactPercentage || ""}
                  />
                </Box>
              </Card>
            </Grid>

            <Grid item xs={12}>
              <Card>
                <Box p={3}>
                  <CardHeader
                    title="Description"
                    align="center"
                    style={{ backgroundColor: "#002B45", color: "white" }}
                  />
                  <TextField
                    minRows={12}
                    multiline
                    maxRows={Infinity}
                    id="Description"
                    value={props.project.description}
                    variant="outlined"
                    fullWidth
                    margin="normal"
                  />
                </Box>
              </Card>
            </Grid>
            <Grid
              container
              justifyContent="center"
              style={{ height: "fit-content" }}
            >
              <Button
                variant="outlined"
                color="primary"
                aria-label="outlined button group"
                onClick={() => setModalOpen(true)}
              >
                Cancel Project
              </Button>
            </Grid>
          </Grid>
        </fieldset>
      </Container>
    </div>
  );
}

function IconBar(props) {
  switch (props.approvalStatusId) {
    case "6dfcedf7-2acf-47a7-b446-a82a7e166ce9": //Approved
      return <CheckOutlinedIcon />;
    case "d6ac8e69-d48a-4365-9032-e66af4835020": //Pending
      return <HourglassEmptyOutlinedIcon />;
    case "5e04924b-a618-4f77-8f96-7ae0c94893ce": //Declined
      return <NotInterestedOutlinedIcon />;
    case "1d8fae49-58bb-4b98-98b6-c246d449a0bf": //None
      return "Not sent";
  }
  return null;
}

function FileList(props) {
  function downloadFile(projectFileId, fileName) {
    customInstance.get("File/" + projectFileId).then((response) => {
      const a = document.createElement("a");
      a.href = response.data;
      a.download = response.data.split("/").pop();
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);

    });
  }

  if (props.files === undefined) {
    return null;
  } else {
    return (
      <List>
        {props.files.map((file) => (
          <Grid container item xs={12}>
            <Grid item xs={9}>
              <ListItem>
                <ListItemText primary={file.fileName} />
              </ListItem>
            </Grid>
            <Grid item xs={3}>
              <Button
                onClick={() => downloadFile(file.projectFileId, file.fileName)}
              >
                <ListItemIcon>
                  <GetAppIcon />
                </ListItemIcon>
              </Button>
            </Grid>
          </Grid>
        ))}
      </List>
    );
  }
}

export default class ProjectLockedView extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      project: {},
      ebit: {},
      ebitPlus: {},
      ovi: {},
      bussinessCFO: {},
      bussinessController: {},
      bussinessOwner: {},
      files: [],
      additionalEntities: [],
      loading: true
    };
  }

  componentDidMount() {
    this.getProjectDetails();
    this.getImprovementCalculations();
    this.getProjectUsers();
    this.getProjectFiles();
    this.getAdditionalEntities();
    this.setState({loading: false});
  }

  getProjectDetails() {
    customInstance
      .get("Project/" + this.props.id)
      .then((response) => {
        this.setState({ project: response.data });

      })
      .catch((error) => {
        console.log(error);
      });

  }

  getImprovementCalculations() {
    customInstance
      .get("ImprovementCalculation?projectId=" + this.props.id)
      .then((response) => {
        var ebit = response.data.filter((calculation) => {
          return calculation.calculationType == "EBIT";
        })[0];
        if (ebit != undefined) {
          this.setState({ ebit: ebit });
        }

        var ebitPlus = response.data.filter((calculation) => {
          return calculation.calculationType == "EBIT+";
        })[0];
        if (ebitPlus != undefined) {
          this.setState({ ebitPlus: ebitPlus });
        }

        var ovi = response.data.filter((calculation) => {
          return calculation.calculationType == "OVI";
        })[0];
        if (ovi != undefined) {
          this.setState({ ovi: ovi });
        }
      });
  }

  getProjectUsers() {
    customInstance
      .get("ProjectUser?projectId=" + this.props.id)
      .then((response) => {
        var controller = response.data.filter((user) => {
          return user.roleName == "Bussiness Controller";
        })[0];

        var cfo = response.data.filter((user) => {
          return user.roleName == "Bussiness CFO";
        })[0];

        var owner = response.data.filter((user) => {
          return user.roleName == "Bussiness Owner";
        })[0];

        if (cfo !== undefined) {
          this.setState({ bussinessCFO: cfo });
        }
        if (controller !== undefined) {
          this.setState({ bussinessController: controller });
        }
        if (owner !== undefined) {
          this.setState({ bussinessOwner: owner });
        }
      });
  }

  getProjectFiles() {
    customInstance.get("File?projectId=" + this.props.id).then((response) => {
      this.setState({ files: response.data });
    });
  }

  getAdditionalEntities() {
    customInstance
      .get("ProjectEntity?projectId=" + this.props.id)
      .then((response) => {
        this.setState({ additionalEntities: response.data });
      });
  }

  render() {
    return (

      <div>
        <ProjectDetailsView
          project={this.state.project}
          bussinessCFO={this.state.bussinessCFO}
          bussinessController={this.state.bussinessController}
          bussinessOwner={this.state.bussinessOwner}
          ebit={this.state.ebit}
          ebitPlus={this.state.ebitPlus}
          ovi={this.state.ovi}
          files={this.state.files}
          additionalEntities={this.state.additionalEntities}
        />
      </div>
    );
  }
}


What I have tried:

I am trying to change the state inside the componentDidMount function, but it's not changing anything:
JavaScript
componentDidMount() {
  this.getProjectDetails();
  this.getImprovementCalculations();
  this.getProjectUsers();
  this.getProjectFiles();
  this.getAdditionalEntities();
  this.setState({loading: false});
}
Posted
Updated 20-Apr-22 1:35am

1 solution

Use try catch and add this.setState({loading: false}); in catch block;

Also you may add loader at the begining of your componentDidMount instead of initializing it in constructor, I would prefer setting loader at function level so when api is called loading beings and when it finishes or error occurs loading stops.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900