import React, { useState } from "react"; import { useCart } from "@/contexts/CartContext"; import { useFavorites } from "@/contexts/FavoritesContext"; import toast from "react-hot-toast"; const INITIAL_OFFERS_LIMIT = 5; interface CoreProductCardOffer { id?: string; productId?: string; offerKey?: string; pcs: string; days: string; recommended?: boolean; price: string; count: string; isExternal?: boolean; currency?: string; warehouse?: string; supplier?: string; deliveryTime?: number; } interface CoreProductCardProps { brand: string; article: string; name: string; image?: string; offers: CoreProductCardOffer[]; showMoreText?: string; isAnalog?: boolean; isLoadingOffers?: boolean; onLoadOffers?: () => void; partsIndexPowered?: boolean; } const CoreProductCard: React.FC = ({ brand, article, name, image, offers, showMoreText, isAnalog = false, isLoadingOffers = false, onLoadOffers, partsIndexPowered = false }) => { const { addItem } = useCart(); const { addToFavorites, removeFromFavorites, isFavorite, favorites } = useFavorites(); const [visibleOffersCount, setVisibleOffersCount] = useState(INITIAL_OFFERS_LIMIT); const [quantities, setQuantities] = useState<{ [key: number]: number }>( offers.reduce((acc, _, index) => ({ ...acc, [index]: 1 }), {}) ); const [quantityErrors, setQuantityErrors] = useState<{ [key: number]: string }>({}); const displayedOffers = offers.slice(0, visibleOffersCount); const hasMoreOffers = visibleOffersCount < offers.length; // Проверяем, есть ли товар в избранном const isItemFavorite = isFavorite( offers[0]?.productId, offers[0]?.offerKey, article, brand ); // Функция для парсинга цены из строки const parsePrice = (priceStr: string): number => { const cleanPrice = priceStr.replace(/[^\d.,]/g, '').replace(',', '.'); return parseFloat(cleanPrice) || 0; }; // Функция для парсинга времени доставки const parseDeliveryTime = (daysStr: string): string => { const match = daysStr.match(/\d+/); return match ? `${match[0]} дней` : daysStr; }; // Функция для парсинга количества в наличии const parseStock = (stockStr: string): number => { const match = stockStr.match(/\d+/); return match ? parseInt(match[0]) : 0; }; const handleQuantityInput = (index: number, value: string) => { const offer = offers[index]; const availableStock = parseStock(offer.pcs); let num = parseInt(value, 10); if (isNaN(num) || num < 1) num = 1; if (num > availableStock) { toast.error(`Максимум ${availableStock} шт.`); return; } setQuantities(prev => ({ ...prev, [index]: num })); }; const handleAddToCart = (offer: CoreProductCardOffer, index: number) => { const quantity = quantities[index] || 1; const availableStock = parseStock(offer.pcs); // Проверяем наличие if (quantity > availableStock) { toast.error(`Недостаточно товара в наличии. Доступно: ${availableStock} шт.`); return; } const numericPrice = parsePrice(offer.price); addItem({ productId: offer.productId, offerKey: offer.offerKey, name: name, description: `${brand} ${article} - ${name}`, brand: brand, article: article, price: numericPrice, currency: offer.currency || 'RUB', quantity: quantity, deliveryTime: parseDeliveryTime(offer.days), warehouse: offer.warehouse || 'Склад', supplier: offer.supplier || (offer.isExternal ? 'AutoEuro' : 'Protek'), isExternal: offer.isExternal || false, image: image, }); // Показываем тоастер вместо alert toast.success(
Товар добавлен в корзину!
{`${brand} ${article} (${quantity} шт.)`}
, { duration: 3000, icon: '🛒', } ); }; // Обработчик клика по сердечку const handleFavoriteClick = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); if (isItemFavorite) { // Находим товар в избранном и удаляем по правильному ID const favoriteItem = favorites.find((item: any) => { // Проверяем по разным комбинациям идентификаторов if (offers[0]?.productId && item.productId === offers[0].productId) return true; if (offers[0]?.offerKey && item.offerKey === offers[0].offerKey) return true; if (item.article === article && item.brand === brand) return true; return false; }); if (favoriteItem) { removeFromFavorites(favoriteItem.id); } } else { // Добавляем в избранное const bestOffer = offers[0]; // Берем первое предложение как лучшее const numericPrice = bestOffer ? parsePrice(bestOffer.price) : 0; addToFavorites({ productId: bestOffer?.productId, offerKey: bestOffer?.offerKey, name: name, brand: brand, article: article, price: numericPrice, currency: bestOffer?.currency || 'RUB', image: image }); } }; if (isLoadingOffers) { return (
info

{brand}

{article}

{name}

Загрузка предложений...

); } if (!offers || offers.length === 0) { return (
info

{brand}

{article}

{name}
{image && (
{name} {partsIndexPowered && (
powered by Parts Index
)}
)}
{onLoadOffers ? ( ) : (

Предложений не найдено.

)}
); } return ( <>
info

{brand}

{article}

{name}
{image && (
{name} {partsIndexPowered && (
powered by Parts Index
)}
)}
Наличие
Доставка
Цена
{displayedOffers.map((offer, idx) => { const isLast = idx === displayedOffers.length - 1; return (
{offer.pcs}
{offer.days}
{offer.recommended && ( <>
Рекомендуем
)}
{offer.price}
handleQuantityInput(idx, e.target.value)} className="text-block-26 w-full text-center outline-none" aria-label="Количество" />
); })}
{hasMoreOffers || visibleOffersCount > INITIAL_OFFERS_LIMIT ? (
{ if (hasMoreOffers) { setVisibleOffersCount(prev => Math.min(prev + 10, offers.length)); } else { setVisibleOffersCount(INITIAL_OFFERS_LIMIT); } }} style={{ cursor: 'pointer' }} tabIndex={0} role="button" aria-label={hasMoreOffers ? `Еще ${offers.length - visibleOffersCount} предложений` : 'Скрыть предложения'} onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { if (hasMoreOffers) { setVisibleOffersCount(prev => Math.min(prev + 10, offers.length)); } else { setVisibleOffersCount(INITIAL_OFFERS_LIMIT); } } }} >
{hasMoreOffers ? `Еще ${offers.length - visibleOffersCount} предложений` : 'Скрыть'}
) : null}
); }; export default CoreProductCard;