自动完成:获取我从用户列表中选择的用户的 ID,post 状态为 400 的请求

AutoComplete: get the id for the user that i was choosen from users list, post request with status 400

我有这个项目,在邮递员中很清楚,我有一个请求,通过请求我必须将 invoiceId 发送到发票,除了消息之外还必须发送用户 ID,但真正的问题是我不知道如何获取用户ID,意思是当我打印“invoiceID”,“UserID”和“Message”时,invoiceID和message有一个值,但是UserID没有值就没有价值“undefined ”,原因是我有用户列表,我必须选择一个用户,然后我想为我选择的用户传递这个用户 ID,并在“assignToUser”函​​数中传递它,但我没有知道怎么做了。

在网络中我有这些错误:

在网络中我有这个错误:

enter image description here

我该如何解决我的问题?

invoiceSlice.js:

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
import FuseUtils from "@fuse/utils";
import { getInvoices } from "./invoicesSlice";

export const assignToUser = createAsyncThunk(
  "invoicesApp/invoice/assignToUser",
  async ({ invoiceId, userId, message }, { dispatch }) => {
    console.log("invoiceId, userId, message", invoiceId, userId, message);
    const response = await axios
      .post(`/invoices/flow/${invoiceId}/approve`, { userId, message })
      .catch((error) => {
        console.log("error response: ", error);
      });
    const data = await response.data.data;
    console.log("approve invoices: ", data);
    dispatch(getInvoices());
    return data;
  }
);

const invoiceSlice = createSlice({
  name: "invoicesApp/invoice",
  initialState: null,
  reducers: {
    resetInvoice: () => null,
    newInvoice: {
      reducer: (state, action) => action.payload,
      prepare: (event) => ({
        payload: {
          invoice: "",
          netAmount: 0,
          taxNumber: 0,
          grossAmount: 0,
          dueDate: "",
          issueDate: "",
        },
      }),
    },
  },
  extraReducers: {
    [assignToUser.fulfilled]: (state, action) => action.payload,
  },
});

export const { newInvoice, resetInvoice } = invoiceSlice.actions;

export default invoiceSlice.reducer;

approveUser.js:

import { Fragment, useState } from "react";
import { ButtonGroup } from "@material-ui/core";
import React from "react";
import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import { useTheme } from "@material-ui/core/styles";
import { useSnackbar } from "notistack";
import Slide from "@material-ui/core/Slide";
import {
  rejectInvoice,
  approveInvoice,
  assignToUser,
} from "../../store/invoiceSlice";
import { useDispatch, useSelector } from "react-redux";
import TextField from "@mui/material/TextField";
import FlagIcon from "@mui/icons-material/Flag";
import { makeStyles } from "@material-ui/core/styles";
import Autocomplete from "@mui/material/Autocomplete";
import { getUsers } from "../../store/invoiceSlice";
import { useEffect } from "react";

const useStyles = makeStyles((theme) => ({
  paper: { padding: "3rem", maxWidth: "990px", minWidth: "300px" },
  textStyle: {
    paddingLeft: "2rem",
  },
  formControl: {
    margin: theme.spacing(1),
    minWidth: 120,
  },
  selectEmpty: {
    marginTop: theme.spacing(2),
  },
  font: {
    fontSize: "5rem",
  },
}));

