/** * БЛОК ДЕТАЛЬНОГО КАТАЛОГА С РЕЦЕПТУРОЙ * * Выделен из create-suppliers-supply-page.tsx * Детальный просмотр товаров с настройкой рецептуры и панелью управления */ 'use client' import { useQuery } from '@apollo/client' import { Package, Building2, Sparkles, Zap, Star, Orbit, X } from 'lucide-react' import Image from 'next/image' import React, { useState } from 'react' import { Badge } from '@/components/ui/badge' import { DatePicker } from '@/components/ui/date-picker' import { Input } from '@/components/ui/input' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { GET_WB_WAREHOUSE_DATA } from '@/graphql/queries' import type { DetailedCatalogBlockProps, GoodsProduct, ProductRecipe, FulfillmentService, FulfillmentConsumable, SellerConsumable, } from '../types/supply-creation.types' export const DetailedCatalogBlock = React.memo(function DetailedCatalogBlock({ allSelectedProducts, productRecipes, fulfillmentServices, fulfillmentConsumables, sellerConsumables, deliveryDate, selectedFulfillment, allCounterparties, onQuantityChange, onRecipeChange, onDeliveryDateChange, onFulfillmentChange, onProductRemove, }: DetailedCatalogBlockProps) { const fulfillmentCenters = allCounterparties?.filter((partner) => partner.type === 'FULFILLMENT') || [] return (
{/* Панель управления */}
{/* ЗАГОЛОВОК УДАЛЕН ДЛЯ МИНИМАЛИЗМА */}
{/* Дата поставки */}
{ console.log('DatePicker onChange вызван:', date) onDeliveryDateChange(date) }} className="glass-input text-white text-sm h-9" />
{/* Фулфилмент-центр */}
{/* Каталог товаров с рецептурой - Новый стиль таблицы */}
{/* Строки товаров */} {allSelectedProducts.length === 0 ? (

Товары не добавлены

Выберите товары из каталога выше для настройки рецептуры

) : ( allSelectedProducts.map((product) => { const recipe = productRecipes[product.id] const selectedServicesIds = recipe?.selectedServices || [] const selectedFFConsumablesIds = recipe?.selectedFFConsumables || [] const selectedSellerConsumablesIds = recipe?.selectedSellerConsumables || [] return ( ) }) )}
) }) // Компонент строки товара в табличном стиле interface ProductTableRowProps { product: GoodsProduct & { selectedQuantity: number } recipe?: ProductRecipe fulfillmentServices: FulfillmentService[] fulfillmentConsumables: FulfillmentConsumable[] sellerConsumables: SellerConsumable[] selectedServicesIds: string[] selectedFFConsumablesIds: string[] selectedSellerConsumablesIds: string[] selectedFulfillment?: string onQuantityChange: (productId: string, quantity: number) => void onRecipeChange: (productId: string, recipe: ProductRecipe) => void onRemove: (productId: string) => void } function ProductTableRow({ product, recipe, selectedServicesIds, selectedFFConsumablesIds, selectedSellerConsumablesIds, fulfillmentServices, fulfillmentConsumables, sellerConsumables, selectedFulfillment, onQuantityChange, onRecipeChange, onRemove, }: ProductTableRowProps) { // Расчет стоимости услуг и расходников const servicesCost = selectedServicesIds.reduce((sum, serviceId) => { const service = fulfillmentServices.find(s => s.id === serviceId) return sum + (service ? service.price * product.selectedQuantity : 0) }, 0) const ffConsumablesCost = selectedFFConsumablesIds.reduce((sum, consumableId) => { const consumable = fulfillmentConsumables.find(c => c.id === consumableId) return sum + (consumable ? consumable.price * product.selectedQuantity : 0) }, 0) const sellerConsumablesCost = selectedSellerConsumablesIds.reduce((sum, consumableId) => { const consumable = sellerConsumables.find(c => c.id === consumableId) return sum + (consumable ? (consumable.pricePerUnit || 0) * product.selectedQuantity : 0) }, 0) const productCost = product.price * product.selectedQuantity const totalCost = productCost + servicesCost + ffConsumablesCost + sellerConsumablesCost return (
{/* КНОПКА УДАЛЕНИЯ */}
{/* ТОВАР (3 колонки) */}
Товар
{product.mainImage || (product.images && product.images[0]) ? ( {product.name} ) : (
)}
{product.name}
{product.article &&

Арт: {product.article}

}
{product.price.toLocaleString('ru-RU')} ₽/{product.unit || 'шт'}
{/* КОЛИЧЕСТВО (1 колонка) */}
Кол-во
{product.quantity !== undefined && (
0 ? 'bg-green-400' : 'bg-red-400'}`} /> 0 ? 'text-green-400' : 'text-red-400'}`}> {product.quantity > 0 ? product.quantity : 0}
)}
{ const inputValue = e.target.value const newQuantity = inputValue === '' ? 0 : Math.max(0, parseInt(inputValue) || 0) if (newQuantity > product.quantity) { onQuantityChange(product.id, product.quantity) return } onQuantityChange(product.id, newQuantity) }} className="glass-input w-14 h-7 text-xs text-center text-white placeholder:text-white/50" placeholder="0" />
{/* УСЛУГИ ФФ (2 колонки) */}
Услуги ФФ
{(() => { console.log('🎯 Услуги ФФ:', { fulfillmentServicesCount: fulfillmentServices.length, fulfillmentServices: fulfillmentServices, selectedFulfillment: selectedFulfillment }) return null })()} {fulfillmentServices.length > 0 ? ( fulfillmentServices.map((service) => { const isSelected = selectedServicesIds.includes(service.id) return ( ) }) ) : (
{!selectedFulfillment ? 'Выберите ФФ-центр' : 'Нет услуг'}
)}
{/* РАСХОДНИКИ ФФ (2 колонки) */}
Расходники ФФ
{fulfillmentConsumables.length > 0 ? ( fulfillmentConsumables.map((consumable) => { const isSelected = selectedFFConsumablesIds.includes(consumable.id) return ( ) }) ) : (
{!selectedFulfillment ? 'Выберите ФФ-центр' : 'Нет расходников'}
)}
{/* РАСХОДНИКИ СЕЛЛЕРА (2 колонки) */}
Расходники сел.
{sellerConsumables.length > 0 ? ( sellerConsumables.map((consumable) => { const isSelected = selectedSellerConsumablesIds.includes(consumable.id) return ( ) }) ) : (
Нет расходников
)}
{/* МП КАРТОЧКА (1 колонка) */}
МП
{ onRecipeChange(productId, { selectedServices: selectedServicesIds, selectedFFConsumables: selectedFFConsumablesIds, selectedSellerConsumables: selectedSellerConsumablesIds, selectedWBCard: cardId === 'none' ? undefined : cardId, }) }} selectedCardId={recipe?.selectedWBCard} />
{/* СТОИМОСТЬ (1 колонка) */}
Сумма
{totalCost.toLocaleString('ru-RU')} ₽
{totalCost > productCost && (
+{(totalCost - productCost).toLocaleString('ru-RU')} ₽
)}
) } // КОМПОНЕНТ ВЫБОРА КАРТОЧКИ МАРКЕТПЛЕЙСА interface MarketplaceCardSelectorProps { productId: string onCardSelect?: (productId: string, cardId: string) => void selectedCardId?: string } function MarketplaceCardSelector({ productId, onCardSelect, selectedCardId }: MarketplaceCardSelectorProps) { const { data, loading, error } = useQuery(GET_WB_WAREHOUSE_DATA, { fetchPolicy: 'cache-first', errorPolicy: 'all', }) console.log('📦 GET_WB_WAREHOUSE_DATA результат:', { loading, error: error?.message, dataExists: !!data, warehouseDataExists: !!data?.getWBWarehouseData, cacheExists: !!data?.getWBWarehouseData?.cache, rawData: data }) // Извлекаем карточки из кеша склада WB, как на странице склада const wbCards = (() => { try { console.log('🔍 Структура данных WB:', { hasData: !!data, hasWBData: !!data?.getWBWarehouseData, hasCache: !!data?.getWBWarehouseData?.cache, cache: data?.getWBWarehouseData?.cache, cacheData: data?.getWBWarehouseData?.cache?.data }) const cacheData = data?.getWBWarehouseData?.cache?.data if (!cacheData) { console.log('❌ Нет данных кеша WB') return [] } const parsedData = typeof cacheData === 'string' ? JSON.parse(cacheData) : cacheData const stocks = parsedData?.stocks || [] console.log('📦 Найдено карточек WB:', stocks.length) return stocks.map((stock: any) => ({ id: stock.nmId.toString(), nmId: stock.nmId, vendorCode: stock.vendorCode || '', title: stock.title || 'Без названия', brand: stock.brand || '', })) } catch (error) { console.error('Ошибка парсинга данных WB склада:', error) return [] } })() // Временная отладка console.warn('📊 MarketplaceCardSelector WB Warehouse:', { loading, error: error?.message, hasCache: !!data?.getWBWarehouseData?.cache, cardsCount: wbCards.length, firstCard: wbCards[0], }) return (
) }