Product Details Page
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
The Product Details Page is a server-rendered component responsible for displaying comprehensive information about a single product. It utilizes a dynamic route based on the product's slug to fetch and present data. The page is designed to be robust, using React Suspense for loading states and a dedicated data-fetching hook that leverages @tanstack/react-query for efficient caching and server state management.
The primary goal of this page is to provide the end-user with all necessary details about a product, such as its name, price, images, and attributes, facilitating an informed purchasing decision. The architecture separates the page's entry point from its content and data logic, promoting modularity and maintainability.
Architecture and Data Flow
The system follows a clear, component-based data flow, starting from the user's navigation and ending with the rendered product details.
Component Rendering Flow
The diagram below illustrates the rendering flow initiated by a user request.
Data Fetching Sequence
Data fetching is managed by @tanstack/react-query through a custom hook. This sequence diagram shows the interactions between the UI, the hook, and the API service layer.
Routing
The page uses Next.js App Router's dynamic segments to capture the product slug from the URL.
- File:
app/(shop)/products/[slug]/page.tsx - Route:
/products/[slug] - Logic: The
ProductDetailPagecomponent receives theslugfrom theparamsobject and passes it down to theProductDetailContentcomponent, which is responsible for fetching and rendering the data.
// app/(shop)/products/[slug]/page.tsx
import { ProductDetailContent } from "@/features/products/components/product-detail-content";
import type { JSX } from "react";
import { Suspense } from "react";
interface ProductDetailPageProps {
readonly params: Promise<{ slug: string }>;
}
export default async function ProductDetailPage({ params }: ProductDetailPageProps): Promise<JSX.Element> {
const { slug } = await params;
return (
<Suspense fallback={<div>Đang tải...</div>}>
<ProductDetailContent productSlug={slug} />
</Suspense>
);
}
Sources: app/(shop)/products/[slug]/page.tsx:1-13
Data Fetching
Data fetching for the product details is encapsulated within the useProductBySlug hook.
Sources: features/products/hooks/use-products-query.ts:40-47
useProductBySlug Hook
This hook, found in features/products/hooks/use-products-query.ts, uses @tanstack/react-query's useQuery to fetch a single product by its slug.
| Property | Description |
|---|---|
queryKey | queryKeys.products.bySlug(slug) (e.g., ['products', 'bySlug', 'my-product-slug']) for caching. |
queryFn | A function that calls productsApi.getBySlug(slug) to fetch the data. |
enabled | !!slug - The query will only run if a slug is provided. |
staleTime | 5 * 60 * 1000 (5 minutes) - The data is considered fresh for 5 minutes before a refetch is attempted. |
Sources: features/products/hooks/use-products-query.ts:41-46
Data Models
The structure of the product data is strictly defined using Zod schemas and TypeScript interfaces, ensuring type safety throughout the application.
Sources: types/product.types.ts
Product and Category Relationship
A product can optionally belong to a single category.
Product Interface
This table describes the main fields of the Product object.
| Field | Type | Description |
|---|---|---|
id | string | Unique CUID identifier for the product. |
sku | string | Stock Keeping Unit. |
name | string | The product's name. |
slug | string | URL-friendly identifier for the product. |
priceInt | number | Price in the smallest currency unit (e.g., VND). |
stock | number | Available quantity in stock. |
description | string | null | A detailed description of the product. |
imageUrls | string[] | An array of URLs for product images. |
categoryId | string | null | The CUID of the associated category. |
attributes | ProductAttributes | null | An object containing detailed product attributes. |
model3dUrl | string | null | A URL to a 3D model of the product (e.g., for AR). |
createdAt | string | ISO date string of when the product was created. |
updatedAt | string | ISO date string of the last update. |
category | Category | null | undefined | The optional, populated category object. |
Sources: types/product.types.ts:90-113
ProductAttributes Interface
This interface defines a flexible structure for various product characteristics.
| Field | Type | Description |
|---|---|---|
brand | string | undefined | The brand of the product. |
frameShape | string | undefined | The shape of the glasses frame. |
frameMaterial | string | undefined | The material of the frame. |
color | string | undefined | The primary color of the product. |
gender | "Nam" | "Nữ" | "Unisex" | undefined | Target gender for the product. |
tryOnImageUrl | string | undefined | URL for the virtual try-on feature image. |
... | ... | Other optional boolean and string attributes. |
Sources: types/product.types.ts:13-43
Summary
The Product Details Page is a critical feature for the e-commerce shop, implemented using modern frontend practices. It leverages Next.js dynamic server components for initial rendering, React Suspense for a smooth loading experience, and @tanstack/react-query for intelligent client-side data management. The feature is built upon a strongly-typed data model, ensuring data integrity from the API to the UI. This modular and efficient design makes the page both performant for the user and easy to maintain for developers.