export function renderScheduleOverviewState(container, { kind = 'loading', message = '', onRetry = null } = {}) { if (!container) return; const labels = { loading: message || 'Загружаем ближайшие занятия…', empty: message || 'В ближайшие дни занятий нет', error: message || 'Не удалось загрузить ближайшие занятия' }; container.innerHTML = `
${kind === 'loading' ? '' : ''} ${escapeHtml(labels[kind] || message)} ${kind === 'error' && onRetry ? '' : ''}
`; container.querySelector('[data-overview-retry]')?.addEventListener('click', onRetry); } export function renderScheduleOverview(container, lessons, { role = 'student', now = new Date(), onGoToday = null } = {}) { if (!container) return { todayCount: 0, hasNext: false }; const { todayIso, todayLessons, nextLesson } = buildScheduleOverviewModel(lessons, now); container.innerHTML = `
Быстрый обзор

${escapeHtml(formatLongDate(now))}

Сегодня

${todayLessons.length ? pluralLessons(todayLessons.length) : 'Свободный день'}

${todayLessons.length}
${todayLessons.length ? todayLessons.map(lesson => renderCompactLesson(lesson, role)).join('') : '

На сегодня занятий нет.

'}
Следующая пара

${nextLesson ? escapeHtml(relativeDate(nextLesson.date, todayIso)) : 'Пока ничего не запланировано'}

${nextLesson ? `${lessonStart(nextLesson) <= now ? 'Идёт сейчас' : escapeHtml(trimTime(nextLesson.startTime))}` : ''}
${nextLesson ? renderNextLesson(nextLesson, role) : '

В ближайшие 14 дней занятий нет.

'}
`; container.querySelector('[data-overview-today]')?.addEventListener('click', onGoToday || (() => {})); return { todayCount: todayLessons.length, hasNext: Boolean(nextLesson) }; } export function buildScheduleOverviewModel(lessons, now = new Date()) { const ordered = [...(lessons || [])].sort((left, right) => lessonStart(left) - lessonStart(right)); const todayIso = toIsoDate(now); return { todayIso, todayLessons: ordered.filter(lesson => lesson.date === todayIso), nextLesson: ordered.find(lesson => lessonEnd(lesson) >= now) || null }; } function renderCompactLesson(lesson, role) { return `
${escapeHtml(lesson.subjectName || 'Занятие')} ${escapeHtml(lessonMeta(lesson, role).join(' · ') || 'Подробности уточняются')}
`; } function renderNextLesson(lesson, role) { return `
${escapeHtml(trimTime(lesson.startTime))} до ${escapeHtml(trimTime(lesson.endTime))}

${escapeHtml(lesson.subjectName || 'Занятие')}

${escapeHtml(lessonMeta(lesson, role).join(' · ') || 'Подробности уточняются')}

${lesson.lessonTypeName ? `${escapeHtml(lesson.lessonTypeName)}` : ''}
`; } function lessonMeta(lesson, role) { const groups = Array.isArray(lesson.groupNames) ? lesson.groupNames.join(', ') : ''; const subgroup = Array.isArray(lesson.subgroupNames) ? lesson.subgroupNames.join(', ') : lesson.subgroupName; return role === 'teacher' ? [groups || subgroup, lesson.classroomName].filter(Boolean) : [lesson.teacherName, lesson.classroomName, subgroup].filter(Boolean); } function lessonStart(lesson) { return new Date(`${lesson.date}T${normalizeTime(lesson.startTime)}`); } function lessonEnd(lesson) { return new Date(`${lesson.date}T${normalizeTime(lesson.endTime || lesson.startTime)}`); } function normalizeTime(value) { const text = String(value || '00:00:00'); return text.length === 5 ? `${text}:00` : text; } function relativeDate(value, todayIso) { if (value === todayIso) return 'Сегодня'; const today = parseIsoDate(todayIso); const target = parseIsoDate(value); const dayDifference = Math.round((target - today) / 86400000); if (dayDifference === 1) return 'Завтра'; return target.toLocaleDateString('ru-RU', { weekday: 'long', day: 'numeric', month: 'long' }); } function parseIsoDate(value) { const [year, month, day] = String(value).split('-').map(Number); return new Date(year, month - 1, day); } function toIsoDate(date) { return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`; } function formatLongDate(date) { const value = date.toLocaleDateString('ru-RU', { weekday: 'long', day: 'numeric', month: 'long' }); return value.charAt(0).toUpperCase() + value.slice(1); } function pluralLessons(count) { const mod10 = count % 10; const mod100 = count % 100; const noun = mod10 === 1 && mod100 !== 11 ? 'занятие' : mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14) ? 'занятия' : 'занятий'; return `${count} ${noun}`; } function trimTime(value) { return String(value || '').slice(0, 5); } function escapeHtml(value) { return String(value ?? '') .replaceAll('&', '&') .replaceAll('<', '<') .replaceAll('>', '>') .replaceAll('"', '"') .replaceAll("'", '''); }