import React, { useState, useEffect, useRef } from "react"; import Link from "next/link"; import { useCart } from "@/contexts/CartContext"; import { useMutation, useQuery } from "@apollo/client"; import { CREATE_ORDER, CREATE_PAYMENT, GET_CLIENT_ME, GET_CLIENT_DELIVERY_ADDRESSES } from "@/lib/graphql"; import toast from "react-hot-toast"; interface CartSummaryProps { step: number; setStep: (step: number) => void; } const CartSummary: React.FC = ({ step, setStep }) => { const { state, updateDelivery, updateOrderComment, clearCart } = useCart(); const { summary, delivery, items, orderComment } = state; const legalEntityDropdownRef = useRef(null); const addressDropdownRef = useRef(null); const paymentDropdownRef = useRef(null); const [consent, setConsent] = useState(false); const [error, setError] = useState(""); const [isProcessing, setIsProcessing] = useState(false); const [showAuthWarning, setShowAuthWarning] = useState(false); // Новые состояния для первого шага const [selectedLegalEntity, setSelectedLegalEntity] = useState(""); const [selectedLegalEntityId, setSelectedLegalEntityId] = useState(""); const [isIndividual, setIsIndividual] = useState(true); // true = физ лицо, false = юр лицо const [showLegalEntityDropdown, setShowLegalEntityDropdown] = useState(false); const [selectedDeliveryAddress, setSelectedDeliveryAddress] = useState(""); const [showAddressDropdown, setShowAddressDropdown] = useState(false); const [recipientName, setRecipientName] = useState(""); const [recipientPhone, setRecipientPhone] = useState(""); // Новые состояния для способа оплаты const [paymentMethod, setPaymentMethod] = useState("yookassa"); const [showPaymentDropdown, setShowPaymentDropdown] = useState(false); // Упрощенный тип доставки - только курьер или самовывоз // const [deliveryType, setDeliveryType] = useState<'courier' | 'pickup'>('courier'); const [createOrder] = useMutation(CREATE_ORDER); const [createPayment] = useMutation(CREATE_PAYMENT); // Убираем useMutation для GET_DELIVERY_OFFERS // Получаем данные клиента const { data: clientData, loading: clientLoading } = useQuery(GET_CLIENT_ME); const { data: addressesData, loading: addressesLoading } = useQuery(GET_CLIENT_DELIVERY_ADDRESSES); // Получаем пользователя из localStorage для проверки авторизации const [userData, setUserData] = useState(null); useEffect(() => { if (typeof window !== 'undefined') { const storedUserData = localStorage.getItem('userData'); if (storedUserData) { setUserData(JSON.parse(storedUserData)); } } }, []); // Загрузка состояния компонента из localStorage useEffect(() => { if (typeof window !== 'undefined') { const savedCartSummaryState = localStorage.getItem('cartSummaryState'); if (savedCartSummaryState) { try { const state = JSON.parse(savedCartSummaryState); setStep(state.step || 1); setSelectedLegalEntity(state.selectedLegalEntity || ''); setSelectedLegalEntityId(state.selectedLegalEntityId || ''); setIsIndividual(state.isIndividual ?? true); setSelectedDeliveryAddress(state.selectedDeliveryAddress || ''); setRecipientName(state.recipientName || ''); setRecipientPhone(state.recipientPhone || ''); setPaymentMethod(state.paymentMethod || 'yookassa'); setConsent(state.consent || false); } catch (error) { console.error('Ошибка загрузки состояния CartSummary:', error); } } } }, []); // Сохранение состояния компонента в localStorage useEffect(() => { if (typeof window !== 'undefined') { const stateToSave = { step, selectedLegalEntity, selectedLegalEntityId, isIndividual, selectedDeliveryAddress, recipientName, recipientPhone, paymentMethod, consent }; localStorage.setItem('cartSummaryState', JSON.stringify(stateToSave)); } }, [step, selectedLegalEntity, selectedLegalEntityId, isIndividual, selectedDeliveryAddress, recipientName, recipientPhone, paymentMethod, consent]); // Инициализация данных получателя useEffect(() => { if (clientData?.clientMe && !recipientName && !recipientPhone) { setRecipientName(clientData.clientMe.name || ''); setRecipientPhone(clientData.clientMe.phone || ''); } }, [clientData, recipientName, recipientPhone]); // Закрытие dropdown при клике вне их useEffect(() => { const handleClickOutside = (event: MouseEvent) => { // Проверяем клик вне дропдауна типа лица if (legalEntityDropdownRef.current && !legalEntityDropdownRef.current.contains(event.target as Node)) { setShowLegalEntityDropdown(false); } // Проверяем клик вне дропдауна адресов if (addressDropdownRef.current && !addressDropdownRef.current.contains(event.target as Node)) { setShowAddressDropdown(false); } // Проверяем клик вне дропдауна способов оплаты if (paymentDropdownRef.current && !paymentDropdownRef.current.contains(event.target as Node)) { setShowPaymentDropdown(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, []); const handleProceedToStep2 = () => { if (!recipientName.trim()) { toast.error('Пожалуйста, введите имя получателя'); return; } if (!recipientPhone.trim()) { toast.error('Пожалуйста, введите телефон получателя'); return; } if (!selectedDeliveryAddress.trim()) { toast.error('Пожалуйста, выберите адрес доставки'); return; } updateDelivery({ address: selectedDeliveryAddress, cost: 0, date: 'Включена в стоимость товаров', time: 'Способ доставки указан в адресе' }); setStep(2); }; const handleBackToStep1 = () => { setStep(1); }; const handleSubmit = async () => { if (!recipientName.trim() || !recipientPhone.trim() || !consent) { setError("Пожалуйста, заполните данные получателя и согласитесь с правилами."); return; } // Проверяем авторизацию const userData = typeof window !== 'undefined' ? localStorage.getItem('userData') : null; if (!userData) { setError("Для оформления заказа необходимо войти в систему."); setShowAuthWarning(true); return; } setIsProcessing(true); setError(""); setShowAuthWarning(false); try { const user = JSON.parse(userData); const selectedItems = items.filter(item => item.selected); // Создаем заказ с clientId для авторизованных пользователей const orderResult = await createOrder({ variables: { input: { clientId: user.id, clientEmail: user.email || '', clientPhone: recipientPhone, clientName: recipientName, deliveryAddress: selectedDeliveryAddress || delivery.address, legalEntityId: !isIndividual ? selectedLegalEntityId : null, paymentMethod: paymentMethod, comment: orderComment || `Адрес доставки: ${selectedDeliveryAddress}. ${!isIndividual && selectedLegalEntity ? `Юридическое лицо: ${selectedLegalEntity}.` : 'Физическое лицо.'} Способ оплаты: ${getPaymentMethodName(paymentMethod)}. Доставка: ${selectedDeliveryAddress}.`, items: selectedItems.map(item => ({ productId: item.productId, externalId: item.offerKey, name: item.name, article: item.article || '', brand: item.brand || '', price: item.price, quantity: item.quantity })) } } }); const order = orderResult.data?.createOrder; if (!order) { throw new Error('Не удалось создать заказ'); } // Обрабатываем разные способы оплаты if (paymentMethod === 'balance') { // Для оплаты с баланса - заказ уже оплачен, переходим на страницу успеха clearCart(); // Очищаем сохраненное состояние оформления заказа if (typeof window !== 'undefined') { localStorage.removeItem('cartSummaryState'); } window.location.href = `/payment/success?orderId=${order.id}&orderNumber=${order.orderNumber}&paymentMethod=balance`; } else { // Для ЮКассы - создаем платеж и переходим на оплату const paymentResult = await createPayment({ variables: { input: { orderId: order.id, returnUrl: `${window.location.origin}/payment/success?orderId=${order.id}&orderNumber=${order.orderNumber}`, description: `Оплата заказа №${order.orderNumber}` } } }); const payment = paymentResult.data?.createPayment; if (!payment?.confirmationUrl) { throw new Error('Не удалось создать платеж'); } // Очищаем корзину и переходим на оплату clearCart(); // Очищаем сохраненное состояние оформления заказа if (typeof window !== 'undefined') { localStorage.removeItem('cartSummaryState'); } window.location.href = payment.confirmationUrl; } } catch (error) { console.error('Ошибка при создании заказа:', error); setError(error instanceof Error ? error.message : 'Произошла ошибка при оформлении заказа'); } finally { setIsProcessing(false); } }; // Функция для форматирования цены const formatPrice = (price: number) => { return `${price.toLocaleString('ru-RU')} ₽`; }; // Функция для получения названия способа оплаты const getPaymentMethodName = (method: string) => { switch (method) { case 'yookassa': return 'ЮКасса (банковские карты)'; case 'balance': return 'Оплата с баланса'; default: return 'ЮКасса (банковские карты)'; } }; if (step === 1) { // Первый шаг - настройка доставки return (
{/* Тип клиента - показываем всегда */}
Тип клиента
setShowLegalEntityDropdown(!showLegalEntityDropdown)} style={{ cursor: 'pointer', justifyContent: 'space-between', alignItems: 'center' }} >
{isIndividual ? 'Физическое лицо' : selectedLegalEntity || 'Выберите юридическое лицо'}
{/* Dropdown список типов клиента */} {showLegalEntityDropdown && (
{/* Опция физического лица */}
{ setIsIndividual(true); setSelectedLegalEntity(''); setSelectedLegalEntityId(''); setPaymentMethod('yookassa'); // Для физ лица только ЮКасса setShowLegalEntityDropdown(false); }} style={{ padding: '12px 16px', cursor: 'pointer', borderBottom: '1px solid #f0f0f0', backgroundColor: isIndividual ? '#f8f9fa' : 'white', fontSize: '14px', }} onMouseEnter={(e) => { if (!isIndividual) { e.currentTarget.style.backgroundColor = '#f8f9fa'; } }} onMouseLeave={(e) => { if (!isIndividual) { e.currentTarget.style.backgroundColor = 'white'; } }} > Физическое лицо
{/* Юридические лица (если есть) */} {clientData?.clientMe?.legalEntities && clientData.clientMe.legalEntities.length > 0 && clientData.clientMe.legalEntities.map((entity: any, index: number) => (
{ setIsIndividual(false); setSelectedLegalEntity(entity.shortName || entity.fullName); setSelectedLegalEntityId(entity.id); setPaymentMethod('yookassa'); // По умолчанию ЮКасса для юр лица setShowLegalEntityDropdown(false); }} style={{ padding: '12px 16px', cursor: 'pointer', borderBottom: index < clientData.clientMe.legalEntities.length - 1 ? '1px solid #f0f0f0' : 'none', backgroundColor: !isIndividual && (entity.shortName || entity.fullName) === selectedLegalEntity ? '#f8f9fa' : 'white', fontSize: '14px' }} onMouseEnter={(e) => { if (isIndividual || (entity.shortName || entity.fullName) !== selectedLegalEntity) { e.currentTarget.style.backgroundColor = '#f8f9fa'; } }} onMouseLeave={(e) => { if (isIndividual || (entity.shortName || entity.fullName) !== selectedLegalEntity) { e.currentTarget.style.backgroundColor = 'white'; } }} > {entity.shortName || entity.fullName}
)) }
)}
{/* Адрес доставки */}
Адрес доставки
setShowAddressDropdown(!showAddressDropdown)} style={{ cursor: 'pointer', justifyContent: 'space-between', alignItems: 'center' }} >
{selectedDeliveryAddress || 'Выберите адрес доставки'}
{/* Dropdown список адресов */} {showAddressDropdown && (
{/* Кнопка добавления нового адреса */}
{ // Переход в личный кабинет на страницу адресов window.location.href = '/profile-addresses'; setShowAddressDropdown(false); }} style={{ padding: '12px 16px', cursor: 'pointer', backgroundColor: '#f8f9fa', fontSize: '14px', fontWeight: 500, color: '#007bff', borderBottom: '1px solid #dee2e6' }} onMouseEnter={(e) => { e.currentTarget.style.backgroundColor = '#e3f2fd'; }} onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = '#f8f9fa'; }} > + Добавить новый адрес
{/* Существующие адреса */} {addressesData?.clientMe?.deliveryAddresses?.map((address: any, index: number) => (
{ setSelectedDeliveryAddress(address.address); setShowAddressDropdown(false); // Обновляем адрес в контексте корзины updateDelivery({ address: address.address }); }} style={{ padding: '12px 16px', cursor: 'pointer', borderBottom: index < (addressesData?.clientMe?.deliveryAddresses?.length || 0) - 1 ? '1px solid #f0f0f0' : 'none', backgroundColor: address.address === selectedDeliveryAddress ? '#f8f9fa' : 'white', fontSize: '14px' }} onMouseEnter={(e) => { if (address.address !== selectedDeliveryAddress) { e.currentTarget.style.backgroundColor = '#f8f9fa'; } }} onMouseLeave={(e) => { if (address.address !== selectedDeliveryAddress) { e.currentTarget.style.backgroundColor = 'white'; } }} >
{address.name || address.deliveryType}
{address.address}
)) || (
Нет сохранённых адресов
)}
)} {/* Показываем выбранный адрес */} {selectedDeliveryAddress && (
{selectedDeliveryAddress}
)}
{/* Способ оплаты */}
Способ оплаты
setShowPaymentDropdown(!showPaymentDropdown)} style={{ cursor: 'pointer', justifyContent: 'space-between', alignItems: 'center' }} >
{getPaymentMethodName(paymentMethod)}
{/* Dropdown список способов оплаты */} {showPaymentDropdown && (
{/* ЮКасса - доступна всегда */}
{ setPaymentMethod('yookassa'); setShowPaymentDropdown(false); }} style={{ padding: '12px 16px', cursor: 'pointer', borderBottom: '1px solid #f0f0f0', backgroundColor: paymentMethod === 'yookassa' ? '#f8f9fa' : 'white', fontSize: '14px', fontWeight: paymentMethod === 'yookassa' ? 500 : 400, color: '#222' }} onMouseEnter={(e) => { if (paymentMethod !== 'yookassa') { e.currentTarget.style.backgroundColor = '#f8f9fa'; } }} onMouseLeave={(e) => { if (paymentMethod !== 'yookassa') { e.currentTarget.style.backgroundColor = 'white'; } }} > ЮКасса (банковские карты)
{/* Дополнительные способы оплаты для юридических лиц */} {!isIndividual && ( <>
{ setPaymentMethod('balance'); setShowPaymentDropdown(false); }} style={{ padding: '12px 16px', cursor: 'pointer', borderBottom: '1px solid #f0f0f0', backgroundColor: paymentMethod === 'balance' ? '#f8f9fa' : 'white', fontSize: '14px' }} onMouseEnter={(e) => { if (paymentMethod !== 'balance') { e.currentTarget.style.backgroundColor = '#f8f9fa'; } }} onMouseLeave={(e) => { if (paymentMethod !== 'balance') { e.currentTarget.style.backgroundColor = 'white'; } }} >
Оплата с баланса
{(() => { if (clientLoading) { return ( Загрузка... ); } if (!clientData?.clientMe) { return ( Ошибка загрузки данных ); } const activeContracts = clientData?.clientMe?.contracts?.filter((contract: any) => contract.isActive) || []; const defaultContract = activeContracts.find((contract: any) => contract.isDefault) || activeContracts[0]; if (!defaultContract) { return ( Активный договор не найден ); } const balance = defaultContract.balance || 0; const creditLimit = defaultContract.creditLimit || 0; const totalAvailable = balance + creditLimit; return ( Доступно: {formatPrice(totalAvailable)} ); })()}
)}
)}
{/* Сводка заказа */}
Товары, {summary.totalItems} шт.
{formatPrice(summary.totalPrice)}
{summary.totalDiscount > 0 && (
Моя скидка
-{formatPrice(summary.totalDiscount)}
)}
Доставка
Включена в стоимость товаров
Итого

