Search code examples
javascriptreactjsredux-toolkit

Update/PUT doesnt work using Redux toolkit. data from frontend to slice goes as undefined. Check the picture


Let me tell you that my create(POST) and view(GET) works fine, but PUT or update doesn't work.

FrontEnd: send Invoice VIN number to modify/Update using PUT using Redux-Toolkit:

import Navigation from "../Auth/Navigation";
import Box from "@mui/material/Box";
import { useUpdateSavedInvoiceByIdMutation } from "../../../redux/api/invoiceApiSlice";

import { useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useState } from "react";

const SingleSavedInvoice = () => {
  const { id: invoiceID } = useParams();

  const [vinNumber, setVinNumber] = useState("12344024124474484");

  const [
    updateSavedInvoiceById,
    error,
    isLoading,
    isFetching,
    isError,
    isSuccess,
  ] = useUpdateSavedInvoiceByIdMutation();

  console.log(error, isLoading, isError, isSuccess, isFetching);

  const handleFormSubmit = async (e) => {
    e.preventDefault();
    try {
      const data = await updateSavedInvoiceById({
        vinNumber,
        invoiceID,
      });
      if (data?.error) {
        toast.error(data.error, {
          position: toast.POSITION.TOP_RIGHT,
          autoClose: 2000,
        });
      } else {
        toast.success(`VIN successfully updated`, {
          position: toast.POSITION.TOP_RIGHT,
          autoClose: 2000,
        });
      }
    } catch (err) {
      toast.error(err.data || err.error);
    }
  };

  return (
    <>
      <Box sx={{ display: "flex" }}>
        <Navigation />
        <Box component="main" sx={{ flexGrow: 1, p: 3 }}>
          <h2 className="text-center text-success h3">Edit Saved Invoice</h2>
          <hr className="mb-3" />
          <form onSubmit={handleFormSubmit}>
            <div className="container-fluid border mb-3">
              <div className="row mt-3 mb-3">
                <b className="h5 text-primary">Car Details</b>
                <div className="col-md-3">
                  <label htmlFor="name block">VIN # </label>
                  <input
                    type="text"
                    name="vinNumber"
                    className="p-4 mb-3 w-[30rem] border rounded-lg bg-[#101011] text-white "
                    value={vinNumber}
                    onChange={(e) => setVinNumber(e.target.value)}
                  />
                </div>
              </div>
            </div>
            <div className="container-fluid border mb-3 ">
              <div className="row mt-3 mb-3">
                <b className="h5 text-primary">Description</b>

                <div className="col-md-12">
                  <div className="form-group"></div>
                </div>
              </div>
            </div>
            <div className="button-box col-lg-12">
              <div className="row mt-4">
                <div className="col-md-3"></div>
                <div className="col-md-3">
                  <button
                    type="submit"
             
                    className="button-box btn btn-success  col-md-4 mt-3"
                  >
                    Submit Invoice
                  </button>
                </div>
              
              </div>
            </div>
          </form>
        </Box>
      </Box>
    </>
  );
};

export default SingleSavedInvoice;

InvoiceApiSlice below:

import { apiSlice } from "../../redux/api/apiSlice";
import { USERS_URL } from "../constants";

export const invoiceApiSlice = apiSlice.injectEndpoints({
  endpoints: (builder) => ({
    updateSavedInvoiceById: builder.mutation({
      query: ({ data, invoiceID }) => ({
        a: console.log(
          "I m in invoiceApiSlice at updateSavedInvoiceById",
          data,
          invoiceID
        ),
        url: `${USERS_URL}/invoice/savedInvoice/edit/${invoiceID}`,
        // url: `${EXPENSE_URL}/create-expense`,
        method: "PUT",
        body: data,
        // headers: { "Content-Type": "application/json" },
        // mode: "no-cors", 
        // credentials: "include", 
      }),
    }),

  }),
});

export const {
  useUpdateSavedInvoiceByIdMutation
} = invoiceApiSlice;

enter image description here

enter image description here

apiSlice:

import { fetchBaseQuery, createApi } from "@reduxjs/toolkit/query/react";
import { BASE_URL } from "../constants";

const baseQuery = fetchBaseQuery({ baseUrl: BASE_URL });

export const apiSlice = createApi({
  baseQuery,
  endpoints: () => ({}),
});

store:

export const store = configureStore({
  reducer: {
    auth: authReducer,
    [apiSlice.reducerPath]: apiSlice.reducer,
    [invoiceApiSlice.reducerPath]: invoiceApiSlice.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(
      apiSlice.middleware,
      invoiceApiSlice.middleware
    ),
  devTools: true,
});

setupListeners(store.dispatch);

export default store;

Invoice Controller:

static updateSavedInvoiceById = asyncHandler(async (req, res) => {
  try {
    const invoice = await Invoice.findById(req.params.id);
    const user = await UserModel.findById(_id);
    if (!invoice) {
      return res.status(404).json({ error: "invoice not found" });
    }
    if (invoice) {
      invoice.vinNumber = req.body.vinNumber;
      const latestInvoice = await invoice.save();
      user.invoiceCreatedByThisUser.push(latestInvoice);
      user.save();    
    } else {
      res.status(404);
      throw new Error("invoice not found");
    }
  } catch (error) {
    console.error(error);
    res.status(404).json({ error: " invoice not found" });
  }
});

Invoice Model:

import mongoose from "mongoose";
const { ObjectId } = mongoose.Schema;

const invoiceSchema = mongoose.Schema(
  {
    vinNumber: {
      type: Number,
      trim: true,
    },
  },
  { timestamps: true }
);

const Invoice = mongoose.model("invoice", invoiceSchema);

export default Invoice;

Invoice Routes:

router.put(
  "/savedInvoice/edit/:id",
  InvoiceController.updateSavedInvoiceById
);

Solution

  • Issue

    The query function takes an object and destructures data and invoiceID properties.

    query: ({ data, invoiceID }) => ({
      url: `${USERS_URL}/invoice/savedInvoice/edit/${invoiceID}`,
      method: "PUT",
      body: data,
    }),
    

    You are passing to the mutation trigger function an object with vinNumber and invoiceID properties.

    const data = await updateSavedInvoiceById({
      vinNumber,
      invoiceID,
    });
    

    The reason why data is undefined in the query function is because no key/value pair is passed for it.

    Solution

    Update the code so you are either pass the expected data property to the endpoint

    const data = await updateSavedInvoiceById({
      data: vinNumber,
      invoiceID,
    });
    

    or destructure the vinNumber property in the endpoint

    query: ({ invoiceID, vinNumber }) => ({
      url: `${USERS_URL}/invoice/savedInvoice/edit/${invoiceID}`,
      method: "PUT",
      body: vinNumber,
    }),