Files
parsshop/app/product/[slug]/page.tsx
2026-03-30 22:35:43 +03:30

252 lines
13 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import ScrollToTop from '@/components/scrolltop';
import { notFound } from 'next/navigation';
import Image from "next/image";
import ProductCartAction from '@/components/cartaction';
import { getProductBySlug } from "@/public/src/services/products/api";
interface PageProps {
params: Promise<{ slug: string }>;
}
export default async function SingleProductPage({ params }: PageProps) {
// --------------------------------------------------------
// ۱. منطق دریافت داده‌ها (دقیقا مشابه درخواست شما)
// --------------------------------------------------------
const resolvedParams = await params;
const slug = resolvedParams.slug;
console.log("👉 Extracted slug from URL:", slug);
if (!slug) {
return notFound();
}
const product = await getProductBySlug(slug);
if (!product) {
console.log(`🔴 Product not found or API failed for slug: ${slug}`);
return notFound();
}
// --------------------------------------------------------
// ۲. آماده‌سازی و مپ کردن داده‌های API برای UI
// --------------------------------------------------------
// فرمت کردن قیمت
const formattedPrice = product.display_price
? product.display_price.toLocaleString('fa-IR')
: null;
// وضعیت موجودی
const hasStock = product.stock && product.stock > 0;
// تصویر محصول (جلوگیری از خطای null در next/image)
const imageUrl = product.mainImageUrl || '/placeholder-image.png'; // می‌توانید آدرس یک عکس پیش‌فرض را اینجا بگذارید
// دریافت ویژگی‌ها (Attributes) از آرایه دیتابیس با تابع کمکی
const getAttribute = (attrName: string) => {
const attr = product.attributes?.find((a: any) => a.name === attrName);
return attr ? attr.valueText : "-";
};
// --------------------------------------------------------
// ۳. خروجی UI (بدون تغییر در ساختار و استایل‌ها)
// --------------------------------------------------------
return (
<div className="bg-[#f8f9fc] min-h-screen py-8" dir="rtl">
<div className="mx-auto px-4 lg:px-8 container max-w-7xl">
<ScrollToTop />
{/* مسیر راهنما */}
<div className="text-sm text-gray-500 mb-6 flex items-center gap-2">
<span>خانه</span> &gt; <span>محصولات</span> &gt; <span className="text-gray-800 font-semibold">{product.title}</span>
</div>
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 lg:gap-8">
{/* بخش 1: معرفی محصول */}
<div className="lg:col-span-8 order-1 lg:order-none">
<div className="bg-white rounded-3xl shadow-sm p-6 md:p-8 flex flex-col md:flex-row gap-8 items-center border border-gray-100">
{/* باکس تصویر */}
<div className="w-full md:w-[52%] h-72 rounded-2xl bg-[linear-gradient(135deg,#f8f9fc_0%,#e2e8f0_100%)] flex items-center justify-center p-6 relative">
{product.featured && (
<span className="absolute top-4 right-4 bg-orange-500 text-white text-xs font-bold px-2 py-1 rounded-md">
پیشنهاد ویژه
</span>
)}
<Image
src={imageUrl}
width={250}
height={250}
alt={product.title}
className="object-contain mix-blend-multiply"
/>
</div>
<div className="flex-1 w-full">
<div className="inline-block px-3 py-1 bg-gray-100 text-gray-700 rounded-lg text-sm font-bold mb-4 tracking-wider">
{product.brand}
</div>
<h1 className="text-3xl font-bold text-gray-800 mb-6 leading-relaxed">
{product.title}
</h1>
<p className='text-gray-500 text-[13px] mb-8'>
{product.meta?.shortDescription || 'توضیحات کوتاهی برای این محصول ثبت نشده است.'}
</p>
<div className="grid grid-cols-2 gap-4">
{/* رندر داینامیک ۳ ویژگی اول از API */}
{product.attributes?.slice(0, 3).map((attr: any) => (
<div key={attr.id} className="bg-gray-50 p-4 rounded-2xl flex flex-col items-center justify-center text-center border border-gray-100">
<span className="text-gray-500 text-sm mb-2">{attr.name}</span>
<span className="font-bold text-gray-800 text-sm" dir="ltr">{attr.valueText || '-'}</span>
</div>
))}
{/* آیتم چهارم: دسته‌بندی (برای حفظ ظاهر گرید ۴ تایی) */}
<div className="bg-gray-50 p-4 rounded-2xl flex flex-col items-center justify-center text-center border border-gray-100">
<span className="text-gray-500 text-sm mb-2">دستهبندی</span>
<span className="font-bold text-gray-800 text-sm" dir="ltr">{product.primaryCategory?.name || '-'}</span>
</div>
</div>
</div>
</div>
</div>
{/* بخش 2: سایدبار و دکمه خرید */}
<div className="lg:col-span-4 col-span-2 lg:row-span-2 order-2 lg:order-none relative h-full">
<div className="flex flex-col gap-4 lg:sticky lg:top-[20px] pb-8">
<div className="bg-white rounded-[2rem] shadow-[0_4px_20px_-10px_rgba(0,0,0,0.05)] p-5 border border-gray-100 text-center">
{hasStock ? (
<div className="bg-[#eaf8ee] text-[#28a745] py-3 rounded-2xl text-sm font-bold mb-4">
موجود در انبار ({product.stock} عدد)
</div>
) : (
<div className="bg-red-50 text-red-500 py-3 rounded-2xl text-sm font-bold mb-4">
ناموجود - نیاز به تامین
</div>
)}
<div className="bg-[#f8f9fa] rounded-2xl py-6 mb-6 flex flex-col items-center justify-center">
<span className="text-gray-500 text-sm mb-2">قیمت مصرفکننده:</span>
{formattedPrice ? (
<>
<span className="text-3xl font-extrabold text-[#1a2332] tracking-tight">{formattedPrice}</span>
<span className="text-gray-500 text-sm mt-2"> {product.currency_label}</span>
</>
) : (
<span className="text-2xl font-extrabold text-[#1a2332]">استعلام قیمت</span>
)}
</div>
<ProductCartAction product={product} />
<div className="flex flex-col gap-3 text-[13px] text-gray-500 mt-4 border-t border-gray-100 pt-6">
<div className="flex items-center gap-2 justify-center">
<span>ضمانت اصالت دائم کالا</span>
</div>
<div className="flex items-center gap-2 justify-center">
<span>ارسال فوری (شیراز ۲ ساعته)</span>
</div>
<div className="flex items-center gap-2 justify-center">
<span>فاکتور رسمی شرکتی</span>
</div>
</div>
</div>
{/* دکمه‌های دانلود دیتاشیت و مشاوره */}
<div className="bg-white rounded-3xl p-5 shadow-[0_4px_20px_-10px_rgba(0,0,0,0.05)] border border-gray-100 hidden lg:flex justify-between items-center cursor-pointer hover:bg-gray-50 transition-colors">
<div className="flex flex-col gap-1 text-right">
<span className="font-extrabold text-[#1a2332] text-sm">دانلود دیتاشیت</span>
<span className="text-xs text-gray-400 font-sans tracking-wide" dir="ltr">PDF 1.2 MB English</span>
</div>
<div className="w-12 h-12 bg-red-50 rounded-xl flex items-center justify-center text-red-400 shrink-0">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
</svg>
</div>
</div>
<div className="bg-[#121826] rounded-3xl p-5 shadow-lg hidden lg:flex justify-between items-center cursor-pointer hover:bg-[#1a2332] transition-colors relative overflow-hidden">
<div className="flex flex-col gap-1 z-10 text-right">
<span className="font-extrabold text-white text-sm">نیاز به مشاوره؟</span>
<span className="text-xs text-gray-400">تماس مستقیم با مهندسین</span>
</div>
<div className="w-12 h-12 bg-white/10 rounded-xl flex items-center justify-center text-white z-10 backdrop-blur-sm shrink-0">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
</div>
<div className="absolute top-0 right-0 w-32 h-32 bg-white/5 rounded-full -mr-10 -mt-10 blur-2xl"></div>
</div>
</div>
</div>
{/* بخش 3: مشخصات ابعادی */}
<div className="lg:col-span-8 order-3 lg:order-none">
<div className="bg-white rounded-3xl shadow-sm p-6 md:p-8 border border-gray-100">
<div className="flex justify-between items-center mb-8 border-b border-gray-100 pb-4">
<h2 className="text-xl font-bold text-gray-800">مشخصات ابعادی دقیق</h2>
<span className="text-sm text-gray-400">واحد: میلیمتر (mm)</span>
</div>
<div className="flex flex-col md:flex-row gap-12 items-center">
<div className="w-full md:w-1/2 bg-[#121826] rounded-2xl aspect-[4/3] relative flex items-center justify-center overflow-hidden">
<div className="w-48 h-48 border border-gray-600 rounded-full flex items-center justify-center relative">
<div className="w-20 h-20 border border-gray-600 rounded-full"></div>
<div className="absolute w-full h-[1px] bg-orange-500"></div>
<div className="absolute h-1/2 w-[1px] bg-orange-500 top-1/2 right-1/2"></div>
<div className="absolute top-1/2 -mt-5 left-[60%] text-orange-400 text-xs font-mono px-1 z-10" dir="ltr">
{"$D=" + getAttribute('قطر خارجی').replace('mm', '').trim() + "$"}
</div>
<div className="absolute top-[60%] right-1/2 text-orange-400 text-xs font-mono px-1 z-10" dir="ltr">
{"$d=" + getAttribute('قطر داخلی').replace('mm', '').trim() + "$"}
</div>
</div>
</div>
<div className="w-full md:w-1/2">
<table className="w-full text-right text-sm">
<tbody>
<tr className="border-b border-gray-50">
<td className="py-3 text-gray-500">قطر داخلی ($d$)</td>
<td className="py-3 font-bold text-gray-800 text-left" dir="ltr">{getAttribute('قطر داخلی')}</td>
</tr>
<tr className="border-b border-gray-50">
<td className="py-3 text-gray-500">قطر خارجی ($D$)</td>
<td className="py-3 font-bold text-gray-800 text-left" dir="ltr">{getAttribute('قطر خارجی')}</td>
</tr>
<tr className="border-b border-gray-50">
<td className="py-3 text-gray-500">پهنا ($B$)</td>
<td className="py-3 font-bold text-gray-800 text-left" dir="ltr">{getAttribute('پهنا')}</td>
</tr>
<tr className="border-b border-gray-50">
<td className="py-3 text-gray-500">وزن خالص</td>
<td className="py-3 font-bold text-gray-800 text-left" dir="ltr">{getAttribute('وزن')}</td>
</tr>
<tr className="border-b border-gray-50">
<td className="py-3 text-gray-500">جنس قفسه</td>
<td className="py-3 font-bold text-gray-800 text-left" dir="ltr">{getAttribute('جنس قفسه')}</td>
</tr>
<tr>
<td className="py-3 text-gray-500">کد بینالمللی</td>
<td className="py-3 font-bold text-gray-800 text-left" dir="ltr">{product.technicalCode}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}