let currentWeekStart = null;
const weekdays = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье'];
const weekdaysShort = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
function getTodayInLondon() {
// Получаем текущую дату в таймзоне London
const now = new Date();
const formatter = new Intl.DateTimeFormat('en-CA', {
timeZone: 'Europe/London',
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
return formatter.format(now);
}
function getWeekStart(dateStr = null) {
if (!dateStr) {
dateStr = getTodayInLondon();
}
const date = new Date(dateStr + 'T00:00:00');
const day = date.getDay();
const diff = date.getDate() - day + (day === 0 ? -6 : 1); // Понедельник = 1
const monday = new Date(date.setDate(diff));
return monday.toISOString().split('T')[0];
}
function formatDate(dateStr) {
const date = new Date(dateStr + 'T00:00:00');
return `${weekdaysShort[date.getDay()]}, ${date.getDate()}`;
}
function formatDateFull(dateStr) {
const date = new Date(dateStr + 'T00:00:00');
const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня',
'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'];
return `${weekdays[date.getDay()]}, ${date.getDate()} ${months[date.getMonth()]}`;
}
function getWeekDates(startDate) {
const dates = [];
const start = new Date(startDate + 'T00:00:00');
for (let i = 0; i < 7; i++) {
const date = new Date(start);
date.setDate(start.getDate() + i);
dates.push(date.toISOString().split('T')[0]);
}
return dates;
}
async function loadSchedule() {
const weekDates = getWeekDates(currentWeekStart);
const fromDate = weekDates[0];
const toDate = weekDates[6];
console.log('Loading schedule from', fromDate, 'to', toDate);
try {
const response = await fetch(`/api/schedule?from_date=${fromDate}&to_date=${toDate}`);
const data = await response.json();
console.log('Received items:', data.items);
renderSchedule(weekDates, data.items);
// Обновляем заголовок недели
const startDate = new Date(weekDates[0] + 'T00:00:00');
const endDate = new Date(weekDates[6] + 'T00:00:00');
document.getElementById('week-range').textContent =
`${formatDateFull(weekDates[0])} - ${formatDateFull(weekDates[6])}`;
} catch (error) {
console.error('Error loading schedule:', error);
}
}
function renderSchedule(weekDates, items) {
const grid = document.getElementById('schedule-grid');
grid.innerHTML = '';
console.log('Rendering schedule for dates:', weekDates);
console.log('All items:', items);
weekDates.forEach(dateStr => {
const dayItems = items.filter(item => {
const match = item.date === dateStr;
if (!match && items.length > 0) {
console.log(`Item date ${item.date} !== ${dateStr}`);
}
return match;
});
console.log(`Date ${dateStr}: ${dayItems.length} items`);
const date = new Date(dateStr + 'T00:00:00');
const column = document.createElement('div');
column.className = 'day-column';
column.innerHTML = `
${renderDayItems(dayItems)}
`;
grid.appendChild(column);
});
}
function renderDayItems(items) {
console.log('Rendering items for day:', items);
if (items.length === 0) {
return 'Нет записей
';
}
const tasks = items.filter(item => item.kind === 'task');
const events = items.filter(item => item.kind === 'event');
console.log('Tasks:', tasks, 'Events:', events);
let html = '';
// Tasks
tasks.forEach(task => {
html += `
${task.title}
${task.repeat_weekly ? '
Повторяется
' : ''}
`;
});
// Events
events.sort((a, b) => a.start_time.localeCompare(b.start_time)).forEach(event => {
const endTime = calculateEndTime(event.start_time, event.duration_min);
html += `
${event.start_time}-${endTime}
${event.title}
`;
});
return html;
}
function calculateEndTime(startTime, durationMin) {
const [hour, minute] = startTime.split(':').map(Number);
const totalMinutes = hour * 60 + minute + durationMin;
const endHour = Math.floor(totalMinutes / 60);
const endMinute = totalMinutes % 60;
return `${String(endHour).padStart(2, '0')}:${String(endMinute).padStart(2, '0')}`;
}
function showModal(content) {
document.getElementById('modal-body').innerHTML = content;
document.getElementById('modal').style.display = 'block';
}
function closeModal() {
document.getElementById('modal').style.display = 'none';
}
function showAddTaskModal(selectedDate = null) {
const weekDates = getWeekDates(currentWeekStart);
const today = getTodayInLondon();
const todayDate = new Date(today + 'T00:00:00');
const selectedDateObj = selectedDate ? new Date(selectedDate + 'T00:00:00') : todayDate;
// getDay() возвращает 0=воскресенье, 1=понедельник, ..., 6=суббота
// Конвертируем в формат 0=понедельник, 6=воскресенье
const jsWeekday = selectedDateObj.getDay();
const selectedWeekday = jsWeekday === 0 ? 6 : jsWeekday - 1; // 0=пн, 6=вс
const remainingWeekdays = [];
// Оставшиеся дни недели после выбранного (среда=2, четверг=3, пятница=4, суббота=5, воскресенье=6)
for (let i = selectedWeekday + 1; i <= 6; i++) {
remainingWeekdays.push(i);
}
const content = `
Добавить задачу
`;
showModal(content);
document.getElementById('task-repeat-weekly').addEventListener('change', function() {
document.getElementById('copy-weekdays-group').style.display =
this.checked ? 'none' : 'block';
});
document.getElementById('add-task-form').addEventListener('submit', async (e) => {
e.preventDefault();
const date = document.getElementById('task-date').value;
const title = document.getElementById('task-title').value;
const repeatWeekly = document.getElementById('task-repeat-weekly').checked;
const copyWeekdays = Array.from(document.querySelectorAll('input[name="copy-weekday"]:checked'))
.map(cb => parseInt(cb.value));
try {
const response = await fetch('/api/events?kind=task', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
date,
title,
repeat_weekly: repeatWeekly,
copy_to_weekdays: copyWeekdays.length > 0 ? copyWeekdays : null
})
});
if (response.ok) {
const result = await response.json();
console.log('Task created:', result);
closeModal();
await loadSchedule();
} else {
const error = await response.json();
console.error('Error creating task:', error);
alert('Ошибка: ' + (error.detail || 'Неизвестная ошибка'));
}
} catch (error) {
console.error('Exception creating task:', error);
alert('Ошибка при добавлении задачи: ' + error.message);
}
});
}
function showAddEventModal(selectedDate = null) {
const today = getTodayInLondon();
const content = `
Добавить занятие
`;
showModal(content);
document.getElementById('add-event-form').addEventListener('submit', async (e) => {
e.preventDefault();
const date = document.getElementById('event-date').value;
const hour = document.getElementById('event-hour').value;
const minute = document.getElementById('event-minute').value;
const durHour = parseInt(document.getElementById('event-duration-hour').value);
const durMin = parseInt(document.getElementById('event-duration-minute').value);
const title = document.getElementById('event-title').value;
const durationMin = durHour * 60 + durMin;
if (durationMin === 0) {
alert('Длительность должна быть минимум 15 минут');
return;
}
try {
const response = await fetch('/api/events?kind=event', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
date,
start_time: `${hour}:${minute}`,
duration_min: durationMin,
title
})
});
if (response.ok) {
const result = await response.json();
console.log('Event created:', result);
closeModal();
await loadSchedule();
} else {
const error = await response.json();
console.error('Error creating event:', error);
alert('Ошибка: ' + (error.detail || 'Неизвестная ошибка'));
}
} catch (error) {
console.error('Exception creating event:', error);
alert('Ошибка при добавлении занятия: ' + error.message);
}
});
}
async function editItem(id, kind) {
// TODO: Реализовать редактирование
alert('Редактирование будет реализовано позже');
}
async function deleteItem(id, kind) {
if (!confirm('Удалить эту запись?')) return;
try {
const response = await fetch(`/api/events/${id}`, {
method: 'DELETE'
});
if (response.ok) {
loadSchedule();
} else {
alert('Ошибка при удалении');
}
} catch (error) {
alert('Ошибка при удалении');
console.error(error);
}
}
// Инициализация
document.addEventListener('DOMContentLoaded', () => {
currentWeekStart = getWeekStart();
loadSchedule();
document.getElementById('prev-week').addEventListener('click', () => {
const date = new Date(currentWeekStart + 'T00:00:00');
date.setDate(date.getDate() - 7);
currentWeekStart = date.toISOString().split('T')[0];
loadSchedule();
});
document.getElementById('next-week').addEventListener('click', () => {
const date = new Date(currentWeekStart + 'T00:00:00');
date.setDate(date.getDate() + 7);
currentWeekStart = date.toISOString().split('T')[0];
loadSchedule();
});
document.getElementById('add-task-btn').addEventListener('click', () => showAddTaskModal());
document.getElementById('add-event-btn').addEventListener('click', () => showAddEventModal());
document.querySelector('.close').addEventListener('click', closeModal);
window.addEventListener('click', (e) => {
const modal = document.getElementById('modal');
if (e.target === modal) {
closeModal();
}
});
// Клик по дню для добавления
document.addEventListener('click', (e) => {
if (e.target.closest('.day-items')) {
const date = e.target.closest('.day-items').dataset.date;
if (e.ctrlKey || e.metaKey) {
showAddEventModal(date);
} else if (e.shiftKey) {
showAddTaskModal(date);
}
}
});
});