Files
tourrism_site/public/components/admin-calendar-resource.jsx
Andrey K. Choi 13c752b93a feat: Оптимизация навигации AdminJS в логические группы
- Объединены ресурсы в 5 логических групп: Контент сайта, Бронирования, Отзывы и рейтинги, Персонал и гиды, Администрирование
- Удалены дублирующие настройки navigation для чистой группировки
- Добавлены CSS стили для визуального отображения иерархии с отступами
- Добавлены эмодзи-иконки для каждого типа ресурсов через CSS
- Улучшена навигация с правильной вложенностью элементов
2025-11-30 21:57:58 +09:00

223 lines
7.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react'
const AdminCalendarResource = () => {
const [currentDate, setCurrentDate] = useState(new Date())
const [guides, setGuides] = useState([])
const [selectedGuide, setSelectedGuide] = useState(null)
const [workingDays, setWorkingDays] = useState([])
const [holidays, setHolidays] = useState([])
const [loading, setLoading] = useState(true)
useEffect(() => {
loadData()
}, [currentDate])
const loadData = async () => {
setLoading(true)
try {
const [guidesRes, holidaysRes] = await Promise.all([
fetch('/api/guides'),
fetch('/api/holidays')
])
const guidesData = await guidesRes.json()
const holidaysData = await holidaysRes.json()
setGuides(guidesData.data || guidesData)
setHolidays(holidaysData)
if (selectedGuide) {
const workingRes = await fetch(`/api/guide-working-days?guide_id=${selectedGuide}&month=${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}`)
const workingData = await workingRes.json()
setWorkingDays(workingData)
}
} catch (error) {
console.error('Error loading data:', 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 isWorkingDay = (day) => {
if (!day || !selectedGuide) return false
const dateStr = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`
return workingDays.some(wd => wd.work_date === dateStr)
}
const isHoliday = (day) => {
if (!day) return false
const dateStr = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`
return holidays.some(h => h.date === dateStr)
}
const toggleWorkingDay = async (day) => {
if (!selectedGuide || !day) return
const dateStr = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`
const isWorking = isWorkingDay(day)
try {
if (isWorking) {
await fetch('/api/guide-working-days', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ guide_id: selectedGuide, work_date: dateStr })
})
} else {
await fetch('/api/guide-working-days', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ guide_id: selectedGuide, work_date: dateStr })
})
}
loadData()
} catch (error) {
console.error('Error toggling working day:', error)
}
}
const changeMonth = (delta) => {
const newDate = new Date(currentDate)
newDate.setMonth(newDate.getMonth() + delta)
setCurrentDate(newDate)
}
const monthNames = [
'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь',
'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'
]
const weekDays = ['ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ', 'ВС']
if (loading) {
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<div>Загрузка календаря...</div>
</div>
)
}
return (
<div style={{ padding: '20px', fontFamily: 'system-ui' }}>
<div style={{ marginBottom: '20px' }}>
<h2>Календарь рабочих дней гидов</h2>
<div style={{ marginBottom: '20px' }}>
<label style={{ display: 'block', marginBottom: '5px' }}>Выберите гида:</label>
<select
value={selectedGuide || ''}
onChange={(e) => setSelectedGuide(e.target.value)}
style={{ padding: '8px', borderRadius: '4px', border: '1px solid #ddd', minWidth: '200px' }}
>
<option value="">-- Выберите гида --</option>
{guides.map(guide => (
<option key={guide.id} value={guide.id}>{guide.name}</option>
))}
</select>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '20px', marginBottom: '20px' }}>
<button
onClick={() => changeMonth(-1)}
style={{ padding: '8px 16px', border: '1px solid #ddd', borderRadius: '4px', background: 'white', cursor: 'pointer' }}
>
Предыдущий
</button>
<h3 style={{ margin: 0 }}>
{monthNames[currentDate.getMonth()]} {currentDate.getFullYear()}
</h3>
<button
onClick={() => changeMonth(1)}
style={{ padding: '8px 16px', border: '1px solid #ddd', borderRadius: '4px', background: 'white', cursor: 'pointer' }}
>
Следующий
</button>
</div>
</div>
{selectedGuide && (
<div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: '1px', marginBottom: '20px' }}>
{weekDays.map(day => (
<div key={day} style={{
padding: '10px',
textAlign: 'center',
fontWeight: 'bold',
background: '#f5f5f5',
border: '1px solid #ddd'
}}>
{day}
</div>
))}
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: '1px' }}>
{getDaysInMonth(currentDate).map((day, index) => (
<div
key={index}
onClick={() => toggleWorkingDay(day)}
style={{
padding: '15px',
textAlign: 'center',
border: '1px solid #ddd',
minHeight: '50px',
cursor: day ? 'pointer' : 'default',
background: day ?
(isHoliday(day) ? '#ffcccb' :
isWorkingDay(day) ? '#c8e6c9' : 'white') : '#f9f9f9',
color: day ? (isHoliday(day) ? '#d32f2f' : '#333') : '#ccc',
fontWeight: day ? 'normal' : '300'
}}
>
{day || ''}
</div>
))}
</div>
<div style={{ marginTop: '20px', display: 'flex', gap: '20px', fontSize: '14px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
<div style={{ width: '20px', height: '20px', background: '#c8e6c9', border: '1px solid #ddd' }}></div>
<span>Рабочий день</span>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
<div style={{ width: '20px', height: '20px', background: '#ffcccb', border: '1px solid #ddd' }}></div>
<span>Выходной/Праздник</span>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
<div style={{ width: '20px', height: '20px', background: 'white', border: '1px solid #ddd' }}></div>
<span>Не назначено</span>
</div>
</div>
</div>
)}
{!selectedGuide && (
<div style={{ textAlign: 'center', padding: '40px', color: '#666' }}>
Выберите гида для просмотра календаря
</div>
)}
</div>
)
}
export default AdminCalendarResource