
Next Js Tutorial #6 - Ecommerce App - Admin Create Product Page & Api Route
We'll create functionality for create product and make a admin only protection creating an admin layout page.

You can also watch the YouTube video:
Next JS Tutorial #6 | Ecommerce App - Admin Create Product Page & API Route
We want to make every page admin only in the app/auth/admin
folder so we'll move our is admin check from auth/admin/page.js
to auth/admin/layout.js
Instead of checking the user is admin or not in every page we'll make every page admin protected this way.
Edit page.js
in app/auth/admin
folder:
"use client";
import AreaChartComponent from "@/components/Admin/AreaChartComponent";
import BarChartComponent from "@/components/Admin/BarChartComponent";
import PieChartComponent from "@/components/Admin/PieChartComponent";
const AdminPage = () => {
return (
<div className="container mx-auto py-8 px-4 lg:py-16">
<h1 className="mb-4 text-3xl font-bold text-gray-900 dark:text-white">
Dashboard
</h1>
<div className="grid grid-cols-3 gap-4">
<AreaChartComponent />
<BarChartComponent />
<PieChartComponent />
</div>
</div>
);
};
export default AdminPage;
Create layout.js
in app/auth/admin
folder:
"use client";
import { useCurrentUser } from "@/contexts/CurrentUserContext";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
export default function AdminLayout({ children }) {
const { currentUser } = useCurrentUser();
const router = useRouter();
useEffect(() => {
if (!currentUser || currentUser.role !== "ADMIN") {
router.push("/");
}
}, [currentUser]);
return children;
}
Create route.js
in app/api/products
folder:
import { NextResponse } from "next/server";
import { PrismaClient } from "@prisma/client";
import { cookies } from "next/headers";
import jwt from "jsonwebtoken";
const prisma = new PrismaClient();
export async function POST(request) {
const body = await request.json();
const { title, description, price, image } = body;
if (!title || !description || !price || !image) {
return NextResponse.json(
{ error: "You must fill all the required fields!" },
{ status: 200 }
);
}
try {
const tokenCookie = await cookies();
const getToken = tokenCookie.get("token");
if (getToken) {
const token = jwt.verify(getToken.value, "appSecret");
const userId = token.id;
if (!userId) {
return NextResponse.json(
{ error: "Unauthorized request!" },
{ status: 200 }
);
}
const user = await prisma.user.findUnique({ where: { id: userId } });
if (!user) {
return NextResponse.json(
{ error: "Unauthorized request!" },
{ status: 200 }
);
}
if (user.role !== "ADMIN") {
return NextResponse.json(
{ error: "Unauthorized request!" },
{ status: 200 }
);
}
const product = await prisma.product.create({
data: {
title,
description,
image,
price: parseFloat(price),
},
});
return NextResponse.json(product, { status: 201 });
}
return NextResponse.json(
{ error: "Unauthorized request!" },
{ status: 200 }
);
} catch (error) {
console.log(error.message);
return NextResponse.json(
{ error: "Failed to create post" },
{ status: 500 }
);
} finally {
await prisma.$disconnect();
}
}
Create page.js
in app/auth/admin/create-product
folder:
import CreateProduct from "@/components/Admin/CreateProduct";
export default function Home() {
return <CreateProduct />;
}
Create CreateProduct.jsx
in components/Admin
folder:
"use client";
import { useState } from "react";
import { Button } from "../ui/button";
import { Input } from "../ui/input";
import { Label } from "../ui/label";
const CreateProduct = () => {
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [image, setImage] = useState("");
const [price, setPrice] = useState("");
const [errorMsg, setErrorMsg] = useState("");
const handleSubmit = async () => {
try {
const response = await fetch("/api/products", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
title,
description,
price,
image,
}),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.error) {
setErrorMsg(data.error);
setTimeout(() => {
setErrorMsg("");
}, 4000);
} else {
window.location.reload();
}
return data;
} catch (error) {
console.error("There was a problem with the fetch operation:", error);
}
};
return (
<section>
<div className="py-8 px-4 mx-auto max-w-2xl lg:py-16">
<h1 className="mb-4 text-2xl font-bold text-gray-900 dark:text-white">
Create Product
</h1>
{errorMsg ? (
<div
className="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50"
role="alert"
>
<span className="font-medium">Error:</span>
{errorMsg}
</div>
) : undefined}
<div>
<div className="grid gap-4 sm:grid-cols-2 sm:gap-6">
<div className="sm:col-span-2">
<Label
htmlFor="title"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Title
</Label>
<Input
type="text"
name="title"
id="title"
value={title}
onChange={(event) => setTitle(event.target.value)}
className="input"
placeholder="Title"
required
/>
</div>
<div className="sm:col-span-2">
<Label
htmlFor="description"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Description
</Label>
<Input
type="text"
name="description"
id="description"
value={description}
onChange={(event) => setDescription(event.target.value)}
className="input"
placeholder="Description"
required
/>
</div>
<div className="sm:col-span-2">
<Label
htmlFor="price"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Price
</Label>
<Input
type="number"
name="price"
id="price"
value={price}
onChange={(event) => setPrice(event.target.value)}
className="input"
placeholder="Price"
required
/>
</div>
<div className="sm:col-span-2">
<Label
htmlFor="image"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Image
</Label>
<Input
type="text"
name="image"
id="image"
value={image}
onChange={(event) => setImage(event.target.value)}
className="input"
placeholder="Image"
required
/>
</div>
</div>
<Button onClick={handleSubmit} className="btn mt-6">
Create
</Button>
</div>
</div>
</section>
);
};
export default CreateProduct;
That's it for this tutorial, we created functionality for create product and made a admin only protection creating a admin layout page.
Next tutorial we'll listing products in our home page and make api route for it.