300 lines
14 KiB
TypeScript
300 lines
14 KiB
TypeScript
'use client'
|
||
import { Button } from '@/components/ui/button'
|
||
import { Separator } from '@/components/ui/separator'
|
||
import Layout from '@/hoc/Layout'
|
||
import { NextPage } from 'next'
|
||
import Image from 'next/image'
|
||
import { useSearchParams } from 'next/navigation'
|
||
import { useEffect, useState, Suspense } from 'react';
|
||
import { useGetCompare, useSearchCompareProduct } from './hooks/useCompareData'
|
||
import { useLocalCart } from '@/app/product/hooks/useLocalCart'
|
||
import { toast } from '@/components/Toast'
|
||
import { CompareProduct } from './types/Types'
|
||
import { useSharedStore } from '@/share/store/sharedStore'
|
||
import DefaulModal from '@/components/DefaulModal'
|
||
|
||
const ComparePageContent: NextPage = () => {
|
||
|
||
const [productIds, setProductIds] = useState<string[]>([]);
|
||
const [isCompareModalOpen, setIsCompareModalOpen] = useState(false);
|
||
const search = useSearchParams()
|
||
const { data, isLoading } = useGetCompare(productIds)
|
||
const { data: searchData } = useSearchCompareProduct(productIds[0])
|
||
const { addToLocalCart } = useLocalCart()
|
||
const { isLogin } = useSharedStore()
|
||
|
||
const products = data?.results?.products || []
|
||
|
||
const handleAddToCart = (product: CompareProduct) => {
|
||
if (!isLogin) {
|
||
toast('لطفا ابتدا وارد حساب کاربری خود شوید', 'error')
|
||
return
|
||
}
|
||
|
||
if (!product._id || !product.default_variant?._id) return
|
||
|
||
addToLocalCart(product._id, product.default_variant._id, 1)
|
||
toast('محصول به سبد خرید اضافه شد', 'success')
|
||
}
|
||
|
||
const handleProductClick = (productId: number) => {
|
||
const productIdStr = productId.toString()
|
||
|
||
// بررسی اینکه محصول قبلاً اضافه نشده باشد
|
||
if (productIds.includes(productIdStr)) {
|
||
toast('این محصول قبلاً در لیست مقایسه اضافه شده است', 'error')
|
||
return
|
||
}
|
||
|
||
// اضافه کردن محصول به لیست مقایسه
|
||
const newProductIds = [...productIds, productIdStr]
|
||
setProductIds(newProductIds)
|
||
|
||
// بهروزرسانی URL با محصولات جدید
|
||
const url = new URL(window.location.href)
|
||
url.searchParams.set('productIds', newProductIds.join(','))
|
||
url.searchParams.delete('productId') // حذف productId قدیمی
|
||
window.history.pushState({}, '', url.toString())
|
||
|
||
setIsCompareModalOpen(false)
|
||
toast('محصول به لیست مقایسه اضافه شد', 'success')
|
||
}
|
||
|
||
useEffect(() => {
|
||
const productId = search.get('productId')
|
||
const productIdsParam = search.get('productIds')
|
||
|
||
|
||
if (productIdsParam) {
|
||
// اگر productIds در URL موجود است، آن را استفاده کن
|
||
const ids = productIdsParam.split(',').filter(id => id.trim())
|
||
setProductIds(ids)
|
||
|
||
// حذف productId قدیمی از URL
|
||
if (productId) {
|
||
const url = new URL(window.location.href)
|
||
url.searchParams.delete('productId')
|
||
window.history.replaceState({}, '', url.toString())
|
||
}
|
||
} else if (productId) {
|
||
// اگر فقط productId موجود است، آن را به productIds تبدیل کن
|
||
setProductIds([productId])
|
||
|
||
// URL را به productIds تبدیل کن
|
||
const url = new URL(window.location.href)
|
||
url.searchParams.delete('productId')
|
||
url.searchParams.set('productIds', productId)
|
||
window.history.replaceState({}, '', url.toString())
|
||
}
|
||
}, [search]);
|
||
|
||
|
||
if (isLoading) {
|
||
return (
|
||
<Layout>
|
||
<div className='mt-24 px-20'>
|
||
<div className='flex justify-center items-center min-h-[400px]'>
|
||
<div className='text-center'>
|
||
<div className='animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto'></div>
|
||
<p className='mt-4 text-gray-600'>در حال بارگذاری...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Layout>
|
||
)
|
||
}
|
||
|
||
if (products.length === 0) {
|
||
return (
|
||
<Layout>
|
||
<div className='mt-24 px-20'>
|
||
<div className='flex justify-center items-center min-h-[400px]'>
|
||
<div className='text-center'>
|
||
<p className='text-gray-600'>هیچ محصولی برای مقایسه انتخاب نشده است</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Layout>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<Layout>
|
||
<div className='mt-24 px-20'>
|
||
<div className='flex items-center border-b border-border'>
|
||
{products.map((product, index) => (
|
||
<div key={product._id} className={`w-[300px] flex flex-col justify-center items-center ${index < products.length - 1 ? 'border-l border-border' : ''} pb-5`}>
|
||
<Image
|
||
src={product.imagesUrl.cover}
|
||
alt={product.title_fa}
|
||
width={150}
|
||
height={150}
|
||
className='max-w-[100px] max-h-[100px] object-contain'
|
||
/>
|
||
|
||
<div className='mt-6 font-light text-sm text-center'>
|
||
{product.title_fa}
|
||
</div>
|
||
|
||
<div className='mt-8 text-sm font-light'>
|
||
{product.default_variant.price.selling_price.toLocaleString()} <span className='text-[10px]'>تومان</span>
|
||
</div>
|
||
|
||
<div className='mt-5'>
|
||
<Button
|
||
onClick={() => handleAddToCart(product)}
|
||
disabled={!product.default_variant.stock}
|
||
className={!product.default_variant.stock ? 'opacity-50 cursor-not-allowed' : ''}
|
||
>
|
||
{product.default_variant.stock > 0 ? 'افزودن به سبد' : 'ناموجود'}
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
))}
|
||
|
||
<Button variant={'outline'} onClick={() => setIsCompareModalOpen(true)}>
|
||
افزودن به مقایسه
|
||
</Button>
|
||
</div>
|
||
|
||
<div className='mt-8'>
|
||
<div className='text-sm font-light'>
|
||
مشخصات
|
||
</div>
|
||
</div>
|
||
|
||
{products[0]?.specifications?.map((spec, specIndex) => (
|
||
<div key={specIndex} className='mt-9 border-b border-border pb-7'>
|
||
<div className='text-[#999999] text-sm'>{spec.title}</div>
|
||
|
||
<div className='flex mt-6 font-light'>
|
||
{products.map((product, productIndex) => (
|
||
<div key={product._id} className='w-[300px] flex items-center'>
|
||
{product.specifications?.[specIndex]?.values?.join(', ') || '-'}
|
||
{productIndex < products.length - 1 && <Separator orientation='vertical' className='ml-6' />}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* مودال انتخاب کالا برای مقایسه */}
|
||
<DefaulModal
|
||
open={isCompareModalOpen}
|
||
close={() => setIsCompareModalOpen(false)}
|
||
isHeader={true}
|
||
title_header="انتخاب کالا برای مقایسه"
|
||
width={800}
|
||
>
|
||
<div className="space-y-6">
|
||
{/* نوار جستجو */}
|
||
<div className="flex items-center gap-4">
|
||
<div className="text-sm text-gray-600 whitespace-nowrap">
|
||
759 كالا
|
||
</div>
|
||
<div className="flex-1 relative">
|
||
<input
|
||
type="text"
|
||
placeholder="نام یا کد کالا را وارد کنید"
|
||
className="w-full px-4 py-3 pr-12 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary text-sm"
|
||
/>
|
||
<div className="absolute left-3 top-1/2 transform -translate-y-1/2">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||
<circle cx="11" cy="11" r="8" />
|
||
<path d="m21 21-4.35-4.35" />
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* عنوان برترین کالاها */}
|
||
<div className="text-sm font-medium text-gray-800">
|
||
برترین کالاها برای مقایسه
|
||
</div>
|
||
|
||
{/* لیست محصولات */}
|
||
<div className="grid grid-cols-3 gap-3 max-h-80 overflow-y-auto">
|
||
{searchData?.results?.products?.slice(0, 6).map((product: CompareProduct) => (
|
||
<div
|
||
key={product._id}
|
||
className="border border-gray-200 rounded-lg p-3 hover:shadow-md transition-shadow bg-white cursor-pointer"
|
||
onClick={() => handleProductClick(product._id)}
|
||
>
|
||
<div className="flex flex-col items-center text-center space-y-2">
|
||
{/* تصویر محصول */}
|
||
<div className="w-full h-24 relative">
|
||
<Image
|
||
src={product.imagesUrl.cover}
|
||
alt={product.title_fa}
|
||
fill
|
||
className="object-cover rounded-lg"
|
||
/>
|
||
</div>
|
||
|
||
{/* متن ذخیره سازی */}
|
||
<div className="text-xs text-primary font-medium">
|
||
ذخیره سازی
|
||
</div>
|
||
|
||
{/* نام محصول */}
|
||
<h3 className="text-xs font-medium text-gray-900 leading-tight">
|
||
{product.title_fa}
|
||
</h3>
|
||
|
||
{/* ستارهها */}
|
||
<div className="flex items-center gap-1">
|
||
{[...Array(5)].map((_, i) => (
|
||
<svg key={i} width="10" height="10" viewBox="0 0 24 24" fill={i < 3.5 ? "#FFD700" : "#E5E7EB"} className="w-2.5 h-2.5">
|
||
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
|
||
</svg>
|
||
))}
|
||
</div>
|
||
|
||
{/* قیمت */}
|
||
<div className="text-xs font-medium text-gray-900">
|
||
{product.default_variant.price.selling_price.toLocaleString()} <span className="text-[10px]">تومان</span>
|
||
</div>
|
||
|
||
{/* آیکون قلب */}
|
||
<button
|
||
className="p-1 hover:bg-gray-100 rounded-full transition-colors"
|
||
onClick={(e) => {
|
||
e.stopPropagation()
|
||
// TODO: اضافه کردن به علاقهمندیها
|
||
}}
|
||
>
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</DefaulModal>
|
||
</Layout>
|
||
)
|
||
}
|
||
|
||
const ComparePage: NextPage = () => {
|
||
return (
|
||
<Suspense fallback={
|
||
<Layout>
|
||
<div className='mt-24 px-20'>
|
||
<div className='flex justify-center items-center min-h-[400px]'>
|
||
<div className='text-center'>
|
||
<div className='animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto'></div>
|
||
<p className='mt-4 text-gray-600'>در حال بارگذاری...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Layout>
|
||
}>
|
||
<ComparePageContent />
|
||
</Suspense>
|
||
)
|
||
}
|
||
|
||
export default ComparePage |