DEV Community

Cover image for Fetching and Displaying Dynamic Product Data in Next.js with Prisma
Mohammad Ezzeddin Pratama
Mohammad Ezzeddin Pratama

Posted on • Edited on

Fetching and Displaying Dynamic Product Data in Next.js with Prisma


In this tutorial, ill build a dynamic product page using Next.js and Prisma.ill fetch data based on the selected category and display it using a visually appealing card layout.

1. Setting Up Dynamic Routes

Next.js allows us to create dynamic routes easily. We'll set up a dynamic route that will render products based on the selected category.

Creating the Dynamic Route

First, create a new file under the app/products/[category]/page.tsx directory. This file will handle rendering the products for the selected category.

app/products/[category]/page.tsx

import { notFound } from 'next/navigation';
import { type CategoryTypes } from '@prisma/client';
import React from 'react'
import prisma from '@/app/lib/db';
import ProductCard from '@/app/components/ProductCard';

async function getData(category: string) {
    let input;

    switch (category) {
        case "template":
            input = "template";
            break;
        case "uikit":
            input = "uikit";
            break;
        case "icon":
            input = "icon";
            break;
        case "all":
            input = undefined;
            break;
        default:
            return notFound();
    }

    const data = await prisma.product.findMany({
        where: {
            category: input as CategoryTypes,
        },
        select: {
            id: true,
            images: true,
            smallDescription: true,
            name: true,
            price: true,
        }
    });
    return data;
}

export default async function CategoryPage({ params }: { params: { category: string } }) {
    const data = await getData(params.category);

    return (
        <section className='max-w-7xl mx-auto px-4 md:px-8'>
            <div className="grid grid-cols-1 lg:grid-cols-3 sm:grid-cols-2 gap-10 mt-4">
                {data.map((product) => (
                    <ProductCard
                        key={product.id}
                        images={product.images}
                        name={product.name}
                        smallDescription={product.smallDescription}
                        price={product.price}
                        id={product.id}
                    />
                ))}
            </div>
        </section>
    )
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  • Dynamic Routing: The [category] in the file name tells Next.js to treat this segment as a variable. Based on this variable, we'll fetch and display products.
  • Fetching Data: The getData function retrieves products based on the category. It handles categories like "template", "uikit", "icon", and "all".
  • Rendering Cards: The ProductCard component is used to display each product in a grid layout.

2. Creating the Product Card Component

To present the products, we need a ProductCard component that displays product details in a card format.

app/components/ProductCard.tsx

import React from 'react'
import Image from 'next/image'
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel';
import Link from 'next/link';
import { Button } from '@/components/ui/button';

interface iAppProps {
    id: string;
    name: string;
    smallDescription: string;
    description?: string;
    price: number;
    images: string[];
}

export default function ProductCard({ id, name, smallDescription, price, images }: iAppProps) {
    return (
        <div className='rounded-lg p-2 w-full h-full flex flex-col justify-between items-center bg-white shadow-md'>
            <Carousel>
                <CarouselContent>
                    {images.map((item, index) => (
                        <CarouselItem key={index}>
                            <div className='relative h-[230px] w-full'>
                                <Image
                                    alt='Product image'
                                    src={item}
                                    width={230}
                                    height={230}
                                    quality={75}
                                    className='shadow-md object-cover w-full h-full rounded-lg' />
                            </div>
                        </CarouselItem>
                    ))}
                </CarouselContent>
                {images.length > 1 && (
                    <>
                        <CarouselPrevious className="ml-16" />
                        <CarouselNext className="mr-16" />
                    </>
                )}
            </Carousel>
            <div className='flex flex-col gap-y-2 p-2 items-end justify-start text-left h-full'>
                <div className='flex justify-between items-start mt-2 gap-x-3 w-full'>
                    <h1 className="text-md font-bold text-wrap">{name}</h1>
                    <h3 className="inline-flex items-center rounded-full bg-primary/10 px-2 py-1 text-sm font-medium text-primary ring-1 ring-inset ring-primary/10">$<span className="font-semibold">{price}</span></h3>
                </div>
                <p className='text-neutral-600 text-sm text-left line-clamp-2'>{smallDescription}</p>
                <div className='items-end justify-end pt-2'>
                    <Button className='rounded-lg hover:shadow-lg hover:scale-105 transition-all duration-300 '>
                        <Link href={`/product/${id}`}>View Details</Link>
                    </Button>
                </div>
            </div>
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  • Image Carousel: Displays multiple images for each product. Users can navigate through images using the carousel controls.
  • Product Details: Shows the product's name, price, and a brief description.
  • View Details Button: Links to a detailed product view page.

3. Adding Navigation Links

To enable navigation between different categories, create a NavbarLinks component.

app/components/NavbarLinks.tsx

"use client"
import { cn } from '@/lib/utils'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import React from 'react'

export const navdata = [
    {
        id: 0,
        name: "Home",
        href: "/",
    },
    {
        id: 1,
        name: "Templates", 
        href: "/products/template",
    },
    {
        id: 2,
        name: "UI Kits",
        href: "/products/uikit",
    },
    {
        id: 3,
        name: "Icons",
        href: "/products/icon",
    },
]

export default function NavbarLinks() {
    const location = usePathname();

    return (
        <div className='hidden md:flex justify-center items-center col-span-6 gap-x-9 text-md md:text-sm text-neutral-600'>
            {navdata.map((item) => {
                return (
                    <Link key={item.id} href={item.href} className={cn(
                        location === item.href ? "bg-orange-100/60 font-medium bg-opacity-100 py-1 px-2 transition-all duration-300 rounded-full text-orange-400" : "hover:text-orange-400 duration-300",
                    )}>
                        <h1>{item.name}</h1>
                    </Link>
                )
            })}
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  • Navigation Links: Provides links to different product categories. Highlights the currently active category based on the URL.

Conclusion

In this tutorial, we set up a dynamic route in Next.js to display products based on the selected category. We created a ProductCard component to present products and added a navigation bar to switch between categories.

Feel free to adapt these components and routing strategies to fit your specific project needs. Happy coding!


Top comments (0)