const GroupButttonApproveStatus = (id) => {
  const [dialogOpen, setDialogOpen] = useState(false);
  const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
  const [assignToUserDialog, setAssignToUserDialog] = useState(false);
  const { enqueueSnackbar, closeSnackbar } = useSnackbar();
  const dispatch = useDispatch();
  const theme = useTheme();
  const fullScreen = useMediaQuery(theme.breakpoints.down("sm"));
  const AssignToUserFullScreen = useMediaQuery(theme.breakpoints.down("md"));
  const classes = useStyles();

  const [users, setUsers] = useState([]);
  const [message, setMessage] = useState("");

  useEffect(() => {
    getUsers().then((response) => {
      setUsers(response);
    });
  }, []);
  // confirm

  console.log("users: ", users);

  const handleAssignToUserDialogOpen = () => {
    setAssignToUserDialog(true);
  };

  const handleAssignToUserDialogClose = () => setAssignToUserDialog(false);
  //   end assign to user
  const handleConfirmDialogClose = () => setConfirmDialogOpen(false);
  const handleClickConfirmDialogOpen = () => {
    setConfirmDialogOpen(true);
  };

  //end confirm

  const handleDialogClose = () => setDialogOpen(false);
  const handleClickOpen = () => {
    setDialogOpen(true);
  };

  const handleClose = () => {
    setDialogOpen(false);
  };

  const rejectInvoiceHandleClick = () => {
    enqueueSnackbar(
      "Invoice rejected successfully",
      { variant: "error" },
      {
        anchorOrigin: {
          vertical: "top",
          horizontal: "right",
        },
      },
      { TransitionComponent: Slide }
    );
  };

  const approveInvoiceHandleClick = () => {
    enqueueSnackbar(
      "Invoice approved successfully",
      { variant: "success" },
      {
        anchorOrigin: {
          vertical: "top",
          horizontal: "right",
        },
      },
      { TransitionComponent: Slide }
    );
  };
  return (
    <Fragment>
      <ButtonGroup size="large">
        <Button
          onClick={(ev) => {
            handleClickConfirmDialogOpen();
          }}
        >
          Approve
        </Button>
        <Button
          onClick={(ev) => {
            handleClickOpen();
          }}
        >
          Reject
        </Button>
        <Button
          onClick={(ev) => {
            handleAssignToUserDialogOpen();
          }}
        >
          Assign to User to approve
        </Button>
      </ButtonGroup>
      {/* reject Dialog */}
      <Dialog
        classes={{ paper: classes.paper }}
        maxWidth="sm"
        fullScreen={fullScreen}
        open={dialogOpen}
        onClose={handleDialogClose}
      >
        <DialogTitle style={{ fontWeight: "bold" }}>Reject Invoice</DialogTitle>
        <DialogContent>
          <div
            style={{
              backgroundColor: "#F8F9FA",
              borderRadius: 10,
              padding: "3rem",
            }}
          >
            <DialogContentText>
              <FlagIcon
                style={{ fontSize: 40, color: "#dc3c24", paddingRight: "1rem" }}
              />
              Do you really want to reject this invoice ?
            </DialogContentText>
            <DialogContentText>
              <FlagIcon
                style={{ fontSize: 40, color: "#F8F9FA", paddingRight: "1rem" }}
              />
              Keep in mind that once the invoice is rejected you won’t be able
              to proceed with it.
            </DialogContentText>
          </div>
        </DialogContent>
        <DialogActions>
          <div style={{ paddingRight: "1rem" }}>
            <Button
              onClick={handleClose}
              style={{ color: "#dc3c24", fontWeight: 500 }}
              autoFocus
            >
              Cancel
            </Button>
            <Button
              onClick={(ev) => {
                dispatch(rejectInvoice(id?.id));
                rejectInvoiceHandleClick(ev);
                handleClose();
              }}
              style={{ color: "#212529", fontWeight: 500 }}
              color="primary"
              autoFocus
            >
              Reject Invoice
            </Button>
          </div>
        </DialogActions>
      </Dialog>

      {/* End reject Dialog */}

      {/* Confirm Dialog */}
      <Dialog
        classes={{ paper: classes.paper }}
        maxWidth="sm"
        fullScreen={fullScreen}
        open={confirmDialogOpen}
        onClose={handleConfirmDialogClose}
      >
        <DialogTitle style={{ fontWeight: "bold" }}>
          Approve Invoice
        </DialogTitle>
        <DialogContent>
          <div
            style={{
              backgroundColor: "#F8F9FA",
              borderRadius: 10,
              padding: "3rem",
            }}
          >
            <DialogContentText>Almost ready for payment !</DialogContentText>
            <DialogContentText>
              By confirming you mark this invoice ready for approval.
            </DialogContentText>
          </div>
        </DialogContent>
        <DialogActions>
          <div style={{ paddingRight: "1rem" }}>
            <Button
              onClick={handleConfirmDialogClose}
              style={{ color: "#dc3c24", fontWeight: 500 }}
              autoFocus
            >
              Cancel
            </Button>
            <Button
              onClick={(ev) => {
                dispatch(approveInvoice(id?.id));
                approveInvoiceHandleClick(ev);
                handleConfirmDialogClose();
              }}
              style={{ color: "#212529", fontWeight: 500 }}
              color="primary"
              autoFocus
            >
              yes, Confirm
            </Button>
          </div>
        </DialogActions>
      </Dialog>

      {/* End Confirm Dialog */}

      {/* assign to user dialog */}

      <Dialog
        classes={{ paper: classes.paper }}
        maxWidth="sm"
        fullScreen={AssignToUserFullScreen}
        open={assignToUserDialog}
        onClose={handleAssignToUserDialogClose}
      >
        <DialogTitle style={{ fontWeight: "bold", fontSize: "3rem" }}>
          Request approval
        </DialogTitle>
        <div
          style={{
            backgroundColor: "#F8F9FA",
            borderRadius: 10,
            padding: "2rem",
            paddingLeft: "2rem",
          }}
        >
          <DialogContentText style={{ fontWeight: 600 }}>
            {" "}
            <FlagIcon
              style={{ fontSize: 40, color: "#aacc00", paddingRight: "1rem" }}
            />
            Send an invoice approval request to a team member.
          </DialogContentText>
          <DialogContentText style={{ paddingLeft: 10 }}>
            The assigned member will receive a notification asking them to
            approve this invoice. Once they accept, payment is on the way!
          </DialogContentText>
        </div>

        <DialogTitle>Assign a member to approve</DialogTitle>
        <DialogContent>
          <Autocomplete
            id="combo-box-demo"
            // value={users || ""}
            options={users || []}
            getOptionLabel={(option) => option.name || ""}
            sx={{ width: 860 }}
            renderInput={(params) => (
              <TextField
                {...params}
                placeholder="Search Member"
                fullWidth
                InputProps={{ ...params.InputProps, style: { fontSize: 17 } }}
                InputLabelProps={{ style: { fontSize: 17 } }}
              />
            )}
          />
        </DialogContent>
        <DialogContent style={{ marginTop: "15rem" }}>
          <form className={classes.root} noValidate autoComplete="off">
            <TextField
              value={message}
              onChange={(e) => setMessage(e.target.value)}
              id="outlined-basic"
              variant="outlined"
              placeholder="Add a message"
              fullWidth
              size="medium"
              InputProps={{ style: { fontSize: 17 } }}
              InputLabelProps={{ style: { fontSize: 17 } }}
            />
          </form>
        </DialogContent>
        <DialogActions>
          <div style={{ paddingRight: "1rem" }}>
            <Button
              onClick={handleAssignToUserDialogClose}
              style={{ color: "#dc3c24", fontWeight: 500 }}
              autoFocus
            >
              Cancel
            </Button>
            <Button
              onClick={(ev) => {
                dispatch(assignToUser(id?.id, users.id, message));
                approveInvoiceHandleClick(ev);
                handleAssignToUserDialogClose();
              }}
              style={{ color: "#212529", fontWeight: 500 }}
              color="primary"
              autoFocus
            >
              Assign to approve
            </Button>
          </div>
        </DialogActions>
      </Dialog>
    </Fragment>
  );
};

