'Getting null when I use context.query with getServerSideProps() in Nextjs?
Intro
Basically, I am building an e-commerce website. But I got stuck in this problem while saving the order details after I click payment button (although I had not used any payment gateway).
Problem
After selecting the items in cart , I fill the details in Checkout page and go to pay option to confirm order. In this checkout page I call addorder api which first do some checks(like whether item got out of stock or not) on the product in cart and then create new order.
After creating a new order in order DB (MOngo DB I am using), I goto order page like this with my orderId
res.redirect('/order/' + orderToAdd.orderId, 200);
After clicking the pay button shown in the image above, it redirects to http://localhost:3000/order/814407650978 giving 404 (Not Found).
Thus when I fetch the order details from the MyOrder.js using context.query.orderId, from getServerSideProps() , I am getting null.
export async function getServerSideProps(context) {
if (!mongoose.connections[0].readyState) {
await mongoose.connect(process.env.MONGO_URI);
}
let order = await Order.findById({orderId:context.query.orderId})
console.log("got = ", order);
return {
props: { order: JSON.parse(JSON.stringify(order)) }, // will be passed to the page component as props
};
}
You can see full code below
Code
This is a complete order DB entry, where I am only sending the products object to MyOrder.js
complete order = {
email: '[email protected]',
orderId: '869972292107',
paymentInfo: 'No payment info',
products: {
'wear-the-chess-king-M-Red': {
qty: 2,
price: 599,
name: 'King Chess Stylish Men’s t-Shirt',
size: 'M',
variant: 'Red'
}
},
address: 'A-22\nVinayak campus',
subtotal: 1198,
status: 'Paid',
_id: new ObjectId("626bd1bd01597b226fc76531"),
createdAt: 2022-04-29T11:53:33.046Z,
updatedAt: 2022-04-29T11:53:33.046Z,
__v: 0
}
Checkout.js
import React, { useState } from "react";
import { AiFillPlusCircle, AiFillMinusCircle } from "react-icons/ai";
import { MdOutlinePayment } from "react-icons/md";
import { useRouter } from "next/router";
import "react-toastify/dist/ReactToastify.css";
import { toast, ToastContainer } from "react-toastify";
// Added payment AiOutlineGateway, but due to no merchant key, it is creating invalid checksum => hence push to different branch in both local & remote
const Checkout = ({ cart, clearCart, subtotal, addToCart, removeFromCart }) => {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [phone, setPhone] = useState("");
const [address, setAddress] = useState("");
const [pincode, setPincode] = useState("");
const [city, setCity] = useState("");
const [statemap, setStatemap] = useState("");
const [disable, setDisable] = useState(true);
const router = useRouter();
const handleChange = async (e) => {
if (e.target.name === "name") {
setName(e.target.value);
} else if (e.target.name === "email") {
setEmail(e.target.value);
} else if (e.target.name === "phone") {
setPhone(e.target.value);
} else if (e.target.name === "address") {
setAddress(e.target.value);
} else if (e.target.name === "pincode") {
setPincode(e.target.value);
if (e.target.value.length == 6) {
let pins = await fetch(`${process.env.NEXT_PUBLIC_HOST}/api/pincode`);
let pinjson = await pins.json();
//console.log(pinjson)
if (Object.keys(pinjson).includes(e.target.value)) {
setCity(pinjson[e.target.value][0]);
setStatemap(pinjson[e.target.value][1]);
} else {
setCity("");
setStatemap("");
}
} else {
setCity("");
setStatemap("");
}
}
if (name && email && phone && address && pincode) setDisable(false);
else setDisable(true);
};
const initiateOrder = async () => {
let oid = Math.floor(Math.random() * Date.now());
const data = {
cart: cart,
subtotal: subtotal,
oid: oid,
email: email,
name: name,
address: address,
pincode: pincode,
phone: phone,
};
//console.log(JSON.stringify(data));
let res = await fetch(`${process.env.NEXT_PUBLIC_HOST}/api/addorder`, {
method: "POST", // or 'PUT'
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
let response = await res.json();
//console.log("response from order- ", response);
if (response.success === true) {
localStorage.setItem("token", response.authToken);
toast.success("Order Added Successfully!", {
position: "bottom-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
setTimeout(() => {
router.push("/order");
}, 2500);
} else {
if(response.error === "err1"){
toast.error("Total price of your cart have changed accidently", {
position: "bottom-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
}
else if(response.error === "err2"){
toast.error("Some items in your cart went out of stock !", {
position: "bottom-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
}
else if(response.error === "err5"){
toast.error("Prices of some of the items in your cart have changed !", {
position: "bottom-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
}
else {
toast.error("Error in Adding Order !", {
position: "bottom-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
}
}
};
return (
<>
<div className="container px-2 sm:m-auto">
<ToastContainer
position="bottom-center"
autoClose={2000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
/>
<h1 className="text-xl md:text-3xl text-center my-8 font-semibold">
Checkout
</h1>
{/* part 1 */}
<h2 className="text-xl my-4 font-semibold">1. Delivery Details</h2>
<div className="mx-auto flex">
<div className="px-2 w-1/2">
<div className="mb-4">
<label htmlFor="name" className="leading-7 text-sm text-gray-600">
Name
</label>
<input
type="name"
id="name"
name="name"
value={name}
onChange={handleChange}
className="w-full bg-white rounded border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
/>
</div>
</div>
<div className="px-2 w-1/2">
<div className=" mb-4">
<label
htmlFor="email"
className="leading-7 text-sm text-gray-600"
>
Email
</label>
<input
type="email"
id="email"
name="email"
value={email}
onChange={handleChange}
className="w-full bg-white rounded border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
/>
</div>
</div>
</div>
<div className="px-2 w-full">
<div className=" mb-4">
<label
htmlFor="address"
className="leading-7 text-sm text-gray-600"
>
Address
</label>
<textarea
id="address"
name="address"
value={address}
onChange={handleChange}
className="w-full bg-white rounded border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
/>
</div>
</div>
<div className="mx-auto flex">
<div className="px-2 w-1/2">
<div className="mb-4">
<label
htmlFor="phone"
className="leading-7 text-sm text-gray-600"
>
Phone
</label>
<input
type="text"
id="phone"
name="phone"
value={phone}
onChange={handleChange}
className="w-full bg-white rounded border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
/>
</div>
</div>
{/* city */}
<div className="px-2 w-1/2">
<div className=" mb-4">
<label
htmlFor="pincode"
className="leading-7 text-sm text-gray-600"
>
Pincode
</label>
<input
type="text"
id="pincode"
name="pincode"
value={pincode}
onChange={handleChange}
className="w-full bg-white rounded border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
/>
</div>
</div>
</div>
<div className="mx-auto flex">
<div className="px-2 w-1/2">
<div className="mb-4">
<label
htmlFor="state"
className="leading-7 text-sm text-gray-600"
>
State
</label>
<input
type="text"
id="state"
name="state"
value={statemap}
className="w-full bg-white rounded border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
onChange={handleChange}
/>
</div>
</div>
<div className="px-2 w-1/2">
<div className=" mb-4">
<label htmlFor="city" className="leading-7 text-sm text-gray-600">
City
</label>
<input
type="text"
id="city"
name="city"
value={city}
className="w-full bg-white rounded border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
onChange={handleChange}
/>
</div>
</div>
</div>
{/* part 2 */}
<h2 className="text-xl my-4 font-semibold">2. Review Cart Items</h2>
<div className="z-10 sideCart p-6 mx-2 my-4 bg-blue-100 border-[1px] border-blue-800 rounded">
<ol className="list-decimal font-semibold">
{Object.keys(cart).length === 0 && (
<div className="mt-5 text-center text-xl font-extralight">
Your Cart is Empty :(
</div>
)}
{
//k is cart {k: {name, price,qty,size,variant} }
Object.keys(cart).map((k) => {
return (
<li key={k}>
<div className="flex item my-5 items-center justify-between">
<div className=" font-semibold">
{cart[k].name} [{cart[k].variant} - {cart[k].size}]
</div>
<div className="w-1/3 font-semibold flex items-center justify-center">
<AiFillPlusCircle
onClick={() =>
addToCart(
k,
1,
cart[k].price,
cart[k].name,
cart[k].size,
cart[k].variant
)
}
className="text-blue-700 text-xl cursor-pointer"
/>
<span className="mx-2 text-sm">{cart[k].qty}</span>
<AiFillMinusCircle
onClick={() =>
removeFromCart(
k,
1,
cart[k].price,
cart[k].name,
cart[k].size,
cart[k].variant
)
}
className="text-blue-700 text-xl cursor-pointer"
/>
</div>
</div>
</li>
);
})
}
</ol>
<span className="subtotal text-xl font-extrabold">
Subtotal : ₹ {subtotal} /-
</span>
</div>
<button
disabled={disable}
onClick={initiateOrder}
className="disabled:bg-blue-300 flex text-white bg-blue-500 border-0 py-2 px-3 focus:outline-none hover:bg-blue-600 rounded text-base mx-2 my-4"
>
<MdOutlinePayment className="m-1" />
Pay ₹ {subtotal}
</button>
</div>
</>
);
};
export default Checkout;
/api/addorder.js
import connectDB from "../../middleware/mongoose";
import Order from "../../models/Order";
import Product from "../../models/Product";
const handler = async (req, res) => {
if (req.method === "POST") {
let product,
sumtotal = 0;
for (let item in req.body.cart) {
//got key(slug) as item
console.log(item);
sumtotal += req.body.cart[item].qty * req.body.cart[item].price;
product = await Product.findOne({ slug: item });
//TODO1: check if cart is tampered or not
if (product.price !== req.body.cart[item].price) {
res.status(500).json({ success: false, error: "err1" });
//console.log("ResT - ",res.json)
return;
}
//TODO2: check if cart items are out of stock
if (product.availableQty < req.body.cart[item].qty) {
res.status(500).json({ success: false, error: "err2" });
return;
}
}
//console.log("sumtotal = ",sumtotal," and subtotal = ",req.body.subtotal)
if (sumtotal != req.body.subtotal) {
res.status(500).json({ success: false, error: "err5" });
//console.log("ResP - ",res)
return;
}
//TODO3: check if details are valid or not
let orderToAdd = new Order({
email: req.body.email,
orderId: req.body.oid,
address: req.body.address,
subtotal: req.body.subtotal,
products: req.body.cart,
status: "Paid",
});
await orderToAdd.save();
let ordered_products = orderToAdd.products;
console.log("Orederd pro = ", ordered_products);
console.log("complete order = ", orderToAdd)
for (let slug in ordered_products) {
await Product.findOneAndUpdate(
{ slug: slug },
{ $inc: { availableQty: -ordered_products[slug].qty } }
);
}
res.redirect('/order/' + orderToAdd.orderId, 200)
} else {
// Handle any other HTTP method
res.status(400).json({ success: false });
}
};
export default connectDB(handler);
MyOrder.js
import React from "react";
import mongoose from "mongoose";
import Order from "../models/Order";
//TODO: To change the orderdetail fecthing resource from cart,subtotal to orders DB (user specific orders)
const MyOrder = ({ order }) => {
console.log("order = ",order)
const products = order.products;
console.log(order,products);
return (
<div>
<section className="text-gray-600 body-font overflow-hidden">
<div className="container px-5 py-24 mx-auto">
<div className="lg:w-4/5 mx-auto flex flex-wrap">
<div className="lg:w-1/2 w-full lg:pr-10 lg:py-6 mb-6 lg:mb-0">
<h2 className="text-sm title-font text-gray-500 tracking-widest">
CHESSWEAR.COM
</h2>
<h1 className="text-gray-900 text-3xl title-font font-medium mb-4">
Order Id: 2242434535
</h1>
<p className="leading-relaxed mb-4 text-green-700 rounded-3xl bg-green-100 hover:bg-green-100/70 p-3 border-[1px] border-green-700 inline-flex items-center justify-center ">
Your Order has been successfully placed !
</p>
<div className="flex mb-4 justify-evenly">
<a className="flex-grow w-12 py-2 text-lg px-1">Description</a>
<a className="flex-grow py-2 text-lg px-1">Quantity</a>
<a className="flex-grow py-2 text-lg px-1">Price</a>
</div>
{Object.keys(cart).map((key) => {
return (
<div key={key} className="flex border-t border-gray-200 py-2">
<span className="text-gray-500 w-28 ">
{cart[key].name} ({cart[key].size} - {cart[key].variant})
</span>
<span className="m-auto text-gray-900">
{cart[key].qty}
</span>
<span className="mr-auto mt-auto mb-auto text-gray-900">
₹ {cart[key].price}
</span>
</div>
);
})}
<div className="flex py-2 md:py-4">
<span className="title-font font-medium text-2xl text-gray-900">
Subtotal : <span className="ml-4 text-red-900 font-bold text-3xl leading-tight">₹ {subtotal} /-</span>
</span>
<button className="flex ml-auto text-white bg-blue-500 border-0 py-2 px-6 focus:outline-none hover:bg-blue-600 rounded">
Track Order
</button>
</div>
</div>
<img
alt="ecommerce"
className="lg:w-1/2 w-full lg:h-auto h-64 object-cover object-center rounded"
src="https://dummyimage.com/400x400"
/>
</div>
</div>
</section>
</div>
);
};
export async function getServerSideProps(context) {
if (!mongoose.connections[0].readyState) {
await mongoose.connect(process.env.MONGO_URI);
}
let order = await Order.findById({orderId:context.query.orderId})
console.log("got = ", order);
return {
props: { order: JSON.parse(JSON.stringify(order)) }, // will be passed to the page component as props
};
}
export default MyOrder;
File Structure
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|

