Open In App

Build an Inventory Management System Using NextJS

Last Updated : 21 Aug, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

We will build an Inventory Management System. We will walk through the step-by-step process of creating an inventory management system. This application contains a dashboard that shows a brief report of our inventory. Product sections show all the products listed with a search filter and allow users to add, update, and delete the product.

Output Preview

inventory-management-dashboard
Inventory Management System Using NextJS
inventory-management-products

Prerequisites

Installation & Setup

Step 1: Create a Next.js application using the following command.

npx create-next-app@latest inventory-management

Step 2: It will ask you some questions, so choose as the following.

√  Would you like to use TypeScript? ... No
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... Yes
√ Would you like to use `src/` directory? ... Yes
√ Would you like to use App Router? (recommended) ... Yes
√ Would you like to customize the default import alias (@/*)? ... Yes

Step 3: After creating your project folder i.e. inventory-management, move to it using the following command.

cd  inventory-management

Step 4: Install the required packages by using following command.

npm i chart.js react-chartjs-2 uuid

The updated pakage.json dependencies will look like this:

  "dependencies": {
"chart.js": "^4.4.3",
"next": "14.2.5",
"react": "^18",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18",
"uuid": "^10.0.0"
}

Step 5: Create a Sample Data File inside public/data folder

[
{
"name": "Smartphone",
"category": "Electronics",
"quantity": "25",
"price": "25000",
"maxStock": "50",
"minStock": "10",
"id": "e5f6a7b8-c901-23d4-f567-56789012f3d4"
},
{
"name": "Bookshelf",
"category": "Furniture",
"quantity": "12",
"price": "8000",
"maxStock": "20",
"minStock": "5",
"id": "f6a7b8c9-0123-45e6-g789-67890123g456"
},
{
"name": "Jeans",
"category": "Clothing",
"quantity": "10",
"price": "1200",
"maxStock": "40",
"minStock": "25",
"id": "b8c90123-4567-89f0-i012-89012345i678"
},
{
"name": "Tablet",
"category": "Electronics",
"quantity": "40",
"price": "18000",
"maxStock": "30",
"minStock": "15",
"id": "c9012345-6789-01f2-j345-90123456j789"
},
{
"name": "Laptop",
"category": "Electronics",
"quantity": "21",
"price": "23555",
"maxStock": "10",
"minStock": "5",
"id": "c7989c06-d7ef-4690-b69e-2dd122a3d2df"
},
{
"name": "Book",
"category": "Stationery",
"quantity": "13",
"price": "355",
"maxStock": "20",
"minStock": "15",
"id": "50658c12-b63b-472a-b778-c87c8943991e"
}
]

Project Structure:

inventory-management-structure

Example: This example shows the creation of the inventory management system.

CSS
/* File path: src/app/global.css */

@tailwind base;
@tailwind components;
@tailwind utilities;
JavaScript
//File path: src/app/page.js

"use client";
import React, { useEffect, useState } from 'react';
import { Bar, Pie } from 'react-chartjs-2';
import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  BarElement,
  Title,
  Tooltip,
  Legend,
  ArcElement,
} from 'chart.js';

ChartJS.register(
  CategoryScale,
  LinearScale,
  BarElement,
  Title,
  Tooltip,
  Legend,
  ArcElement
);

