"use client"; import React, { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import { useQuery, useMutation } from "@apollo/client"; import { Sidebar } from "@/components/dashboard/sidebar"; import { useSidebar } from "@/hooks/useSidebar"; import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { ArrowLeft, Building2, MapPin, Phone, Mail, Star, Search, Package, Plus, Minus, ShoppingCart, Wrench, Box, } from "lucide-react"; import { GET_MY_COUNTERPARTIES, GET_ALL_PRODUCTS, GET_SUPPLY_ORDERS, GET_MY_SUPPLIES, } from "@/graphql/queries"; import { CREATE_SUPPLY_ORDER } from "@/graphql/mutations"; import { OrganizationAvatar } from "@/components/market/organization-avatar"; import { toast } from "sonner"; import Image from "next/image"; import { useAuth } from "@/hooks/useAuth"; interface FulfillmentConsumableSupplier { id: string; inn: string; name?: string; fullName?: string; type: "FULFILLMENT" | "SELLER" | "LOGIST" | "WHOLESALE"; address?: string; phones?: Array<{ value: string }>; emails?: Array<{ value: string }>; users?: Array<{ id: string; avatar?: string; managerName?: string }>; createdAt: string; } interface FulfillmentConsumableProduct { id: string; name: string; description?: string; price: number; type?: "PRODUCT" | "CONSUMABLE"; category?: { name: string }; images: string[]; mainImage?: string; organization: { id: string; name: string; }; stock?: number; unit?: string; } interface SelectedFulfillmentConsumable { id: string; name: string; price: number; selectedQuantity: number; unit?: string; category?: string; supplierId: string; supplierName: string; } export function CreateFulfillmentConsumablesSupplyPage() { const router = useRouter(); const { getSidebarMargin } = useSidebar(); const { user } = useAuth(); const [selectedSupplier, setSelectedSupplier] = useState(null); const [selectedLogistics, setSelectedLogistics] = useState(null); const [selectedConsumables, setSelectedConsumables] = useState< SelectedFulfillmentConsumable[] >([]); const [searchQuery, setSearchQuery] = useState(""); const [productSearchQuery, setProductSearchQuery] = useState(""); const [deliveryDate, setDeliveryDate] = useState(""); const [isCreatingSupply, setIsCreatingSupply] = useState(false); // Загружаем контрагентов-поставщиков расходников const { data: counterpartiesData, loading: counterpartiesLoading } = useQuery( GET_MY_COUNTERPARTIES ); // Загружаем товары для выбранного поставщика const { data: productsData, loading: productsLoading } = useQuery( GET_ALL_PRODUCTS, { skip: !selectedSupplier, variables: { search: productSearchQuery || null, category: null }, } ); // Мутация для создания заказа поставки расходников const [createSupplyOrder] = useMutation(CREATE_SUPPLY_ORDER); // Фильтруем только поставщиков расходников (поставщиков) const consumableSuppliers = ( counterpartiesData?.myCounterparties || [] ).filter((org: FulfillmentConsumableSupplier) => org.type === "WHOLESALE"); // Фильтруем только логистические компании const logisticsPartners = ( counterpartiesData?.myCounterparties || [] ).filter((org: FulfillmentConsumableSupplier) => org.type === "LOGIST"); // Фильтруем поставщиков по поисковому запросу const filteredSuppliers = consumableSuppliers.filter( (supplier: FulfillmentConsumableSupplier) => supplier.name?.toLowerCase().includes(searchQuery.toLowerCase()) || supplier.fullName?.toLowerCase().includes(searchQuery.toLowerCase()) || supplier.inn?.toLowerCase().includes(searchQuery.toLowerCase()) ); // Фильтруем товары по выбранному поставщику const supplierProducts = selectedSupplier ? (productsData?.allProducts || []).filter( (product: FulfillmentConsumableProduct) => product.organization.id === selectedSupplier.id ) : []; // Отладочное логирование React.useEffect(() => { console.log("🛒 FULFILLMENT CONSUMABLES DEBUG:", { selectedSupplier: selectedSupplier ? { id: selectedSupplier.id, name: selectedSupplier.name || selectedSupplier.fullName, type: selectedSupplier.type, } : null, productsLoading, allProductsCount: productsData?.allProducts?.length || 0, supplierProductsCount: supplierProducts.length, allProducts: productsData?.allProducts?.map((p) => ({ id: p.id, name: p.name, organizationId: p.organization.id, organizationName: p.organization.name, type: p.type || "NO_TYPE", })) || [], supplierProducts: supplierProducts.map((p) => ({ id: p.id, name: p.name, organizationId: p.organization.id, organizationName: p.organization.name, })), }); }, [selectedSupplier, productsData, productsLoading, supplierProducts]); const formatCurrency = (amount: number) => { return new Intl.NumberFormat("ru-RU", { style: "currency", currency: "RUB", minimumFractionDigits: 0, }).format(amount); }; const renderStars = (rating: number = 4.5) => { return Array.from({ length: 5 }, (_, i) => ( )); }; const updateConsumableQuantity = (productId: string, quantity: number) => { const product = supplierProducts.find( (p: FulfillmentConsumableProduct) => p.id === productId ); if (!product || !selectedSupplier) return; setSelectedConsumables((prev) => { const existing = prev.find((p) => p.id === productId); if (quantity === 0) { // Удаляем расходник если количество 0 return prev.filter((p) => p.id !== productId); } if (existing) { // Обновляем количество существующего расходника return prev.map((p) => p.id === productId ? { ...p, selectedQuantity: quantity } : p ); } else { // Добавляем новый расходник return [ ...prev, { id: product.id, name: product.name, price: product.price, selectedQuantity: quantity, unit: product.unit || "шт", category: product.category?.name || "Расходники", supplierId: selectedSupplier.id, supplierName: selectedSupplier.name || selectedSupplier.fullName || "Поставщик", }, ]; } }); }; const getSelectedQuantity = (productId: string): number => { const selected = selectedConsumables.find((p) => p.id === productId); return selected ? selected.selectedQuantity : 0; }; const getTotalAmount = () => { return selectedConsumables.reduce( (sum, consumable) => sum + consumable.price * consumable.selectedQuantity, 0 ); }; const getTotalItems = () => { return selectedConsumables.reduce( (sum, consumable) => sum + consumable.selectedQuantity, 0 ); }; const handleCreateSupply = async () => { if ( !selectedSupplier || selectedConsumables.length === 0 || !deliveryDate ) { toast.error("Заполните все обязательные поля"); return; } setIsCreatingSupply(true); try { const result = await createSupplyOrder({ variables: { input: { partnerId: selectedSupplier.id, deliveryDate: deliveryDate, // Для фулфилмента указываем себя как получателя (поставка на свой склад) fulfillmentCenterId: user?.organization?.id, logisticsPartnerId: selectedLogistics?.id, items: selectedConsumables.map((consumable) => ({ productId: consumable.id, quantity: consumable.selectedQuantity, })), }, }, refetchQueries: [ { query: GET_SUPPLY_ORDERS }, // Обновляем заказы поставок { query: GET_MY_SUPPLIES }, // Обновляем расходники фулфилмента ], }); if (result.data?.createSupplyOrder?.success) { toast.success("Заказ поставки расходников фулфилмента создан успешно!"); // Очищаем форму setSelectedSupplier(null); setSelectedConsumables([]); setDeliveryDate(""); setProductSearchQuery(""); setSearchQuery(""); // Перенаправляем на страницу поставок фулфилмента с активной вкладкой "Расходники фулфилмента" router.push("/fulfillment-supplies?tab=detailed-supplies"); } else { toast.error( result.data?.createSupplyOrder?.message || "Ошибка при создании заказа поставки" ); } } catch (error) { console.error("Error creating fulfillment consumables supply:", error); toast.error("Ошибка при создании поставки расходников фулфилмента"); } finally { setIsCreatingSupply(false); } }; return (
{/* Заголовок */}

Создание поставки расходников фулфилмента

Выберите поставщика и добавьте расходники в заказ для вашего фулфилмент-центра

{/* Основной контент с двумя блоками */}
{/* Левая колонка - Поставщики и Расходники */}
{/* Блок "Поставщики" */}

Поставщики расходников

setSearchQuery(e.target.value)} className="bg-white/20 backdrop-blur border-white/30 text-white placeholder-white/50 pl-10 h-8 text-sm rounded-full shadow-inner focus:ring-2 focus:ring-purple-400/50 focus:border-purple-400/50 transition-all duration-300" />
{selectedSupplier && ( )}
{counterpartiesLoading ? (

Загружаем поставщиков...

) : filteredSuppliers.length === 0 ? (

{searchQuery ? "Поставщики не найдены" : "Добавьте поставщиков"}

) : (
{filteredSuppliers .slice(0, 7) .map( (supplier: FulfillmentConsumableSupplier, index) => ( { console.log("🔄 ВЫБРАН ПОСТАВЩИК:", { id: supplier.id, name: supplier.name || supplier.fullName, type: supplier.type, }); setSelectedSupplier(supplier); }} >
({ id: user.id, avatar: user.avatar, }) ), }} size="sm" /> {selectedSupplier?.id === supplier.id && (
)}

{( supplier.name || supplier.fullName || "Поставщик" ).slice(0, 10)}

4.5
{/* Hover эффект */}
) )} {filteredSuppliers.length > 7 && (
+{filteredSuppliers.length - 7}
ещё
)}
)}
{/* Блок "Расходники" */}

