"use client" import { useState } from 'react' import { useMutation } from '@apollo/client' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Trash2, AlertTriangle, Package, Store, Minus, Plus } from 'lucide-react' import { OrganizationAvatar } from '@/components/market/organization-avatar' import { Input } from '@/components/ui/input' import Image from 'next/image' import { UPDATE_CART_ITEM, REMOVE_FROM_CART, CLEAR_CART } from '@/graphql/mutations' import { GET_MY_CART } from '@/graphql/queries' import { toast } from 'sonner' interface CartItem { id: string quantity: number totalPrice: number isAvailable: boolean availableQuantity: number product: { id: string name: string article: string price: number quantity: number images: string[] mainImage?: string organization: { id: string name?: string fullName?: string inn: string } } } interface Cart { id: string items: CartItem[] totalPrice: number totalItems: number } interface CartItemsProps { cart: Cart } export function CartItems({ cart }: CartItemsProps) { const [loadingItems, setLoadingItems] = useState>(new Set()) const [quantities, setQuantities] = useState>({}) const [updateCartItem] = useMutation(UPDATE_CART_ITEM, { refetchQueries: [{ query: GET_MY_CART }], onCompleted: (data) => { if (data.updateCartItem.success) { toast.success(data.updateCartItem.message) } else { toast.error(data.updateCartItem.message) } }, onError: (error) => { toast.error('Ошибка при обновлении заявки') console.error('Error updating cart item:', error) } }) const [removeFromCart] = useMutation(REMOVE_FROM_CART, { refetchQueries: [{ query: GET_MY_CART }], onCompleted: (data) => { if (data.removeFromCart.success) { toast.success(data.removeFromCart.message) } else { toast.error(data.removeFromCart.message) } }, onError: (error) => { toast.error('Ошибка при удалении заявки') console.error('Error removing from cart:', error) } }) const [clearCart] = useMutation(CLEAR_CART, { refetchQueries: [{ query: GET_MY_CART }], onCompleted: () => { toast.success('Заявки очищены') }, onError: (error) => { toast.error('Ошибка при очистке заявок') console.error('Error clearing cart:', error) } }) const getQuantity = (productId: string, defaultQuantity: number) => quantities[productId] || defaultQuantity const setQuantity = (productId: string, quantity: number) => { setQuantities(prev => ({ ...prev, [productId]: quantity })) } const updateQuantity = async (productId: string, newQuantity: number) => { if (newQuantity <= 0) return setLoadingItems(prev => new Set(prev).add(productId)) try { await updateCartItem({ variables: { productId, quantity: newQuantity } }) } finally { setLoadingItems(prev => { const newSet = new Set(prev) newSet.delete(productId) return newSet }) } } const removeItem = async (productId: string) => { setLoadingItems(prev => new Set(prev).add(productId)) try { await removeFromCart({ variables: { productId } }) } finally { setLoadingItems(prev => { const newSet = new Set(prev) newSet.delete(productId) return newSet }) } } const handleClearCart = async () => { if (confirm('Вы уверены, что хотите очистить все заявки?')) { await clearCart() } } const formatPrice = (price: number) => { return new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB' }).format(price) } const unavailableItems = cart.items.filter(item => !item.isAvailable) // Группировка товаров по поставщикам const groupedItems = cart.items.reduce((groups, item) => { const orgId = item.product.organization.id if (!groups[orgId]) { groups[orgId] = { organization: item.product.organization, items: [], totalPrice: 0, totalItems: 0 } } groups[orgId].items.push(item) groups[orgId].totalPrice += item.totalPrice groups[orgId].totalItems += item.quantity return groups }, {} as Record) const supplierGroups = Object.values(groupedItems) return (
{/* Заголовок с кнопкой очистки */}

Заявки на товары

{cart.items.length > 0 && ( )}
{/* Предупреждение о недоступных товарах */} {unavailableItems.length > 0 && (
{unavailableItems.length} заявок недоступно для оформления
)} {/* Группы поставщиков */}
{supplierGroups.map((group) => (
{/* Заголовок поставщика */}

{group.organization.name || group.organization.fullName || `ИНН ${group.organization.inn}`}

{group.totalItems} товаров {formatPrice(group.totalPrice)}
{group.items.length} заявок
{/* Товары этого поставщика */}
{group.items.map((item) => { const isLoading = loadingItems.has(item.product.id) const mainImage = item.product.images?.[0] || item.product.mainImage return (
{/* Информация о поставщике в карточке товара */}
Поставщик: {item.product.organization.name || item.product.organization.fullName || `ИНН ${item.product.organization.inn}`}
{/* Основное содержимое карточки */}
{/* Изображение товара */}
{mainImage ? ( {item.product.name} ) : (
)}
{/* Информация о товаре */}
{/* Название и артикул */}

{item.product.name}

Арт: {item.product.article}

{/* Статус и наличие */}
{item.availableQuantity} шт. {item.isAvailable ? ( В наличии ) : ( Недоступно )}
{/* Управление количеством */}
{ const value = e.target.value // Разрешаем только цифры и пустое поле if (value === '' || /^\d+$/.test(value)) { const numValue = value === '' ? 0 : parseInt(value) // Временно сохраняем даже если 0 или больше лимита для удобства ввода if (value === '' || (numValue >= 0 && numValue <= 99999)) { setQuantity(item.product.id, numValue || 1) } } }} onFocus={(e) => { // При фокусе выделяем весь текст для удобного редактирования e.target.select() }} onBlur={(e) => { // При потере фокуса проверяем и корректируем значение, отправляем запрос let value = parseInt(e.target.value) if (isNaN(value) || value < 1) { value = 1 } else if (value > item.availableQuantity) { value = item.availableQuantity } setQuantity(item.product.id, value) updateQuantity(item.product.id, value) }} onKeyDown={(e) => { // Enter для быстрого обновления if (e.key === 'Enter') { let value = parseInt(e.currentTarget.value) if (isNaN(value) || value < 1) { value = 1 } else if (value > item.availableQuantity) { value = item.availableQuantity } setQuantity(item.product.id, value) updateQuantity(item.product.id, value) e.currentTarget.blur() } }} disabled={isLoading || !item.isAvailable} className="w-16 h-7 text-xs text-center glass-input text-white border-white/20 bg-white/5" placeholder="1" />
до {item.availableQuantity}
{/* Правая часть: цена и кнопка удаления */}
{/* Цена */}
{formatPrice(item.totalPrice)}
{formatPrice(item.product.price)} за шт.
{/* Кнопка удаления */}
) })}
))}
) }