export default function Dashboard() {

  const [products, setProducts] = useState([])

  useEffect(() => {
    fetchProducts(); 
  }, []);

  const fetchProducts = async (searchValue = '') => {

    let data = await fetch(`/api/products?search=${searchValue}`, {
      method: "GET"
    });

    data = await data.json();
    setProducts(data.data);
  };


  const stockData = {
    labels: products.map(product => product.name),
    datasets: [
      {
        label: 'Quantity',
        data: products.map(product => Number(product.quantity)),
        backgroundColor: 'rgba(54, 162, 235, 0.5)',
      },
      {
        label: 'Max Stock',
        data: products.map(product => Number(product.maxStock)),
        backgroundColor: 'rgba(255, 99, 132, 0.5)',
      },
    ],
  };

  const categories = [...new Set(products.map(product => product.category))];
  const categoryCounts = categories.map(category => products.filter(product => product.category === category).length);

  const categoryData = {
    labels: categories,
    datasets: [
      {
        label: 'Category Breakdown',
        data: categoryCounts,
        backgroundColor: [
          'rgba(75, 192, 192, 0.5)',
          'rgba(153, 102, 255, 0.5)',
          'rgba(255, 159, 64, 0.5)',
          'rgba(255, 205, 86, 0.5)',
        ],
      },
    ],
  };

  return (
    <div className="p-6">
      <h1 className="text-3xl font-bold mb-4">Inventory Management System</h1>

      <div className='grid grid-cols-2 gap-1'>

        <div class="max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700">
          <h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Total Products</h5>
          <h2 class="mb-2 text-6xl font-bold tracking-tight text-gray-900 dark:text-white">{products.length}</h2>
        </div>

        <div class="max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700">
          <h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Total Category</h5>

          <h2 class="mb-2 text-6xl font-bold tracking-tight text-gray-900 dark:text-white">{categories.length}</h2>
        </div>

        <div className="max-w-sm w-full p-6 bg-white border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700">
          <h5 className="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Stock Level vs. Max Stock for Each Product</h5>
          <div className="h-64">
            <Bar data={stockData} options={{ maintainAspectRatio: false }} />
          </div>
        </div>

        <div className="max-w-sm w-full p-6 bg-white border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700">
          <h5 className="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Product Categories Breakdown</h5>
          <div className="h-64">
            <Pie data={categoryData} options={{ maintainAspectRatio: false }} />
          </div>
        </div>
      </div>
    </div>
  );
}
JavaScript
//File path: src/app/layout.js

import { Inter } from "next/font/google";
import "./globals.css";
import Link from "next/link";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Inventory Management App",
  description: "Inventory Management",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <button data-drawer-target="default-sidebar" data-drawer-toggle="default-sidebar" aria-controls="default-sidebar" type="button" className="inline-flex items-center p-2 mt-2 ms-3 text-sm text-gray-500 rounded-lg sm:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600">
          <span className="sr-only">Open sidebar</span>
          <svg className="w-6 h-6" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
            <path clipRule="evenodd" fillRule="evenodd" d="M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"></path>
          </svg>
        </button>

        <aside id="default-sidebar" className="fixed top-0 left-0 z-40 w-64 h-screen transition-transform -translate-x-full sm:translate-x-0" aria-label="Sidebar">
          <div className="h-full px-3 py-4 overflow-y-auto bg-gray-50 dark:bg-gray-800">
            <span className="flex items-center ps-2.5 mb-5">
              <span className="self-center text-xl font-semibold whitespace-nowrap dark:text-white">Inventory</span>
            </span>
            <ul className="space-y-2 font-medium">
              <li>
                <Link href="/" className="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
                  <span className="ms-3">
                    Dashboard
                  </span>
                </Link>
              </li>
              <li>
                <Link href="/products" className="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
                  <span className="ms-3">Products</span>
                </Link>
              </li>
              <li>
                <Link href="/products/add" className="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
                  <span className="ms-3">Add Product</span>
                </Link>
              </li>
            </ul>
          </div>
        </aside>

        <div className="p-4 sm:ml-64">
          {children}
        </div>
      </body>
    </html>
  );
}
JavaScript
// File path: src/app/products/page.js 

"use client";

import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';

