112 lines
3.6 KiB
TypeScript
112 lines
3.6 KiB
TypeScript
import type { Metadata } from "next";
|
|
import Link from "next/link";
|
|
import { notFound } from "next/navigation";
|
|
import { PageHero } from "@/components/PageHero";
|
|
import { Pagination } from "@/components/Pagination";
|
|
import { ProductGrid } from "@/components/ProductGrid";
|
|
import { ProductTabs } from "@/components/ProductTabs";
|
|
import { ProductView } from "@/components/ProductView";
|
|
import { getCategories, getCategoryBySlug, getComments, getProduct, getStoreItemByProduct } from "@/lib/api";
|
|
import { listMappedProductsForCategory } from "@/lib/mappers";
|
|
import { SITE } from "@/lib/site";
|
|
|
|
type Props = {
|
|
params: Promise<{ slug: string }>;
|
|
searchParams: Promise<{ page?: string }>;
|
|
};
|
|
|
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
const { slug } = await params;
|
|
try {
|
|
const product = await getProduct(slug);
|
|
if (product) {
|
|
return {
|
|
title: `${product.nameFa || product.title} | ${SITE.nameFa}`,
|
|
description: product.summary || SITE.tagline,
|
|
};
|
|
}
|
|
|
|
const category = await getCategoryBySlug(slug);
|
|
if (category) {
|
|
return {
|
|
title: `${category.nameFa || category.name} | ${SITE.nameFa}`,
|
|
description: SITE.tagline,
|
|
};
|
|
}
|
|
} catch {
|
|
// fall through
|
|
}
|
|
|
|
return { title: SITE.nameFa };
|
|
}
|
|
|
|
export default async function ProductOrCategoryPage({ params, searchParams }: Props) {
|
|
const { slug } = await params;
|
|
const product = await getProduct(slug);
|
|
|
|
if (product) {
|
|
const [storeItem, comments] = await Promise.all([
|
|
getStoreItemByProduct(product.id),
|
|
getComments("product", product.id),
|
|
]);
|
|
return (
|
|
<>
|
|
<PageHero
|
|
title={product.nameFa || product.title}
|
|
english={product.title}
|
|
crumbs={[{ name: "محصولات", href: "/products" }, { name: product.nameFa || product.title }]}
|
|
/>
|
|
<section className="container-site py-10 md:py-14">
|
|
<ProductView product={product} variants={storeItem?.variants ?? []} />
|
|
<ProductTabs productId={product.id} descriptionHtml={product.descriptionHtml} comments={comments} />
|
|
</section>
|
|
</>
|
|
);
|
|
}
|
|
|
|
const [category, categories] = await Promise.all([getCategoryBySlug(slug), getCategories()]);
|
|
if (!category) notFound();
|
|
|
|
const { page: pageParam } = await searchParams;
|
|
const page = Math.max(1, Number(pageParam) || 1);
|
|
const children = categories.filter((item) => item.parentId === category.id);
|
|
const data = await listMappedProductsForCategory(
|
|
category.id,
|
|
children.map((item) => item.id),
|
|
page,
|
|
16,
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<PageHero
|
|
title={category.nameFa || category.name}
|
|
english={category.name}
|
|
crumbs={[{ name: "محصولات", href: "/products" }, { name: category.nameFa || category.name }]}
|
|
/>
|
|
<section className="container-site py-10 md:py-14">
|
|
{children.length > 0 && (
|
|
<div className="mb-8 flex flex-wrap gap-2">
|
|
{children.map((item) => (
|
|
<Link
|
|
key={item.id}
|
|
href={`/products/${item.slug}`}
|
|
className="rounded-full border border-black/10 px-4 py-2 text-sm hover:border-brand hover:text-brand"
|
|
>
|
|
{item.nameFa || item.name}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
)}
|
|
<ProductGrid products={data.items} />
|
|
<Pagination
|
|
page={data.page}
|
|
pageSize={data.pageSize}
|
|
total={data.total}
|
|
makeHref={(nextPage) => (nextPage > 1 ? `/products/${slug}?page=${nextPage}` : `/products/${slug}`)}
|
|
/>
|
|
</section>
|
|
</>
|
|
);
|
|
}
|