import { useEffect, useState } from 'react'; import { CONFLICT_CHECK_STATE, classroomOccupancyLabel, conflictCheckPresentation, currentSlotLabel, currentWeekDateRange, detectScheduleConflicts, fetchDashboardReferenceData, fetchEffectiveTimeSlots, fetchTodayLessons, findCurrentSlot, formatLocalDate, freeClassroomsForSlot, lessonsForSlot, loadWeekDepartmentSchedules, sortTimeSlots, totalStudents } from '../dashboard-service.js'; const REALTIME_UPDATE_MS = 30_000; export function DashboardTab() { const [reference, setReference] = useState(null); const [todayLessons, setTodayLessons] = useState([]); const [timeSlots, setTimeSlots] = useState([]); const [dataPhase, setDataPhase] = useState('loading'); const [conflictPhase, setConflictPhase] = useState('checking'); const [conflicts, setConflicts] = useState({ items: [], presentation: null }); const [recheckBusy, setRecheckBusy] = useState(false); const [now, setNow] = useState(() => new Date()); useEffect(() => { void loadData(); }, []); useEffect(() => { const timer = setInterval(() => setNow(new Date()), REALTIME_UPDATE_MS); return () => clearInterval(timer); }, []); async function loadData() { setDataPhase('loading'); setConflictPhase('checking'); try { const loadedReference = await fetchDashboardReferenceData(); const todayStr = formatLocalDate(new Date()); const [lessons, slots] = await Promise.all([ fetchTodayLessons(loadedReference.departments, todayStr), fetchEffectiveTimeSlots(todayStr) ]); setReference(loadedReference); setTodayLessons(lessons); setTimeSlots(sortTimeSlots(slots)); setDataPhase('ready'); await checkConflicts(loadedReference); } catch { setDataPhase('error'); setConflictPhase('error'); console.error('Не удалось загрузить данные панели'); } } async function checkConflicts(referenceData) { setConflictPhase('checking'); try { const range = currentWeekDateRange(new Date()); const scheduleLoad = await loadWeekDepartmentSchedules(referenceData.departments, range); const items = detectScheduleConflicts(scheduleLoad.lessons, referenceData.groups, referenceData.classrooms); const presentation = scheduleLoad.state === CONFLICT_CHECK_STATE.NOT_RUN ? conflictCheckPresentation(scheduleLoad, 0, range) : conflictCheckPresentation(scheduleLoad, items.length, range); setConflicts({ items, presentation }); setConflictPhase('ready'); } catch { setConflictPhase('error'); console.error('Не удалось выполнить проверку конфликтов'); } } async function recheck() { setRecheckBusy(true); try { if (dataPhase === 'ready' && reference) { await checkConflicts(reference); } else { await loadData(); } } finally { setRecheckBusy(false); } } const ready = dataPhase === 'ready' && reference !== null; const currentSlot = ready ? findCurrentSlot(timeSlots, now) : null; const currentLessons = currentSlot ? lessonsForSlot(todayLessons, currentSlot.orderNumber) : []; const freeRooms = ready ? freeClassroomsForSlot(reference.classrooms, todayLessons, currentSlot ? currentSlot.orderNumber : null) : []; return (
| Аудитория | Дисциплина | Преподаватель | Группа |
|---|---|---|---|
| Определение текущего времени... | |||
| В данный момент учебные пары не проводятся | |||
| В текущий слот занятий не запланировано | |||
| {lesson.classroomName} | {lesson.subjectName}{' '} {lesson.lessonTypeName} | {lesson.teacherName} | {lesson.groupNames.join(', ')} |
{(conflict.segments || []).map((segment, index) => ( typeof segment === 'string' ? segment : {segment.strong} ))}