"use client"; import React, { useState } 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 { useAuth } from "@/hooks/useAuth"; 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"; interface ConsumableSupplier { 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 ConsumableProduct { id: string; name: string; description?: string; price: number; category?: { name: string }; images: string[]; mainImage?: string; organization: { id: string; name: string; }; stock?: number; unit?: string; } interface SelectedConsumable { id: string; name: string; price: number; selectedQuantity: number; unit?: string; category?: string; supplierId: string; supplierName: string; } export function CreateConsumablesSupplyPage() { const router = useRouter(); const { user } = useAuth(); const { getSidebarMargin } = useSidebar(); const [selectedSupplier, setSelectedSupplier] = useState(null); const [selectedConsumables, setSelectedConsumables] = useState< SelectedConsumable[] >([]); const [searchQuery, setSearchQuery] = useState(""); const [productSearchQuery, setProductSearchQuery] = useState(""); const [deliveryDate, setDeliveryDate] = useState(""); const [selectedFulfillmentCenter, setSelectedFulfillmentCenter] = useState(null); const [selectedLogistics, setSelectedLogistics] = useState(null); 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: ConsumableSupplier) => org.type === "WHOLESALE"); // Фильтруем фулфилмент-центры const fulfillmentCenters = ( counterpartiesData?.myCounterparties || [] ).filter((org: ConsumableSupplier) => org.type === "FULFILLMENT"); // Фильтруем логистические компании const logisticsPartners = (counterpartiesData?.myCounterparties || []).filter( (org: ConsumableSupplier) => org.type === "LOGIST" ); // Фильтруем поставщиков по поисковому запросу const filteredSuppliers = consumableSuppliers.filter( (supplier: ConsumableSupplier) => 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: ConsumableProduct) => product.organization.id === selectedSupplier.id ) : []; 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: ConsumableProduct) => 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; } // Для селлеров требуется выбор фулфилмент-центра if (!selectedFulfillmentCenter) { toast.error("Выберите фулфилмент-центр для доставки"); return; } // Логистика опциональна - может выбрать селлер или оставить фулфилменту if (selectedLogistics && !selectedLogistics.id) { toast.error("Некорректно выбрана логистическая компания"); return; } // Дополнительные проверки if (!selectedFulfillmentCenter.id) { toast.error("ID фулфилмент-центра не найден"); return; } if (!selectedSupplier.id) { toast.error("ID поставщика не найден"); return; } if (selectedConsumables.length === 0) { toast.error("Не выбраны расходники"); return; } // Проверяем дату const deliveryDateObj = new Date(deliveryDate); if (isNaN(deliveryDateObj.getTime())) { toast.error("Некорректная дата поставки"); return; } setIsCreatingSupply(true); // 🔍 ОТЛАДКА: проверяем текущего пользователя console.log("👤 Текущий пользователь:", { userId: user?.id, phone: user?.phone, organizationId: user?.organization?.id, organizationType: user?.organization?.type, organizationName: user?.organization?.name || user?.organization?.fullName, }); console.log("🚀 Создаем поставку с данными:", { partnerId: selectedSupplier.id, deliveryDate: deliveryDate, fulfillmentCenterId: selectedFulfillmentCenter.id, logisticsPartnerId: selectedLogistics?.id, hasLogistics: !!selectedLogistics?.id, consumableType: "SELLER_CONSUMABLES", itemsCount: selectedConsumables.length, mutationInput: { partnerId: selectedSupplier.id, deliveryDate: deliveryDate, fulfillmentCenterId: selectedFulfillmentCenter.id, ...(selectedLogistics?.id ? { logisticsPartnerId: selectedLogistics.id } : {}), consumableType: "SELLER_CONSUMABLES", items: selectedConsumables.map((consumable) => ({ productId: consumable.id, quantity: consumable.selectedQuantity, })), }, }); try { const result = await createSupplyOrder({ variables: { input: { partnerId: selectedSupplier.id, deliveryDate: deliveryDate, fulfillmentCenterId: selectedFulfillmentCenter.id, // 🔄 ЛОГИСТИКА ОПЦИОНАЛЬНА: селлер может выбрать или оставить фулфилменту ...(selectedLogistics?.id ? { logisticsPartnerId: selectedLogistics.id } : {}), // 🏷️ КЛАССИФИКАЦИЯ согласно правилам (раздел 2.2) consumableType: "SELLER_CONSUMABLES", // Расходники селлеров 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); setSelectedFulfillmentCenter(null); setSelectedConsumables([]); setDeliveryDate(""); setProductSearchQuery(""); setSearchQuery(""); // Перенаправляем на страницу поставок селлера с открытой вкладкой "Расходники" router.push("/supplies?tab=consumables"); } else { toast.error( result.data?.createSupplyOrder?.message || "Ошибка при создании заказа поставки" ); } } catch (error) { console.error("Error creating consumables supply:", error); // Детальная диагностика ошибки if (error instanceof Error) { console.error("Error details:", { message: error.message, stack: error.stack, name: error.name, }); // Показываем конкретную ошибку пользователю toast.error(`Ошибка: ${error.message}`); } else { console.error("Unknown error:", 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: ConsumableSupplier, index) => ( 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: ConsumableProduct, 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 ? (

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

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

{selectedFulfillmentCenter && (

Доставка в:

{selectedFulfillmentCenter.name || selectedFulfillmentCenter.fullName}

)}
) : (
{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())}
); }