import React, { useState, useEffect } from 'react'; import SidebarMenu from './SidebarMenu'; import { Box, CircularProgress, Typography } from '@mui/material'; import axios from 'axios'; const SidebarMenuWrapper = ({ isDarkMode, setIsDarkMode, onMenuSelect }) => { const [menuData, setMenuData] = useState(null); const [lastModified, setLastModified] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [editingItem, setEditingItem] = useState(null); const [editModalOpen, setEditModalOpen] = useState(false); const [backgroundLoading, setBackgroundLoading] = useState(false); const [refreshTrigger, setRefreshTrigger] = useState(0); const forceRefreshMenu = () => { setRefreshTrigger(prev => prev + 1); localStorage.removeItem('menuCache'); // Очищаем кэш }; // Загружаем меню из localStorage при инициализации useEffect(() => { const loadCachedMenu = () => { try { const cached = localStorage.getItem('menuCache'); if (cached) { const { data, timestamp } = JSON.parse(cached); setMenuData(data); setLastModified(timestamp); } } catch (e) { console.warn('Failed to load menu from cache', e); } }; loadCachedMenu(); }, []); // Основная загрузка меню useEffect(() => { const fetchMenuData = async () => { try { setLoading(true); const headers = lastModified ? { 'If-Modified-Since': lastModified } : {}; const response = await axios.get(`${import.meta.env.VITE_BACK_URL}/api/menu/full`, { headers, validateStatus: status => status === 200 || status === 304 }); if (response.status === 200) { const newLastModified = response.headers['last-modified']; setMenuData(response.data); setLastModified(newLastModified); // Сохраняем в кэш localStorage.setItem('menuCache', JSON.stringify({ data: response.data, timestamp: newLastModified })); } } catch (err) { console.error('Error fetching menu data:', err); setError(err.message || 'Failed to fetch menu data'); } finally { setLoading(false); } }; fetchMenuData(); }, [refreshTrigger]); // Фоновая проверка обновлений useEffect(() => { if (!lastModified) return; const checkForUpdates = async () => { try { setBackgroundLoading(true); const response = await axios.get(`${import.meta.env.VITE_BACK_URL}/api/menu/check-updates`, { headers: { 'If-Modified-Since': lastModified } }); if (response.data.hasUpdates) { // Если есть обновления, загружаем их в фоне const updateResponse = await axios.get(`${import.meta.env.VITE_BACK_URL}/api/menu/full`); setMenuData(updateResponse.data); setLastModified(updateResponse.headers['last-modified']); localStorage.setItem('menuCache', JSON.stringify({ data: updateResponse.data, timestamp: updateResponse.headers['last-modified'] })); } } catch (err) { console.warn('Background update check failed', err); } finally { setBackgroundLoading(false); } }; // Проверяем обновления каждые 5 минут const interval = setInterval(checkForUpdates, 5 * 60 * 1000); return () => clearInterval(interval); }, [lastModified]); const handleSaveChanges = async (updatedItem) => { try { const response = await axios.put( `${import.meta.env.VITE_BACK_URL}/api/menu/${updatedItem.id}`, updatedItem, { headers: { 'Content-Type': 'application/json', } } ); // Обновляем локальное состояние const updateItemInTree = (items) => { return items.map(item => { if (item.id === updatedItem.id) { return { ...item, ...updatedItem }; } if (item.items) { return { ...item, items: updateItemInTree(item.items) }; } return item; }); }; setMenuData(prev => ({ ...prev, items: updateItemInTree(prev.items), })); setEditModalOpen(false); } catch (err) { console.error('Error updating menu item:', err); setError(err.response?.data?.message || err.message || 'Failed to update menu item'); } }; if (loading) { return ( ); } if (error) { return ( Error loading menu: {error} ); } if (!menuData) { return null; } return ( { setEditingItem(item); setEditModalOpen(true); }} onSelectItem={onMenuSelect} editModalOpen={editModalOpen} editingItem={editingItem} onCloseEditModal={() => setEditModalOpen(false)} onSaveChanges={handleSaveChanges} forceRefreshMenu={forceRefreshMenu} /> ); }; export default SidebarMenuWrapper;