first commit

This commit is contained in:
Bivekich
2025-06-26 06:59:59 +03:00
commit d44874775c
450 changed files with 76635 additions and 0 deletions

View File

@ -0,0 +1,123 @@
import React, { memo, useState, useEffect } from 'react';
import CatalogProductCard from './CatalogProductCard';
import CatalogProductCardSkeleton from './CatalogProductCardSkeleton';
import { useArticleImage } from '@/hooks/useArticleImage';
import { useCatalogPrices } from '@/hooks/useCatalogPrices';
import { PartsAPIArticle } from '@/types/partsapi';
import toast from 'react-hot-toast';
interface ArticleCardProps {
article: PartsAPIArticle;
index: number;
onVisibilityChange?: (index: number, isVisible: boolean) => void;
}
const ArticleCard: React.FC<ArticleCardProps> = memo(({ article, index, onVisibilityChange }) => {
const [shouldShow, setShouldShow] = useState(false);
const [isChecking, setIsChecking] = useState(true);
// Используем хук для получения изображения
const { imageUrl, isLoading: imageLoading, error } = useArticleImage(article.artId, {
enabled: !!article.artId
});
// Проверяем и очищаем данные артикула и бренда
const articleNumber = article.artArticleNr?.trim();
const brandName = article.artSupBrand?.trim();
// Используем хук для получения цен только если есть и артикул, и бренд
const { getPriceData, addToCart } = useCatalogPrices();
const shouldFetchPrices = articleNumber && brandName && articleNumber !== '' && brandName !== '';
const priceData = shouldFetchPrices ? getPriceData(articleNumber, brandName) : { minPrice: null, cheapestOffer: null, isLoading: false, hasOffers: false };
// Определяем, должен ли отображаться товар
useEffect(() => {
if (!shouldFetchPrices) {
// Если нет данных для поиска, не показываем товар
setShouldShow(false);
setIsChecking(false);
onVisibilityChange?.(index, false);
console.log('❌ ArticleCard: скрываем товар без данных:', { articleNumber, brandName });
return;
}
if (priceData.isLoading) {
// Если данные загружаются, ждем
setIsChecking(true);
return;
}
// Данные загружены - проверяем результат
if (priceData.hasOffers) {
setShouldShow(true);
setIsChecking(false);
onVisibilityChange?.(index, true);
console.log('✅ ArticleCard: показываем товар с предложениями:', { articleNumber, brandName, hasPrice: !!priceData.minPrice });
} else {
setShouldShow(false);
setIsChecking(false);
onVisibilityChange?.(index, false);
console.log('❌ ArticleCard: скрываем товар без предложений:', { articleNumber, brandName });
}
}, [shouldFetchPrices, priceData.isLoading, priceData.hasOffers, articleNumber, brandName, priceData.minPrice, index, onVisibilityChange]);
// Показываем скелетон если данные загружаются или проверяются
if (isChecking || (shouldShow && (priceData.isLoading || imageLoading))) {
return <CatalogProductCardSkeleton />;
}
// Не отображаем ничего если товар не должен показываться
if (!shouldShow) {
return null;
}
// Формируем название товара
const title = [
brandName || 'N/A',
articleNumber || 'N/A',
].filter(part => part !== 'N/A').join(', ');
const brand = brandName || 'Unknown';
// Формируем цену для отображения
let priceText = '';
if (priceData.isLoading) {
priceText = 'Загрузка...';
} else if (priceData.minPrice && priceData.minPrice > 0) {
priceText = `от ${priceData.minPrice.toLocaleString('ru-RU')}`;
} else {
priceText = 'По запросу';
}
// Обработчик добавления в корзину
const handleAddToCart = async (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
if (!shouldFetchPrices) {
toast.error('Недостаточно данных для добавления товара в корзину');
return;
}
await addToCart(articleNumber!, brandName!);
};
return (
<CatalogProductCard
image={imageUrl}
discount="Новинка"
price={priceText}
oldPrice=""
title={title}
brand={brand}
articleNumber={articleNumber}
brandName={brandName}
artId={article.artId}
onAddToCart={handleAddToCart}
/>
);
});
ArticleCard.displayName = 'ArticleCard';
export default ArticleCard;