import React, { useState, useEffect } from 'react'; const GuideCalendarView = () => { const [currentDate, setCurrentDate] = useState(new Date()); const [workingDays, setWorkingDays] = useState([]); const [guides, setGuides] = useState([]); const [selectedGuide, setSelectedGuide] = useState(''); const [loading, setLoading] = useState(true); const [stats, setStats] = useState({ totalDays: 0, totalGuides: 0 }); useEffect(() => { loadGuides(); }, []); useEffect(() => { loadWorkingDays(); }, [currentDate, selectedGuide]); const loadGuides = async () => { try { const response = await fetch('/api/guides'); const data = await response.json(); setGuides(data.success ? data.data : data); } catch (error) { console.error('Error loading guides:', error); } }; const loadWorkingDays = async () => { setLoading(true); try { const month = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}`; const url = selectedGuide ? `/api/guide-working-days?month=${month}&guide_id=${selectedGuide}` : `/api/guide-working-days?month=${month}`; const response = await fetch(url); const data = await response.json(); setWorkingDays(data); // Подсчет статистики const uniqueGuides = new Set(data.map(d => d.guide_id)); setStats({ totalDays: data.length, totalGuides: uniqueGuides.size }); } catch (error) { console.error('Error loading working days:', error); } setLoading(false); }; const getDaysInMonth = (date) => { const year = date.getFullYear(); const month = date.getMonth(); const daysInMonth = new Date(year, month + 1, 0).getDate(); const firstDayOfWeek = new Date(year, month, 1).getDay(); const days = []; // Добавляем пустые дни в начале for (let i = 0; i < (firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1); i++) { days.push(null); } // Добавляем дни месяца for (let day = 1; day <= daysInMonth; day++) { days.push(day); } return days; }; const getWorkingDaysForDate = (day) => { if (!day) return []; const dateStr = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; return workingDays.filter(wd => wd.work_date === dateStr); }; const getGuideById = (id) => { return guides.find(g => g.id === id); }; const changeMonth = (delta) => { const newDate = new Date(currentDate); newDate.setMonth(newDate.getMonth() + delta); setCurrentDate(newDate); }; const monthNames = [ 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь' ]; const weekDays = ['ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ', 'ВС']; if (loading && workingDays.length === 0) { return (
Загрузка календаря...
); } return (
{/* Заголовок и статистика */}

📅 Календарь рабочих дней гидов

{stats.totalDays} рабочих дней
{stats.totalGuides} активных гидов
{/* Фильтр по гиду */}
{selectedGuide && ( )}
{/* Навигация по месяцам */}

{monthNames[currentDate.getMonth()]} {currentDate.getFullYear()}

{/* Календарная сетка */}
{/* Заголовки дней недели */}
{weekDays.map(day => (
{day}
))}
{/* Дни месяца */}
{getDaysInMonth(currentDate).map((day, index) => { const dayWorkingData = getWorkingDaysForDate(day); const hasData = dayWorkingData.length > 0; return (
{day && ( <>
{day}
{dayWorkingData.map((workDay, idx) => { const guide = getGuideById(workDay.guide_id); return (
{guide?.name || `Гид #${workDay.guide_id}`}
{workDay.notes && (
{workDay.notes.length > 20 ? workDay.notes.substring(0, 20) + '...' : workDay.notes}
)}
); })} )}
); })}
{/* Легенда */}
Городские туры
Горные туры
Морская рыбалка
Рабочий день
{/* Быстрые действия */}

Быстрые действия:

); }; export default GuideCalendarView;