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

2 1 1 1 1

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!


Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more