Corp/backend/static/js/components/calendarWidgetIntegration.js
Игорь Надеин f8a8b3b2f2 fix(calendar): improve integration initialization and fallback to legacy mode
- Fixed calendar_scripts.html to wait for DOM ready before initialization
- Added retry logic if widget not found on first attempt
- Changed integration fallback: show ALL events when no calendars configured
- Changed behavior: if no calendars selected, show all events (legacy mode)
- This ensures backward compatibility with existing events

User feedback: Integration wasn't initializing on page load, button '+' didn't work.
Solution: Auto-init with retry + always show events (no empty state).
2026-02-11 11:26:25 +03:00

260 lines
8.6 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.

/**
* @fileoverview Calendar Widget Integration - связывает calendarManager с calendarWidget
* @module components/calendarWidgetIntegration
*/
import { initCalendarManager } from './calendarManager.js';
import { initCalendarManageModal } from './calendarManageModal.js';
import { getCalendarEvents } from '../api/calendarApi.js';
// Глобальное хранилище интеграции
let globalIntegration = null;
/**
* Расширенная инициализация виджета календаря с поддержкой множественных календарей
* @param {Object} calendarWidgetInstance - Экземпляр calendarWidget
* @param {Object} options - Опции
* @returns {Object} Расширенный API
*/
export function integrateCalendarManager(calendarWidgetInstance, options = {}) {
if (!calendarWidgetInstance) {
console.warn('[CalendarIntegration] calendarWidget instance not provided');
return null;
}
let visibleCalendarIds = [];
let calendars = [];
/**
* Загрузить события с учётом выбранных календарей
* @param {Date} start - Начало периода
* @param {Date} end - Конец периода
* @returns {Promise<Array>} События
*/
async function fetchEventsForVisibleCalendars(start, end) {
const startStr = formatDate(start);
const endStr = formatDate(end);
console.log('[CalendarIntegration] Fetching events for visible calendars:', {
visibleCount: visibleCalendarIds.length,
totalCalendars: calendars.length,
range: `${startStr} - ${endStr}`
});
// Если нет календарей в новой системе, используем legacy режим (показываем ВСЕ события)
if (calendars.length === 0) {
console.log('[CalendarIntegration] No calendars configured, using legacy mode (showing all events)');
return await getCalendarEvents({
start: startStr,
end: endStr
});
}
// Если ни один календарь не выбран, ТОЖЕ показываем все события (legacy режим)
if (visibleCalendarIds.length === 0) {
console.log('[CalendarIntegration] No calendars selected, falling back to legacy mode');
return await getCalendarEvents({
start: startStr,
end: endStr
});
}
// Загружаем события для каждого видимого календаря
const eventChunks = await Promise.all(
visibleCalendarIds.map(async (calendarId) => {
try {
const events = await getCalendarEvents({
start: startStr,
end: endStr,
calendar_id: calendarId
});
console.log(`[CalendarIntegration] Loaded ${events?.length || 0} events for calendar ${calendarId}`);
// Добавляем информацию о календаре к каждому событию
const calendar = calendars.find(c => c.id === calendarId);
return (events || []).map(event => ({
...event,
__calendar: calendar,
// Переопределяем цвет события цветом календаря
color: calendar?.color || event.color
}));
} catch (error) {
console.error(`[CalendarIntegration] Failed to load events for calendar ${calendarId}:`, error);
return [];
}
})
);
// Объединяем все события
const allEvents = eventChunks.flat();
console.log(`[CalendarIntegration] Total events loaded: ${allEvents.length}`);
// Дедупликация по ID
const seen = new Set();
const uniqueEvents = allEvents.filter(event => {
const id = event.id || event.pk;
if (!id || seen.has(id)) return false;
seen.add(id);
return true;
});
console.log(`[CalendarIntegration] Unique events after dedup: ${uniqueEvents.length}`);
return uniqueEvents;
}
/**
* Форматировать дату в YYYY-MM-DD
* @param {Date} date
* @returns {string}
*/
function formatDate(date) {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, '0');
const d = String(date.getDate()).padStart(2, '0');
return `${y}-${m}-${d}`;
}
/**
* Обработчик переключения видимости календаря
* @param {number} calendarId
* @param {boolean} isVisible
*/
function handleCalendarToggle(calendarId, isVisible) {
console.log(`[CalendarIntegration] Calendar ${calendarId} visibility: ${isVisible}`);
// Обновляем список видимых календарей
if (isVisible) {
if (!visibleCalendarIds.includes(calendarId)) {
visibleCalendarIds.push(calendarId);
}
} else {
visibleCalendarIds = visibleCalendarIds.filter(id => id !== calendarId);
}
// Перезагружаем события
if (calendarWidgetInstance.refetchEvents) {
calendarWidgetInstance.refetchEvents();
}
}
/**
* Обработчик изменения списка календарей
* @param {Array} newCalendars
* @param {Array} newVisibleIds
*/
function handleCalendarsChange(newCalendars, newVisibleIds) {
console.log(`[CalendarIntegration] Calendars updated:`, {
total: newCalendars.length,
visible: newVisibleIds.length
});
calendars = newCalendars;
visibleCalendarIds = newVisibleIds;
// Перезагружаем события
if (calendarWidgetInstance.refetchEvents) {
calendarWidgetInstance.refetchEvents();
}
}
/**
* Обработчик успешного сохранения календаря
*/
function handleModalSuccess() {
console.log('[CalendarIntegration] Calendar saved, refreshing list');
// Обновляем список календарей
if (calendarManagerInstance) {
calendarManagerInstance.refresh();
}
}
// Инициализация менеджера календарей
const calendarManagerInstance = initCalendarManager({
containerId: 'calendarListContainer',
onCalendarToggle: handleCalendarToggle,
onCalendarsChange: handleCalendarsChange
});
// Инициализация модального окна управления
const manageModalInstance = initCalendarManageModal({
onSuccess: handleModalSuccess
});
// Привязываем кнопку создания календаря к модальному окну
const createCalendarBtn = document.querySelector('[data-action="create-calendar"]');
if (createCalendarBtn && manageModalInstance) {
createCalendarBtn.addEventListener('click', () => {
manageModalInstance.openForCreate();
});
}
// Обрабатываем событие редактирования календаря из списка
if (manageModalInstance) {
document.addEventListener('calendar:edit', (e) => {
const calendar = e.detail;
console.log('[CalendarIntegration] Edit calendar requested:', calendar);
manageModalInstance.openForEdit(calendar.id);
});
}
// Создаём объект интеграции
const integration = {
/**
* Получить события для видимых календарей
*/
fetchEventsForVisibleCalendars,
/**
* Получить ID видимых календарей
*/
getVisibleCalendarIds: () => [...visibleCalendarIds],
/**
* Получить все календари
*/
getCalendars: () => [...calendars],
/**
* Установить видимые календари
*/
setVisibleCalendars: (ids) => {
if (calendarManagerInstance) {
calendarManagerInstance.setVisibleCalendars(ids);
}
},
/**
* Обновить список календарей
*/
refresh: () => {
if (calendarManagerInstance) {
return calendarManagerInstance.refresh();
}
},
/**
* Получить экземпляры компонентов
*/
instances: {
manager: calendarManagerInstance,
modal: manageModalInstance,
widget: calendarWidgetInstance
}
};
// Сохраняем глобально для доступа из других модулей
globalIntegration = integration;
return integration;
}
/**
* Получить глобальный экземпляр интеграции
* @returns {Object|null}
*/
export function getCalendarIntegration() {
return globalIntegration;
}