/**
* БЛОК ДЕТАЛЬНОГО КАТАЛОГА С РЕЦЕПТУРОЙ
*
* Выделен из 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.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 (
)
}