Files
shop-front/src/app/compare/page.tsx
T
hamid zarghami e50206bca4 remove some logs
2025-11-06 10:04:45 +03:30

300 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
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.
'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