export default function Products() {
    const [product, setProduct] = useState([]);
    const [search, setSearch] = useState('');

    const router = useRouter();

    useEffect(() => {
        fetchProducts(); 
    }, []);

    const fetchProducts = async (searchValue = '') => {

        let data = await fetch(`/api/products?search=${searchValue}`, {
            method: "GET"
        });

        data = await data.json();
        setProduct(data.data);
    };

    const deleteProduct = async (id) => {

        let isConfirm = confirm("Are you sure you want to delete this product?")
        if(!isConfirm) return

        let response = await fetch(`/api/products`,{
            method: "DELETE",
            body: JSON.stringify(id),
            headers:{
                "content-type":"application/json"
            }
        })

        response = await response.json()

        if(response.success) {
            alert(response.message)
            return fetchProducts()
        }

        return alert(response.message)
    }
    return (
        <div className="p-6">
            <h1 className="text-3xl font-bold mb-4">Products</h1>

            <div className="relative shadow-md sm:rounded-lg">
                <div className="flex items-center justify-end flex-column flex-wrap md:flex-row space-y-4 md:space-y-0 pb-4 bg-white">
                    <label htmlFor="table-search" className="sr-only">Search</label>
                    <div className="relative">
                        <div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
                            <svg className="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
                                <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
                            </svg>
                        </div>
                        <input
                            type="text"
                            value={search}
                            onChange={(e) => {
                                const newSearchValue = e.target.value; 
                                setSearch(newSearchValue);
                                fetchProducts(newSearchValue);
                            }}
                            className="block p-2 pl-10 text-sm text-gray-900 border border-gray-300 rounded-lg w-80 bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
                            placeholder="Search for Products"
                        />
                    </div>
                </div>
                <table className="w-full text-sm text-left text-gray-500">
                    <thead className="text-xs text-gray-700 uppercase bg-gray-50">
                        <tr>
                            <th scope="col" className="px-6 py-3">Name</th>
                            <th scope="col" className="px-6 py-3">Category</th>
                            <th scope="col" className="px-6 py-3">Price</th>
                            <th scope="col" className="px-6 py-3">Available Quantity</th>
                            <th scope="col" className="px-6 py-3">Max Stock Quantity</th>
                            <th scope="col" className="px-6 py-3">Min Stock Quantity</th>
                            <th scope="col" className="px-6 py-3">Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        {product.map((item) => (
                            <tr key={item.id} className="bg-white border-b hover:bg-gray-50">
                                <th scope="row" className="flex items-center px-6 py-4 text-gray-900 whitespace-nowrap">
                                    {item.name}
                                </th>
                                <td className="px-6 py-4">{item.category}</td>
                                <td className="px-6 py-4">{item.price}</td>
                                <td className="px-6 py-4">
                                    <div className="flex items-center">
                                        {item.quantity}
                                        <div style={{background:`${(Number(item.quantity) < Number(item.minStock)) ? "red":"green" }`}} className={`h-2.5 w-2.5 rounded-full bg-${(Number(item.quantity) < Number(item.minStock)) ? "red":"green" }-500 ml-2`}></div>
                                    </div>
                                </td>
                                <td className="px-6 py-4">{item.maxStock}</td>
                                <td className="px-6 py-4">{item.minStock}</td>
                                <td className="px-6 py-4 flex">
                                    <button onClick={()=> router.push(`/products/${item.id}`)} className="font-medium text-blue-600 hover:underline">Edit</button>
                                    <button onClick={() => {
                                        deleteProduct(item.id)}} className="font-medium text-red-600 ml-2 hover:underline">Delete</button>
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        </div>
    );
}
JavaScript
// File path: src/app/products/add/page.js 

"use client";

import { useState } from 'react';

export default function Add() {
    const [productName, setProductName] = useState('');
    const [category, setCategory] = useState('');
    const [quantity, setQuantity] = useState('');
    const [price, setPrice] = useState('');
    const [maxStock, setMaxStock] = useState('');
    const [minStock, setMinStock] = useState('');

    const handleSubmit = async (e) => {
        e.preventDefault();
        
        if(!Number(quantity)) return alert("Please Enter Valid Quantity")
       
        if(!Number(price)) return alert("Please Enter Valid Price")

        if(Number(maxStock) < Number(minStock)) return alert("Please select Valid Min & Max Stock Quantity")

        
        const newProduct = {
            name: productName,
            category: category,
            quantity: quantity,
            price: price,
            maxStock: maxStock,
            minStock: minStock,
        };
        
        let response = await fetch('/api/products/add', {
            method:"POST",
            body: JSON.stringify(newProduct),
            headers:{
                "content-type":"application/json"
            }
        })

        response = await response.json()
        
        if(response.success){
            setProductName('');
            setCategory('');
            setQuantity('');
            setPrice('');
            setMaxStock('');
            setMinStock('');
            return alert(response.message)
        };

        return alert(response.message)
    }

    return (
        <div className="p-6">
            <h1 className="text-3xl font-bold mb-4">Add Product</h1>
            <form onSubmit={handleSubmit} className="max-w-md mx-auto">
                <div className="relative z-0 w-full mb-5 group">
                    <input 
                        type="text" 
                        value={productName} 
                        onChange={(e) => setProductName(e.target.value)} 
                        className="block py-2.5 px-0 w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 border-gray-300 appearance-none focus:outline-none focus:ring-0 focus:border-blue-600 peer" 
                        placeholder=" " 
                        required 
                    />
                    <label className="peer-focus:font-medium absolute text-sm text-gray-500 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 peer-focus:text-blue-600 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">
                        Name
                    </label>
                </div>

                <div className="relative z-0 w-full mb-5 group">
                    <select 
                        value={category} 
                        onChange={(e) => setCategory(e.target.value)} 
                        className="block py-2.5 px-0 w-full text-sm text-gray-500 bg-transparent border-0 border-b-2 border-gray-200 appearance-none focus:outline-none focus:ring-0 focus:border-gray-200 peer"
                    >
                        <option value="" disabled>Choose Product Category</option>
                        <option value="Electronics">Electronics</option>
                        <option value="Clothing">Clothing</option>
                        <option value="Furniture">Furniture</option>
                        <option value="Stationery">Stationery</option>
                    </select>
                </div>

                <div className="relative z-0 w-full mb-5 group">
                    <input 
                        type="text" 
                        value={quantity} 
                        onChange={(e) => setQuantity(e.target.value)} 
                        className="block py-2.5 px-0 w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 border-gray-300 appearance-none focus:outline-none focus:ring-0 focus:border-blue-600 peer" 
                        placeholder=" " 
                        required 
                    />
                    <label className="peer-focus:font-medium absolute text-sm text-gray-500 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 peer-focus:text-blue-600 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">
                        Quantity
                    </label>
                </div>

                <div className="relative z-0 w-full mb-5 group">
                    <input 
                        type="text" 
                        value={price} 
                        onChange={(e) => setPrice(e.target.value)} 
                        className="block py-2.5 px-0 w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 border-gray-300 appearance-none focus:outline-none focus:ring-0 focus:border-blue-600 peer" 
                        placeholder=" " 
                        required 
                    />
                    <label className="peer-focus:font-medium absolute text-sm text-gray-500 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 peer-focus:text-blue-600 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">
                        Price
                    </label>
                </div>

                <div className="grid md:grid-cols-2 md:gap-6">
                    <div className="relative z-0 w-full mb-5 group">
                        <select 
                            value={maxStock} 
                            onChange={(e) => setMaxStock(e.target.value)} 
                            className="block py-2.5 px-0 w-full text-sm text-gray-500 bg-transparent border-0 border-b-2 border-gray-200 appearance-none focus:outline-none focus:ring-0 focus:border-gray-200 peer"
                        >
                            <option value="" disabled>Choose Max Stock Quantity</option>
                            <option value="10">10</option>
                            <option value="20">20</option>
                            <option value="30">30</option>
                            <option value="40">40</option>
                            <option value="50">50</option>
                        </select>
                    </div>
                    <div className="relative z-0 w-full mb-5 group">
                        <select 
                            value={minStock} 
                            onChange={(e) => setMinStock(e.target.value)} 
                            className="block py-2.5 px-0 w-full text-sm text-gray-500 bg-transparent border-0 border-b-2 border-gray-200 appearance-none focus:outline-none focus:ring-0 focus:border-gray-200 peer"
                        >
                            <option value="" disabled>Choose Min Stock Quantity</option>
                            <option value="5">5</option>
                            <option value="15">15</option>
                            <option value="25">25</option>
                            <option value="35">35</option>
                            <option value="45">45</option>
                        </select>
                    </div>
                </div>

                <button type="submit" className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center">
                    Add Product
                </button>
            </form>
        </div>
    );
}
JavaScript
// File path: src/app/products/[update]/page.js 

"use client";

import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';

export default function Update({ params }) {
    const [productName, setProductName] = useState('');
    const [category, setCategory] = useState('');
    const [quantity, setQuantity] = useState('');
    const [price, setPrice] = useState('');
    const [maxStock, setMaxStock] = useState('');
    const [minStock, setMinStock] = useState('');

    const router = useRouter()

    useEffect(() => {
        fetchSingleProduct();
    }, []);

    const fetchSingleProduct = async () => {

        let data = await fetch(`/api/products/${params.update}`, {
            method: "GET"
        });

        data = await data.json();

        setProductName(data.data.name);
        setCategory(data.data.category);
        setQuantity(data.data.quantity);
        setPrice(data.data.price);
        setMaxStock(data.data.maxStock);
        setMinStock(data.data.minStock);

    };

    const updateForm = async (e) => {
        e.preventDefault();

        if (!Number(quantity)) return alert("Please Enter Valid Quantity")

        if (!Number(price)) return alert("Please Enter Valid Price")

        if (Number(maxStock) < Number(minStock)) return alert("Please select Valid Min & Max Stock Quantity")


        const newProduct = {
            name: productName,
            category: category,
            quantity: quantity,
            price: price,
            maxStock: maxStock,
            minStock: minStock,
        };

        let response = await fetch(`/api/products/${params.update}`, {
            method: "PUT",
            body: JSON.stringify(newProduct),
            headers: {
                "content-type": "application/json"
            }
        })

        response = await response.json()

        if (response.success) {
            alert(response.message)
            return router.push('/products')
        };
    }

    return (
        <div className="p-6">
            <h1 className="text-3xl font-bold mb-4">Update Product</h1>
            <form onSubmit={updateForm} className="max-w-md mx-auto">
                <div className="relative z-0 w-full mb-5 group">
                    <input
                        type="text"
                        value={productName}
                        onChange={(e) => setProductName(e.target.value)}
                        className="block py-2.5 px-0 w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 border-gray-300 appearance-none focus:outline-none focus:ring-0 focus:border-blue-600 peer"
                        placeholder=" "
                        required
                    />
                    <label className="peer-focus:font-medium absolute text-sm text-gray-500 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 peer-focus:text-blue-600 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">
                        Name
                    </label>
                </div>

                <div className="relative z-0 w-full mb-5 group">
                    <select
                        value={category}
                        onChange={(e) => setCategory(e.target.value)}
                        className="block py-2.5 px-0 w-full text-sm text-gray-500 bg-transparent border-0 border-b-2 border-gray-200 appearance-none focus:outline-none focus:ring-0 focus:border-gray-200 peer"
                    >
                        <option value="" disabled>Choose Product Category</option>
                        <option value="Electronics">Electronics</option>
                        <option value="Clothing">Clothing</option>
                        <option value="Furniture">Furniture</option>
                        <option value="Stationery">Stationery</option>
                    </select>
                </div>

                <div className="relative z-0 w-full mb-5 group">
                    <input
                        type="text"
                        value={quantity}
                        onChange={(e) => setQuantity(e.target.value)}
                        className="block py-2.5 px-0 w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 border-gray-300 appearance-none focus:outline-none focus:ring-0 focus:border-blue-600 peer"
                        placeholder=" "
                        required
                    />
                    <label className="peer-focus:font-medium absolute text-sm text-gray-500 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 peer-focus:text-blue-600 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">
                        Quantity
                    </label>
                </div>

                <div className="relative z-0 w-full mb-5 group">
                    <input
                        type="text"
                        value={price}
                        onChange={(e) => setPrice(e.target.value)}
                        className="block py-2.5 px-0 w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 border-gray-300 appearance-none focus:outline-none focus:ring-0 focus:border-blue-600 peer"
                        placeholder=" "
                        required
                    />
                    <label className="peer-focus:font-medium absolute text-sm text-gray-500 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 peer-focus:text-blue-600 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6">
                        Price
                    </label>
                </div>

                <div className="grid md:grid-cols-2 md:gap-6">
                    <div className="relative z-0 w-full mb-5 group">
                        <select
                            value={maxStock}
                            onChange={(e) => setMaxStock(e.target.value)}
                            className="block py-2.5 px-0 w-full text-sm text-gray-500 bg-transparent border-0 border-b-2 border-gray-200 appearance-none focus:outline-none focus:ring-0 focus:border-gray-200 peer"
                        >
                            <option value="" disabled>Choose Max Stock Quantity</option>
                            <option value="10">10</option>
                            <option value="20">20</option>
                            <option value="30">30</option>
                            <option value="40">40</option>
                            <option value="50">50</option>
                        </select>
                    </div>
                    <div className="relative z-0 w-full mb-5 group">
                        <select
                            value={minStock}
                            onChange={(e) => setMinStock(e.target.value)}
                            className="block py-2.5 px-0 w-full text-sm text-gray-500 bg-transparent border-0 border-b-2 border-gray-200 appearance-none focus:outline-none focus:ring-0 focus:border-gray-200 peer"
                        >
                            <option value="" disabled>Choose Min Stock Quantity</option>
                            <option value="5">5</option>
                            <option value="15">15</option>
                            <option value="25">25</option>
                            <option value="35">35</option>
                            <option value="45">45</option>
                        </select>
                    </div>
                </div>

                <button type="submit" className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center">
                    Update Product
                </button>
            </form>
        </div>
    );
}
JavaScript
// File path: src/app/api/products/route.js 

import { NextResponse } from "next/server";
import { promises as fs } from 'fs';

export async function GET(request) {
    const url = new URL(request.url);
    const searchValue = url.searchParams.get('search');

    // Read the products file and parse it
    let products = await fs.readFile(`${process.cwd()}/public/data/products.json`, 'utf8');
    products = JSON.parse(products); // Parse the JSON string into an array

    // If there is no search value, return all products
    if (!searchValue) {
        return NextResponse.json({
            success: true,
            message: "Products Fetched Successfully",
            data: products
        });
    }

    // Filter the products based on the search value
    let newdata = products.filter((product) => {
        return new RegExp(`^${searchValue}`, 'i').test(product.name); // 'i' for case-insensitive matching
    });

    // Return the filtered products
    return NextResponse.json({
        success: true,
        message: "Products Fetched Successfully",
        data: newdata
    });
}

export async function DELETE(request) {

    const id = await request.json()

    let products = await fs.readFile(`${process.cwd()}/public/data/products.json`, 'utf8')
    
    products = JSON.parse(products)

    let productIndex = products.findIndex(product => product.id == id)

    products.splice(productIndex, 1)

    await fs.writeFile(`${process.cwd()}/public/data/products.json`, JSON.stringify(products, null, 4))

    return NextResponse.json({
        success: true,
        message: "Products Deleted Successfully",
    });
}
JavaScript
// File path: src/app/api/products/add/route.js 

import { NextResponse } from "next/server";
import { promises as fs } from 'fs';
import { v4 } from "uuid";

export async function POST(request) {
    let payload = await request.json();    
    payload.id = v4();

    let products = await fs.readFile(`${process.cwd()}/public/data/products.json`, 'utf8')
    
    products = JSON.parse(products)

    products.push(payload)

    await fs.writeFile(`${process.cwd()}/public/data/products.json`, JSON.stringify(products, null, 4))
    
    return NextResponse.json({success:true, message: "New Product Added Successfully"})
}
JavaScript
// File path: src/app/api/products/[id]/route.js 

import { NextResponse } from "next/server";
import { promises as fs } from 'fs';

export async function GET(request, { params }) {

    // Read the products file and parse it
    let products = await fs.readFile(`${process.cwd()}/public/data/products.json`, 'utf8');
    products = JSON.parse(products); // Parse the JSON string into an array

    products = products.find(product => product.id == params.id)

    return NextResponse.json({
        success: true,
        message: "Products Fetched Successfully",
        data: products
    });
}


export async function PUT(request, { params }) {
    let payload = await request.json();    

    // Read the products file and parse it
    let products = await fs.readFile(`${process.cwd()}/public/data/products.json`, 'utf8');
    products = JSON.parse(products); // Parse the JSON string into an array

    let productIndex = products.findIndex(product => product.id == params.id)

    products[productIndex] = {...payload, id: params.id}

    await fs.writeFile(`${process.cwd()}/public/data/products.json`, JSON.stringify(products, null, 4))
    
    return NextResponse.json({
        success: true,
        message: "Product Updated Successfully",
    });
}

To run the Application open the terminal in the project folder and enter the following command:

npm run dev

Output:


Next Article

Similar Reads