Расходники для фулфилмента {selectedSupplier && ( - {selectedSupplier.name || selectedSupplier.fullName} )}

{selectedSupplier && (
setProductSearchQuery(e.target.value)} className="bg-white/10 border-white/20 text-white placeholder-white/40 pl-7 h-8 text-sm" />
)}
{!selectedSupplier ? (

Выберите поставщика для просмотра расходников

) : productsLoading ? (

Загрузка...

) : supplierProducts.length === 0 ? (

Нет доступных расходников

) : (
{supplierProducts.map( (product: FulfillmentConsumableProduct, index) => { const selectedQuantity = getSelectedQuantity( product.id ); return ( 0 ? "ring-2 ring-green-400/50 bg-gradient-to-br from-green-500/20 via-green-400/10 to-green-500/20" : "hover:from-white/20 hover:via-white/10 hover:to-white/20 hover:border-white/40" }`} style={{ animationDelay: `${index * 50}ms`, minHeight: "200px", width: "100%", }} >
{/* Изображение товара */}
{product.images && product.images.length > 0 && product.images[0] ? ( {product.name} ) : product.mainImage ? ( {product.name} ) : (
)} {selectedQuantity > 0 && (
{selectedQuantity > 999 ? "999+" : selectedQuantity}
)}
{/* Информация о товаре */}

{product.name}

{product.category && ( {product.category.name.slice(0, 10)} )}
{formatCurrency(product.price)} {product.stock && ( {product.stock} )}
{/* Управление количеством */}
{ let inputValue = e.target.value; // Удаляем все нецифровые символы inputValue = inputValue.replace( /[^0-9]/g, "" ); // Удаляем ведущие нули inputValue = inputValue.replace( /^0+/, "" ); // Если строка пустая после удаления нулей, устанавливаем 0 const numericValue = inputValue === "" ? 0 : parseInt(inputValue); // Ограничиваем значение максимумом 99999 const clampedValue = Math.min( numericValue, 99999 ); updateConsumableQuantity( product.id, clampedValue ); }} onBlur={(e) => { // При потере фокуса, если поле пустое, устанавливаем 0 if (e.target.value === "") { updateConsumableQuantity( product.id, 0 ); } }} className="w-16 h-7 text-center text-sm bg-white/10 border-white/20 text-white rounded px-1 focus:ring-2 focus:ring-purple-400/50 focus:border-purple-400/50" placeholder="0" />
{selectedQuantity > 0 && (
{formatCurrency( product.price * selectedQuantity )}
)}
{/* Hover эффект */}
); } )}
)}
{/* Правая колонка - Корзина */}

Корзина ({getTotalItems()} шт)

{selectedConsumables.length === 0 ? (

Корзина пуста

Добавьте расходники для создания поставки

) : (
{selectedConsumables.map((consumable) => (

{consumable.name}

{formatCurrency(consumable.price)} ×{" "} {consumable.selectedQuantity}

{formatCurrency( consumable.price * consumable.selectedQuantity )}
))}
)}
setDeliveryDate(e.target.value)} className="bg-white/10 border-white/20 text-white h-8 text-sm" min={new Date().toISOString().split("T")[0]} required />
{/* Выбор логистики */}
Итого: {formatCurrency(getTotalAmount())}
); }