Files
saman-andish/app/products/[id]/[slug]/page.tsx
T

212 lines
6.7 KiB
TypeScript

import type { Metadata } from "next";
import { ArrowLeft, CheckCircle2, Phone } from "lucide-react";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { cache } from "react";
import ProductCard from "../../../components/ProductCard";
import {
InteriorFooter,
InteriorHeader,
} from "../../../components/InteriorShell";
import {
categoryPath,
fetchProductById,
productPath,
} from "../../../lib/meshkee";
import ProductGallery from "./ProductGallery";
export const dynamic = "force-dynamic";
type ProductPageProps = {
params: Promise<{ id: string; slug: string }>;
};
const getProduct = cache(async (id: string) => fetchProductById(id));
function plainText(value?: string | null) {
return (value || "")
.replace(/<[^>]*>/g, " ")
.replace(/&nbsp;/g, " ")
.replace(/\s+/g, " ")
.trim();
}
export async function generateMetadata({
params,
}: ProductPageProps): Promise<Metadata> {
const { id } = await params;
const data = await getProduct(id).catch(() => undefined);
if (!data?.product) {
return {
title: "محصول یافت نشد | سامان اندیش",
};
}
const product = data.product;
const title = product.nameFa || product.title;
const description =
product.summary ||
plainText(product.descriptionHtml) ||
`مشخصات و تصاویر ${title} را مشاهده کنید و برای دریافت اطلاعات فنی و استعلام قیمت با کارشناسان سامان اندیش تماس بگیرید.`;
const image = product.thumbnailUrl || product.image || product.thumbnail;
return {
title: `${title} | سامان اندیش`,
description: description.slice(0, 160),
alternates: {
canonical: productPath(product),
},
openGraph: {
title: `${title} | سامان اندیش`,
description: description.slice(0, 160),
url: productPath(product),
type: "website",
images: image ? [{ url: image, alt: title }] : undefined,
},
};
}
export default async function ProductDetailPage({
params,
}: ProductPageProps) {
const { id, slug } = await params;
const data = await getProduct(id).catch(() => undefined);
if (!data?.product) notFound();
const product = data.product;
const canonicalPath = productPath(product);
const requestedSlug = decodeURIComponent(slug);
if (!canonicalPath.endsWith(`/${requestedSlug}`)) {
redirect(encodeURI(canonicalPath));
}
const title = product.nameFa || product.title;
const categoryTitle =
product.categoryNameFa || product.categoryName || "ماشین‌آلات صنعتی";
const categoryHref =
product.categoryId && (product.categoryNameFa || product.categoryName)
? categoryPath({
id: product.categoryId,
nameFa: product.categoryNameFa,
name: product.categoryName || categoryTitle,
})
: "/products";
const images = Array.from(
new Set(
[
product.thumbnailUrl,
product.image,
product.thumbnail,
...(product.images || []).map((image) => image.url),
].filter((image): image is string => Boolean(image)),
),
);
if (!images.length) images.push("/assets/product-quadding.jpg");
const description =
plainText(product.descriptionHtml) ||
product.summary ||
"برای دریافت توضیحات فنی کامل این دستگاه با کارشناسان سامان اندیش تماس بگیرید.";
const relatedProducts = (data.relatedProducts || []).slice(0, 4);
return (
<main>
<InteriorHeader active="products" />
<div className="product-detail-breadcrumb">
<div className="container">
<Link href="/">صفحه اصلی</Link>
<i>/</i>
<Link href="/products">ماشین‌آلات</Link>
<i>/</i>
<Link href={categoryHref}>{categoryTitle}</Link>
<i>/</i>
<strong>{title}</strong>
</div>
</div>
<section className="product-detail">
<div className="container product-detail__grid">
<ProductGallery images={images} title={title} />
<div className="product-detail__info">
<span className="inner-eyebrow">INDUSTRIAL MACHINERY</span>
<Link className="product-detail__category" href={categoryHref}>
{categoryTitle}
</Link>
<h1>{title}</h1>
<p className="product-detail__english" dir="ltr">
{product.title}
</p>
<p className="product-detail__summary">{description}</p>
<div className="product-detail__features">
<span>
<CheckCircle2 />
ارزیابی فنی پیش از خرید
</span>
<span>
<CheckCircle2 />
پشتیبانی نصب و راه‌اندازی
</span>
</div>
<div className="product-detail__actions">
<a className="button button--red" href="tel:+982188530256">
<Phone size={18} />
استعلام قیمت
</a>
<Link className="button button--navy" href="/contact-us">
درخواست مشاوره
<ArrowLeft size={18} />
</Link>
</div>
</div>
</div>
</section>
<section className="product-description">
<div className="container product-description__grid">
<article>
<span>PRODUCT DESCRIPTION</span>
<h2>توضیحات محصول</h2>
<p>{description}</p>
</article>
<aside>
<h2>نیاز به اطلاعات بیشتر دارید؟</h2>
<p>
مشخصات فنی، وضعیت دستگاه و شرایط تأمین را مستقیماً از کارشناسان
سامان اندیش دریافت کنید.
</p>
<a href="tel:+982188530256" dir="ltr">
021 8853 0256
</a>
</aside>
</div>
</section>
{relatedProducts.length > 0 && (
<section className="related-products section-gray">
<div className="container">
<div className="product-listing__heading">
<div>
<span>RELATED PRODUCTS</span>
<h2>ماشین‌آلات مرتبط</h2>
</div>
</div>
<div className="product-grid">
{relatedProducts.map((relatedProduct) => (
<ProductCard key={relatedProduct.id} product={relatedProduct} />
))}
</div>
</div>
</section>
)}
<InteriorFooter />
</main>
);
}