"use client" import React, { createContext, useContext, useState, useEffect, ReactNode, useMemo, useRef } from "react" // Добавляем useRef import { useToast } from "@/components/ui/use-toast" import type { CartItemCreate } from "@/lib/cart" // Объединяем импорты из cart-store import cartStore, { Cart, createEmptyCart } from "@/lib/cart-store" import { apiStatus } from "@/lib/api" // Глобальная переменная для отслеживания последней синхронизации let lastSyncTimestamp = 0 const SYNC_THROTTLE_MS = 5000 // Минимальное время между синхронизациями (5 секунд) // Интерфейс контекста корзины interface CartContextType { cart: Cart loading: boolean error: string | null itemCount: number addToCart: (item: CartItemCreate) => Promise updateCartItem: (id: number, quantity: number) => Promise removeFromCart: (id: number) => Promise clearCart: () => Promise synchronizeCart: () => Promise isAuthenticated: boolean } // Создание контекста const CartContext = createContext(undefined) // Удаляем дублирующийся импорт // Провайдер контекста export function CartProvider({ children }: { children: ReactNode }) { // Инициализируем пустой корзиной, чтобы серверный и первый клиентский рендер совпадали const [cart, setCart] = useState(createEmptyCart()) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [syncInProgress, setSyncInProgress] = useState(false) // Внутреннее состояние для отслеживания аутентификации const [isAuthenticated, setIsAuthenticated] = useState(apiStatus.isAuthenticated); const initialSyncDoneRef = useRef(false); // Флаг для отслеживания первичной синхронизации const { toast } = useToast() // Подписка на изменения корзины useEffect(() => { const unsubscribe = cartStore.subscribe(() => { setCart(cartStore.getState()) }) return () => unsubscribe() }, []) // После монтирования на клиенте, устанавливаем актуальное состояние из cartStore useEffect(() => { setCart(cartStore.getState()); }, []); // Следим за изменением глобального apiStatus.isAuthenticated useEffect(() => { // Обновляем внутреннее состояние только если оно действительно изменилось if (apiStatus.isAuthenticated !== isAuthenticated) { setIsAuthenticated(apiStatus.isAuthenticated); // Сбрасываем флаг синхронизации при изменении статуса (например, при логауте) if (!apiStatus.isAuthenticated) { initialSyncDoneRef.current = false; } } // Эта зависимость все еще может быть не идеальной, но лучше, чем ничего. // В идеале, статус аутентификации должен приходить из AuthContext. }, [apiStatus.isAuthenticated, isAuthenticated]); // Синхронизация корзины при изменении статуса аутентификации на true useEffect(() => { // Запускаем синхронизацию только если пользователь стал аутентифицированным // и первичная синхронизация для этой сессии еще не выполнялась. if (isAuthenticated && !initialSyncDoneRef.current) { const now = Date.now(); // Дополнительно проверяем троттлинг на всякий случай if (!syncInProgress && now - lastSyncTimestamp > SYNC_THROTTLE_MS) { console.log("Запуск первичной синхронизации корзины для аутентифицированного пользователя."); synchronizeCart(); initialSyncDoneRef.current = true; // Отмечаем, что первичная синхронизация запущена } } }, [isAuthenticated, syncInProgress]); // Зависим от внутреннего состояния isAuthenticated // Синхронизация локальной корзины с сервером с дроттлингом const synchronizeCart = async () => { try { // Если синхронизация уже идет, не запускаем новую if (syncInProgress) return setSyncInProgress(true) setLoading(true) // Фиксируем время последней синхронизации lastSyncTimestamp = Date.now() await cartStore.syncWithServer() } catch (err) { setError('Не удалось синхронизировать корзину') toast({ variant: 'destructive', title: 'Ошибка', description: 'Не удалось синхронизировать корзину', }) } finally { setLoading(false) setSyncInProgress(false) } } // Добавление товара в корзину const addToCart = async (item: CartItemCreate) => { try { setLoading(true) setError(null) const result = await cartStore.addToCart(item) if (result) { toast({ title: 'Товар добавлен', description: 'Товар успешно добавлен в корзину', }) return true } else { toast({ variant: 'destructive', title: 'Ошибка', description: 'Не удалось добавить товар в корзину', }) return false } } catch (err) { setError('Не удалось добавить товар в корзину') toast({ variant: 'destructive', title: 'Ошибка', description: 'Не удалось добавить товар в корзину', }) return false } finally { setLoading(false) } } // Обновление количества товара в корзине const updateCartItem = async (id: number, quantity: number) => { try { setLoading(true) setError(null) const result = await cartStore.updateCartItem(id, quantity) if (!result) { toast({ variant: 'destructive', title: 'Ошибка', description: 'Не удалось обновить товар в корзине', }) } return result } catch (err) { setError('Не удалось обновить товар в корзине') toast({ variant: 'destructive', title: 'Ошибка', description: 'Не удалось обновить товар в корзине', }) return false } finally { setLoading(false) } } // Удаление товара из корзины const removeFromCart = async (id: number) => { try { setLoading(true) setError(null) const result = await cartStore.removeFromCart(id) if (result) { toast({ title: 'Товар удален', description: 'Товар успешно удален из корзины', }) return true } else { toast({ variant: 'destructive', title: 'Ошибка', description: 'Не удалось удалить товар из корзины', }) return false } } catch (err) { setError('Не удалось удалить товар из корзины') toast({ variant: 'destructive', title: 'Ошибка', description: 'Не удалось удалить товар из корзины', }) return false } finally { setLoading(false) } } // Очистка корзины const clearCart = async () => { try { setLoading(true) setError(null) const result = await cartStore.clearCart() if (result) { toast({ title: 'Корзина очищена', description: 'Корзина успешно очищена', }) return true } else { toast({ variant: 'destructive', title: 'Ошибка', description: 'Не удалось очистить корзину', }) return false } } catch (err) { setError('Не удалось очистить корзину') toast({ variant: 'destructive', title: 'Ошибка', description: 'Не удалось очистить корзину', }) return false } finally { setLoading(false) } } // Вычисляем itemCount на основе состояния cart const itemCount = useMemo(() => { return cart.items.reduce((sum, item) => sum + item.quantity, 0); }, [cart.items]); const value = { cart, loading, error, addToCart, updateCartItem, removeFromCart, clearCart, synchronizeCart, itemCount, // Используем вычисленное значение isAuthenticated // Используем внутреннее состояние } return ( {children} ) } // Хук для использования контекста корзины export function useCart() { const context = useContext(CartContext) if (context === undefined) { throw new Error("useCart должен использоваться внутри CartProvider") } return context }