Удален файл интеграции с Parts Index API и обновлены компоненты для работы с корзиной и избранным. Добавлены функции для обработки добавления товаров в корзину с уведомлениями, улучшена логика работы с избранным, а также добавлены фильтры для истории поиска по производителю.
This commit is contained in:
@ -23,7 +23,7 @@ export default function InfoCard({
|
||||
currency = 'RUB',
|
||||
image
|
||||
}: InfoCardProps) {
|
||||
const { addToFavorites, removeFromFavorites, isFavorite } = useFavorites();
|
||||
const { addToFavorites, removeFromFavorites, isFavorite, favorites } = useFavorites();
|
||||
|
||||
// Проверяем, есть ли товар в избранном
|
||||
const isItemFavorite = isFavorite(productId, offerKey, articleNumber, brand);
|
||||
@ -34,9 +34,18 @@ export default function InfoCard({
|
||||
e.stopPropagation();
|
||||
|
||||
if (isItemFavorite) {
|
||||
// Создаем ID для удаления
|
||||
const id = `${productId || offerKey || ''}:${articleNumber}:${brand}`;
|
||||
removeFromFavorites(id);
|
||||
// Находим товар в избранном по правильному ID
|
||||
const favoriteItem = favorites.find((fav: any) => {
|
||||
// Проверяем по разным комбинациям идентификаторов
|
||||
if (productId && fav.productId === productId) return true;
|
||||
if (offerKey && fav.offerKey === offerKey) return true;
|
||||
if (fav.article === articleNumber && fav.brand === brand) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
if (favoriteItem) {
|
||||
removeFromFavorites(favoriteItem.id);
|
||||
}
|
||||
} else {
|
||||
// Добавляем в избранное
|
||||
addToFavorites({
|
||||
|
@ -1,96 +1,47 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { PARTS_INDEX_SEARCH_BY_ARTICLE } from "@/lib/graphql";
|
||||
|
||||
interface ProductCharacteristicsProps {
|
||||
result?: any;
|
||||
}
|
||||
|
||||
const ProductCharacteristics = ({ result }: ProductCharacteristicsProps) => {
|
||||
const [partsIndexData, setPartsIndexData] = useState<any>(null);
|
||||
|
||||
// Функция для рендеринга характеристик из нашей базы данных
|
||||
const renderInternalCharacteristics = () => {
|
||||
if (!result?.characteristics || result.characteristics.length === 0) return null;
|
||||
// Запрос к Parts Index для получения дополнительных характеристик
|
||||
const { data: partsIndexResult, loading: partsIndexLoading } = useQuery(PARTS_INDEX_SEARCH_BY_ARTICLE, {
|
||||
variables: {
|
||||
articleNumber: result?.articleNumber || '',
|
||||
brandName: result?.brand || '',
|
||||
lang: 'ru'
|
||||
},
|
||||
skip: !result?.articleNumber || !result?.brand,
|
||||
errorPolicy: 'ignore'
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-layout-vflex flex-block-53">
|
||||
<div className="w-layout-hflex flex-block-55">
|
||||
<span className="text-block-29" style={{ fontWeight: 'bold', color: '#333' }}>
|
||||
Характеристики товара:
|
||||
</span>
|
||||
</div>
|
||||
{result.characteristics.map((char: any, index: number) => (
|
||||
<div key={index} className="w-layout-hflex flex-block-55">
|
||||
<span className="text-block-29">{char.characteristic.name}:</span>
|
||||
<span className="text-block-28">{char.value}</span>
|
||||
useEffect(() => {
|
||||
if (partsIndexResult?.partsIndexSearchByArticle) {
|
||||
setPartsIndexData(partsIndexResult.partsIndexSearchByArticle);
|
||||
}
|
||||
}, [partsIndexResult]);
|
||||
|
||||
// Функция для рендеринга параметров из Parts Index
|
||||
const renderPartsIndexParameters = () => {
|
||||
if (!partsIndexData?.parameters) return null;
|
||||
|
||||
return partsIndexData.parameters.map((paramGroup: any, groupIndex: number) => (
|
||||
<div key={groupIndex} className="w-layout-vflex flex-block-53">
|
||||
{paramGroup.params?.map((param: any, paramIndex: number) => (
|
||||
<div key={paramIndex} className="w-layout-hflex flex-block-55">
|
||||
<span className="text-block-29">{param.title}:</span>
|
||||
<span className="text-block-28">
|
||||
{param.values?.map((value: any) => value.value).join(', ') || 'Нет данных'}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Функция для рендеринга характеристик из Parts Index
|
||||
const renderPartsIndexCharacteristics = () => {
|
||||
if (!result?.partsIndexCharacteristics || result.partsIndexCharacteristics.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="w-layout-vflex flex-block-53">
|
||||
<div className="w-layout-hflex flex-block-55">
|
||||
<span className="text-block-29" style={{ fontWeight: 'bold', color: '#333' }}>
|
||||
Дополнительные характеристики:
|
||||
</span>
|
||||
</div>
|
||||
{result.partsIndexCharacteristics.map((char: any, index: number) => (
|
||||
<div key={index} className="w-layout-hflex flex-block-55">
|
||||
<span className="text-block-29">{char.name}:</span>
|
||||
<span className="text-block-28">{char.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Функция для рендеринга изображений из нашей базы данных
|
||||
const renderInternalImages = () => {
|
||||
if (!result?.images || result.images.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="w-layout-vflex flex-block-53" style={{ marginTop: '20px' }}>
|
||||
<div className="w-layout-hflex flex-block-55">
|
||||
<span className="text-block-29" style={{ fontWeight: 'bold', color: '#333' }}>
|
||||
Изображения товара:
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-layout-hflex" style={{ flexWrap: 'wrap', gap: '10px', marginTop: '10px' }}>
|
||||
{result.images.slice(0, 6).map((image: any, index: number) => (
|
||||
<div key={image.id || index} style={{
|
||||
border: '1px solid #e0e0e0',
|
||||
borderRadius: '8px',
|
||||
overflow: 'hidden',
|
||||
width: '120px',
|
||||
height: '120px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#f9f9f9'
|
||||
}}>
|
||||
<img
|
||||
src={image.url}
|
||||
alt={image.alt || `${result?.brand} ${result?.articleNumber} - изображение ${index + 1}`}
|
||||
style={{
|
||||
maxWidth: '100%',
|
||||
maxHeight: '100%',
|
||||
objectFit: 'contain',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
}}
|
||||
onClick={() => window.open(image.url, '_blank')}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
));
|
||||
};
|
||||
|
||||
return (
|
||||
@ -111,27 +62,33 @@ const ProductCharacteristics = ({ result }: ProductCharacteristicsProps) => {
|
||||
<span className="text-block-29">Название:</span>
|
||||
<span className="text-block-28">{result.name}</span>
|
||||
</div>
|
||||
{result?.description && (
|
||||
{partsIndexData?.originalName && (
|
||||
<div className="w-layout-hflex flex-block-55">
|
||||
<span className="text-block-29">Оригинальное название:</span>
|
||||
<span className="text-block-28">{partsIndexData.originalName}</span>
|
||||
</div>
|
||||
)}
|
||||
{partsIndexData?.description && (
|
||||
<div className="w-layout-hflex flex-block-55">
|
||||
<span className="text-block-29">Описание:</span>
|
||||
<span className="text-block-28" style={{ maxWidth: '400px', wordWrap: 'break-word' }}>
|
||||
{result.description}
|
||||
</span>
|
||||
<span className="text-block-28">{partsIndexData.description}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Характеристики из нашей базы данных */}
|
||||
{renderInternalCharacteristics()}
|
||||
|
||||
{/* Дополнительные характеристики из Parts Index */}
|
||||
{renderPartsIndexCharacteristics()}
|
||||
{partsIndexLoading ? (
|
||||
<div className="w-layout-vflex flex-block-53">
|
||||
<div className="w-layout-hflex flex-block-55">
|
||||
<span className="text-block-29">Загрузка характеристик...</span>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
renderPartsIndexParameters()
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Изображения из нашей базы данных */}
|
||||
{renderInternalImages()}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
Reference in New Issue
Block a user