compare
This commit is contained in:
+154
-3
@@ -6,17 +6,20 @@ import { NextPage } from 'next'
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import { useSearchParams } from 'next/navigation'
|
import { useSearchParams } from 'next/navigation'
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useGetCompare } from './hooks/useCompareData'
|
import { useGetCompare, useSearchCompareProduct } from './hooks/useCompareData'
|
||||||
import { useLocalCart } from '@/app/product/hooks/useLocalCart'
|
import { useLocalCart } from '@/app/product/hooks/useLocalCart'
|
||||||
import { toast } from '@/components/Toast'
|
import { toast } from '@/components/Toast'
|
||||||
import { CompareProduct } from './types/Types'
|
import { CompareProduct } from './types/Types'
|
||||||
import { useSharedStore } from '@/share/store/sharedStore'
|
import { useSharedStore } from '@/share/store/sharedStore'
|
||||||
|
import DefaulModal from '@/components/DefaulModal'
|
||||||
|
|
||||||
const ComparePage: NextPage = () => {
|
const ComparePage: NextPage = () => {
|
||||||
|
|
||||||
const [productIds, setProductIds] = useState<string[]>([]);
|
const [productIds, setProductIds] = useState<string[]>([]);
|
||||||
|
const [isCompareModalOpen, setIsCompareModalOpen] = useState(false);
|
||||||
const search = useSearchParams()
|
const search = useSearchParams()
|
||||||
const { data, isLoading } = useGetCompare(productIds)
|
const { data, isLoading } = useGetCompare(productIds)
|
||||||
|
const { data: searchData } = useSearchCompareProduct(productIds[0])
|
||||||
const { addToLocalCart } = useLocalCart()
|
const { addToLocalCart } = useLocalCart()
|
||||||
const { isLogin } = useSharedStore()
|
const { isLogin } = useSharedStore()
|
||||||
|
|
||||||
@@ -34,10 +37,58 @@ const ComparePage: NextPage = () => {
|
|||||||
toast('محصول به سبد خرید اضافه شد', 'success')
|
toast('محصول به سبد خرید اضافه شد', 'success')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleProductClick = (productId: number) => {
|
||||||
|
const productIdStr = productId.toString()
|
||||||
|
|
||||||
|
// بررسی اینکه محصول قبلاً اضافه نشده باشد
|
||||||
|
if (productIds.includes(productIdStr)) {
|
||||||
|
toast('این محصول قبلاً در لیست مقایسه اضافه شده است', 'error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// اضافه کردن محصول به لیست مقایسه
|
||||||
|
const newProductIds = [...productIds, productIdStr]
|
||||||
|
console.log('New product IDs:', newProductIds)
|
||||||
|
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(() => {
|
useEffect(() => {
|
||||||
const productId = search.get('productId')
|
const productId = search.get('productId')
|
||||||
|
const productIdsParam = search.get('productIds')
|
||||||
|
|
||||||
|
console.log('URL params - productId:', productId, 'productIds:', productIdsParam)
|
||||||
|
|
||||||
|
if (productIdsParam) {
|
||||||
|
// اگر productIds در URL موجود است، آن را استفاده کن
|
||||||
|
const ids = productIdsParam.split(',').filter(id => id.trim())
|
||||||
|
console.log('Parsed product IDs:', ids)
|
||||||
|
setProductIds(ids)
|
||||||
|
|
||||||
|
// حذف productId قدیمی از URL
|
||||||
if (productId) {
|
if (productId) {
|
||||||
setProductIds([productId]);
|
const url = new URL(window.location.href)
|
||||||
|
url.searchParams.delete('productId')
|
||||||
|
window.history.replaceState({}, '', url.toString())
|
||||||
|
}
|
||||||
|
} else if (productId) {
|
||||||
|
// اگر فقط productId موجود است، آن را به productIds تبدیل کن
|
||||||
|
console.log('Single product ID:', productId)
|
||||||
|
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]);
|
}, [search]);
|
||||||
|
|
||||||
@@ -74,7 +125,7 @@ const ComparePage: NextPage = () => {
|
|||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<div className='mt-24 px-20'>
|
<div className='mt-24 px-20'>
|
||||||
<div className='flex border-b border-border'>
|
<div className='flex items-center border-b border-border'>
|
||||||
{products.map((product, index) => (
|
{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`}>
|
<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
|
<Image
|
||||||
@@ -104,6 +155,10 @@ const ComparePage: NextPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
<Button variant={'outline'} onClick={() => setIsCompareModalOpen(true)}>
|
||||||
|
افزودن به مقایسه
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-8'>
|
<div className='mt-8'>
|
||||||
@@ -127,6 +182,102 @@ const ComparePage: NextPage = () => {
|
|||||||
</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-blue-500 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-blue-600 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>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,18 @@ import { CompareResponse } from "../types/Types";
|
|||||||
export const getCompare = async (
|
export const getCompare = async (
|
||||||
productIds: string[]
|
productIds: string[]
|
||||||
): Promise<CompareResponse> => {
|
): Promise<CompareResponse> => {
|
||||||
const { data } = await axios.get(`/product/compare?productIds=${productIds}`);
|
console.log("API call - productIds:", productIds);
|
||||||
|
|
||||||
|
// روش اول: ارسال آرایه به صورت جداگانه
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
productIds.forEach((id) => {
|
||||||
|
params.append("productIds", id);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Final URL:", `/product/compare?${params.toString()}`);
|
||||||
|
|
||||||
|
const { data } = await axios.get(`/product/compare?${params.toString()}`);
|
||||||
|
console.log("API response:", data);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import * as api from "../service/Service";
|
import * as api from "../service/Service";
|
||||||
|
import { useSharedStore } from "@/share/store/sharedStore";
|
||||||
|
|
||||||
export const useGetDetailProduct = (id: string) => {
|
export const useGetDetailProduct = (id: string) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
@@ -26,10 +27,11 @@ export const useAddQuestion = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useCheckWishProduct = (productId: string, variantId: string) => {
|
export const useCheckWishProduct = (productId: string, variantId: string) => {
|
||||||
|
const { isLogin } = useSharedStore();
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ["check-wish-product", productId, variantId],
|
queryKey: ["check-wish-product", productId, variantId],
|
||||||
queryFn: () => api.checkWishProduct(productId, variantId),
|
queryFn: () => api.checkWishProduct(productId, variantId),
|
||||||
enabled: !!productId && !!variantId,
|
enabled: !!productId && !!variantId && isLogin,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -73,7 +73,7 @@ axiosInstance.interceptors.response.use(
|
|||||||
console.error("Token refresh failed:", refreshError);
|
console.error("Token refresh failed:", refreshError);
|
||||||
await removeToken();
|
await removeToken();
|
||||||
await removeRefreshToken();
|
await removeRefreshToken();
|
||||||
window.location.href = `/`;
|
// window.location.href = `/`;
|
||||||
return Promise.reject(refreshError);
|
return Promise.reject(refreshError);
|
||||||
} finally {
|
} finally {
|
||||||
window.isRefreshingToken = false;
|
window.isRefreshingToken = false;
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
export const TOKEN_NAME = "sh_token";
|
export const TOKEN_NAME = "sh_token";
|
||||||
export const REFRESH_TOKEN_NAME = "sh_refresh_token";
|
export const REFRESH_TOKEN_NAME = "sh_refresh_token";
|
||||||
export const BASE_URL = "https://shop-api.dev.danakcorp.com";
|
// export const BASE_URL = "https://shop-api.dev.danakcorp.com";
|
||||||
// export const BASE_URL = "https://api.shinan.ir";
|
export const BASE_URL = "http://192.168.1.111:4000";
|
||||||
|
|
||||||
export const PRIMARY_COLOR = "#015699";
|
export const PRIMARY_COLOR = "#015699";
|
||||||
|
|||||||
Reference in New Issue
Block a user