{formatPrice(summary.totalPrice - summary.totalDiscount)}

{error &&
{error}
}
setConsent((v) => !v)}>
{consent && ( )}
Соглашаюсь с правилами пользования торговой площадкой и возврата
); } // Второй шаг - подтверждение и оплата return (
{/* Адрес доставки */}
Адрес доставки

Доставка

Изменить
{selectedDeliveryAddress || delivery.address}
{/* Получатель */}

Получатель

setRecipientName(e.target.value)} style={{ width: '100%', padding: '8px 12px', border: 'none', outline: 'none', boxShadow: 'none', }} />
setRecipientPhone(e.target.value)} style={{ width: '100%', padding: '8px 12px', border: 'none', outline: 'none', boxShadow: 'none', }} />
{/* Тип клиента и способ оплаты */}
Тип клиента и оплата

{isIndividual ? 'Физическое лицо' : selectedLegalEntity}

Изменить
Способ оплаты: {getPaymentMethodName(paymentMethod)}
{paymentMethod === 'balance' && !isIndividual && (
{(() => { const activeContracts = clientData?.clientMe?.contracts?.filter((contract: any) => contract.isActive) || []; const defaultContract = activeContracts.find((contract: any) => contract.isDefault) || activeContracts[0]; if (!defaultContract) { return ( Активный договор не найден ); } const balance = defaultContract.balance || 0; const creditLimit = defaultContract.creditLimit || 0; const totalAvailable = balance + creditLimit; return ( Доступно: {formatPrice(totalAvailable)} ); })()}
)}
{/* Комментарий к заказу */}
Комментарий к заказу