212 lines
6.7 KiB
TypeScript
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(/ /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>
|
|
);
|
|
}
|