233 lines
12 KiB
TypeScript
233 lines
12 KiB
TypeScript
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";
|
||
import Link from 'next/link';
|
||
|
||
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();
|
||
}
|
||
|
||
|
||
// فرمت کردن قیمت
|
||
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 : "-";
|
||
};
|
||
|
||
|
||
return (
|
||
<div className="bg-[#f8f9fc] min-h-screen py-8" dir="rtl">
|
||
<div className="mx-auto px-4 container max-w-6xl">
|
||
<ScrollToTop />
|
||
|
||
{/* مسیر راهنما */}
|
||
<div className="text-sm text-gray-500 mb-6 flex items-center gap-2">
|
||
<Link href={'/'}>خانه</Link> > <Link href={'/products'}>محصولات</Link> > <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 col-span-2 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-2xl 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, 2).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-xs" 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-xs" 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]">
|
||
|
||
<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 col-span-2 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>
|
||
{product.attributes?.map((attr: any) => (
|
||
<tr key={attr.id}>
|
||
<td className="py-3 text-[0.9em] text-gray-500">{attr.name}:</td>
|
||
<td className="py-3 font-bold text-[0.9em] text-gray-800 text-left" dir="ltr">{attr.valueText || '-'}</td>
|
||
</tr>
|
||
))}
|
||
|
||
<tr>
|
||
<td className="py-3 text-[0.9em] text-gray-500">کد بینالمللی:</td>
|
||
<td className="py-3 font-bold text-[0.9em] text-gray-800 text-left" dir="ltr">{product.technicalCode}</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|