export default GroupButttonApproveStatus;

invoiceDetails.js:

import React from "react";
import { getInvoice } from "../../store/invoiceSlice";
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import Grid from "@material-ui/core/Grid";
import TextField from "@material-ui/core/TextField";
import moment from "moment";
import InputAdornment from "@material-ui/core/InputAdornment";
import TodayIcon from "@material-ui/icons/Today";
import { makeStyles } from "@material-ui/core/styles";
import RejectDialog from "./rejectDialog";
import GroupButton from "./groupButttonReviewStatus";
import GroupButttonReviewStatus from "./groupButttonReviewStatus";
import GroupButttonApproveStatus from "./groupButtonApproveStatus";
import GroupButttonPaymentStatus from "./groupButtonPaymentStatus";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import { useTheme } from "@material-ui/core/styles";

const useStyles = makeStyles((theme) => ({
  root: {
    "& > *": {
      margin: theme.spacing(1),
    },
  },
  input: {
    display: "none",
  },
  button: {
    margin: theme.spacing(1),
    // padding: theme.spacing(4),
  },
}));

const InvoiceDetails = () => {
  const classes = useStyles();
  const theme = useTheme();
  const routeParams = useParams();
  const [invoice, setInvoice] = useState([]);
  const [open, setOpen] = React.useState(false);
  const anchorRef = React.useRef(null);
  const [selectedIndex, setSelectedIndex] = React.useState(1);
  const breakpoint = useMediaQuery(theme.breakpoints.down("sm"));
  // const defaultLayoutPluginInstance = defaultLayoutPlugin();

  useEffect(() => {
    getInvoice(routeParams).then((response) => {
      setInvoice(response);
    });
  }, []);

  const handleClick = () => {
    console.info(`You clicked ${options[selectedIndex]}`);
  };

  const handleMenuItemClick = (event, index) => {
    setSelectedIndex(index);
    setOpen(false);
  };

  const handleToggle = () => {
    setOpen((prevOpen) => !prevOpen);
  };

  const handleClose = (event) => {
    if (anchorRef.current && anchorRef.current.contains(event.target)) {
      return;
    }

    setOpen(false);
  };

  console.log("invoice url: ", invoice?.file?.url);
  console.log("invoice tara : ", invoice);

  const statusGropButton = (status, id) => {
    switch (status) {
      case "review_pending":
        return <GroupButttonReviewStatus id={id} />;
      case "approval_pending":
        return <GroupButttonApproveStatus id={id} />;
      case "payment_pending":
        return <GroupButttonPaymentStatus id={id} />;
      case "rejected":
        return <GroupButton id={id} />;
      default:
        return;
    }
  };

  return (
    <>
      <Grid container>
        <Grid item xs={7} sm={7}>
          {/* pdf viewer */}
          <object
            // data={invoice?.file?.url}
            data="https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea%20Brochure.pdf"
            type="application/pdf"
            width="100%"
            height="100%"
          >
            <p>
              Alternative text - include a link{" "}
              <a href="https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea%20Brochure.pdf">
                to the PDF!
              </a>
            </p>
          </object>
        </Grid>

        <Grid item xs={5} sm={5} style={{ padding: "4rem" }}>
          <Grid item>
            <h1 style={{ fontWeight: "bold" }}>Invoice Details</h1>
          </Grid>

          <Grid item style={{ marginTop: "3rem", marginBottom: "2rem" }}>
            <Grid item style={{ marginBottom: 10 }}>
              <h3>From</h3>
            </Grid>
            <Grid item>
              <h3>{invoice?.submittedBy?.name || ""}</h3>
            </Grid>
            <Grid item>
              <h3>{invoice?.submittedBy?.email || ""}</h3>
            </Grid>
          </Grid>

          <Grid item>
            <Grid container item direction={breakpoint ? "row" : "column"}>
              <Grid
                container
                item
                xs={3}
                sm={3}
                direction="row"
                justifyContent="flex-start"
                alignItems="center"
              >
                <h3>Invoice ID</h3>
              </Grid>
              <Grid item xs={12} sm={12}>
                <TextField
                  className="mt-8 mb-16"
                  id="outlined-size-normal"
                  value={invoice.id || ""}
                  variant="outlined"
                  fullWidth
                />
              </Grid>
            </Grid>

            <Grid container item direction={breakpoint ? "row" : "column"}>
              <Grid
                container
                item
                xs={3}
                sm={3}
                direction="row"
                justifyContent="flex-start"
                alignItems="center"
              >
                <h3>Issue Date</h3>
              </Grid>
              <Grid item xs={12} sm={12}>
                <TextField
                  className="mt-8 mb-16"
                  id="outlined-size-normal"
                  value={
                    moment(moment.utc(invoice.issueDate).toDate())
                      .local()
                      .format("YYYY-MM-DD HH:mm:ss") || ""
                  }
                  variant="outlined"
                  InputProps={{
                    endAdornment: (
                      <InputAdornment position="start">
                        <TodayIcon />
                      </InputAdornment>
                    ),
                  }}
                  fullWidth
                />
              </Grid>
            </Grid>

            <Grid container item direction={breakpoint ? "row" : "column"}>
              <Grid
                container
                item
                xs={3}
                sm={3}
                direction="row"
                justifyContent="flex-start"
                alignItems="center"
              >
                <h3>Due Date</h3>
              </Grid>
              <Grid item xs={12} sm={12}>
                <TextField
                  className="mt-8 mb-16"
                  id="outlined-size-normal"
                  value={
                    moment(moment.utc(invoice.dueDate).toDate())
                      .local()
                      .format("YYYY-MM-DD HH:mm:ss") || ""
                  }
                  variant="outlined"
                  InputProps={{
                    endAdornment: (
                      <InputAdornment position="start">
                        <TodayIcon />
                      </InputAdornment>
                    ),
                  }}
                  fullWidth
                />
              </Grid>
            </Grid>

            <Grid container item direction={breakpoint ? "row" : "column"}>
              <Grid
                container
                item
                xs={3}
                sm={3}
                direction="row"
                justifyContent="flex-start"
                alignItems="center"
              >
                <h3>Net Amount</h3>
              </Grid>
              <Grid item xs={12} sm={12}>
                <TextField
                  className="mt-8 mb-16"
                  id="outlined-size-normal"
                  value={invoice.netAmount || ""}
                  variant="outlined"
                  fullWidth
                />
              </Grid>
            </Grid>

            <Grid container item direction={breakpoint ? "row" : "column"}>
              <Grid
                container
                item
                xs={3}
                sm={3}
                direction="row"
                justifyContent="flex-start"
                alignItems="center"
              >
                <h3>Tax Number</h3>
              </Grid>
              <Grid item xs={12} sm={12}>
                <TextField
                  className="mt-8 mb-16"
                  id="outlined-size-normal"
                  value={invoice.taxNumber || ""}
                  variant="outlined"
                  fullWidth
                />
              </Grid>
            </Grid>

            <Grid container item direction={breakpoint ? "row" : "column"}>
              <Grid
                container
                item
                xs={3}
                sm={3}
                direction="row"
                justifyContent="flex-start"
                alignItems="center"
              >
                <h3>Gross Amount</h3>
              </Grid>
              <Grid item xs={12} sm={12}>
                <TextField
                  className="mt-8 mb-16"
                  // label="Size"
                  id="outlined-size-normal"
                  value={invoice.grossAmount || ""}
                  variant="outlined"
                  fullWidth
                />
              </Grid>
            </Grid>

            <Grid
              container
              direction="row"
              justifyContent="center"
              alignItems="center"
              style={{ marginTop: "3rem" }}
            >
              <Grid item>{statusGropButton(invoice.status, invoice?.id)}</Grid>
            </Grid>
          </Grid>
        </Grid>
      </Grid>
    </>
  );
};

export default InvoiceDetails;

和此代码:

useEffect(() => {
    getUsers().then((response) => {
      setUsers(response);
    });
  }, []);

return:

根据你的代码,我观察到了这一点。

  • 您已经在 statusGropButton(invoice.status, invoice?.id) 方法中传递了 invoice?.id
  • 您再次期望输入 id 作为 assignToUser(id?.id, users.id, message) 中的 id?.id。为什么?

只是假设,因此 invoiceId 将变为 undefined。尝试在调用 api 函数时仅传递 id 而不是 id?.id

您正在使用 assignToUserDialog 标志打开 Dialogue。提交表单时,您正在执行 dispatch(assignToUser(id?.id, users.id, message));,其中 users 是一个数组。这就是您获得 undefined 的原因。我建议您保留打开对话的特定用户信息,并将该特定 user.id 发送到 API 调用。

发送请求时未定义invoiceId,可以查看assignToUser