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;
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
);
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.
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,
}),