/** * @fileoverview Calendar Manage Modal - модальное окно создания/редактирования календаря * @module components/calendarManageModal */ import { createCalendar, updateCalendar, deleteCalendar } from '../api/calendarsApi.js'; import { getMyDepartments } from '../api/departmentsApi.js'; /** * Инициализация модального окна управления календарём * @param {Object} options - Параметры * @param {Function} options.onSuccess - Callback при успешном сохранении/удалении * @returns {Object} API модального окна */ export function initCalendarManageModal(options = {}) { const { onSuccess = () => {} } = options; const modal = document.getElementById('calendarManageModal'); if (!modal) { console.warn('[CalendarManageModal] Modal element not found'); return null; } const bsModal = new bootstrap.Modal(modal); // Elements const form = document.getElementById('calendarManageForm'); const titleEl = document.getElementById('calendarManageModalTitle'); const calendarIdInput = document.getElementById('calendarId'); const titleInput = document.getElementById('calendarTitle'); const descInput = document.getElementById('calendarDescription'); const colorInput = document.getElementById('calendarColor'); const colorTextInput = document.getElementById('calendarColorText'); const typeInputs = document.querySelectorAll('input[name="calendar_type"]'); const deptSelect = document.getElementById('calendarDepartment'); const deptSelectWrapper = document.getElementById('calendarDepartmentSelect'); const autoSubscribeDeptWrapper = document.getElementById('calendarAutoSubscribeDeptWrapper'); const saveBtn = document.getElementById('calendarSaveBtn'); const deleteBtn = document.getElementById('calendarDeleteBtn'); const errorEl = document.getElementById('calendarManageError'); let currentCalendar = null; /** * Открыть модальное окно для создания календаря */ function openForCreate() { currentCalendar = null; titleEl.textContent = 'Создать календарь'; deleteBtn.classList.add('d-none'); resetForm(); bsModal.show(); } /** * Открыть модальное окно для редактирования календаря * @param {Object} calendar - Данные календаря */ function openForEdit(calendar) { currentCalendar = calendar; titleEl.textContent = 'Редактировать календарь'; deleteBtn.classList.remove('d-none'); // Заполнить форму calendarIdInput.value = calendar.id; titleInput.value = calendar.title; descInput.value = calendar.description || ''; colorInput.value = calendar.color || '#0d6efd'; colorTextInput.value = calendar.color || '#0d6efd'; // Определить тип let type = 'personal'; if (calendar.is_global) { type = 'public'; } else if (calendar.is_department) { type = 'department'; } typeInputs.forEach(input => { input.checked = input.value === type; }); // Если отдел, выбрать его if (calendar.owner_department) { deptSelect.value = calendar.owner_department; } // Настройки document.getElementById('calendarAutoSubscribeNewUsers').checked = calendar.auto_subscribe_new_users || false; document.getElementById('calendarAutoSubscribeDept').checked = calendar.auto_subscribe_department_members || false; updateTypeVisibility(); bsModal.show(); } /** * Сбросить форму */ function resetForm() { form.reset(); calendarIdInput.value = ''; colorInput.value = '#0d6efd'; colorTextInput.value = '#0d6efd'; errorEl.classList.add('d-none'); updateTypeVisibility(); } /** * Обновить видимость полей в зависимости от типа */ function updateTypeVisibility() { const selectedType = document.querySelector('input[name="calendar_type"]:checked')?.value; if (selectedType === 'department') { deptSelectWrapper.classList.remove('d-none'); autoSubscribeDeptWrapper.classList.remove('d-none'); } else { deptSelectWrapper.classList.add('d-none'); autoSubscribeDeptWrapper.classList.add('d-none'); } } /** * Загрузить список отделов */ async function loadDepartments() { try { const departments = await getMyDepartments(); // Заполнить select deptSelect.innerHTML = '' + departments.map(dept => `` ).join(''); } catch (error) { console.error('[CalendarManageModal] Failed to load departments:', error); } } /** * Собрать данные формы * @returns {Object} */ function getFormData() { const data = { title: titleInput.value.trim(), description: descInput.value.trim(), color: colorInput.value, auto_subscribe_new_users: document.getElementById('calendarAutoSubscribeNewUsers').checked, auto_subscribe_department_members: document.getElementById('calendarAutoSubscribeDept').checked }; const type = document.querySelector('input[name="calendar_type"]:checked')?.value; if (type === 'personal') { data.visibility = 'private'; // owner_user будет установлен автоматически на backend } else if (type === 'public') { data.visibility = 'public'; } else if (type === 'department') { data.visibility = 'department'; data.owner_department = parseInt(deptSelect.value); if (!data.owner_department) { throw new Error('Выберите отдел'); } } return data; } /** * Сохранить календарь */ async function save() { try { errorEl.classList.add('d-none'); saveBtn.disabled = true; const data = getFormData(); if (currentCalendar) { // Обновление await updateCalendar(currentCalendar.id, data); } else { // Создание await createCalendar(data); } bsModal.hide(); onSuccess(); } catch (error) { console.error('[CalendarManageModal] Save failed:', error); errorEl.textContent = error.message || 'Не удалось сохранить календарь'; errorEl.classList.remove('d-none'); } finally { saveBtn.disabled = false; } } /** * Удалить календарь */ async function remove() { if (!currentCalendar) return; if (!confirm(`Удалить календарь "${currentCalendar.title}"?\n\nВсе события этого календаря будут удалены.`)) { return; } try { deleteBtn.disabled = true; await deleteCalendar(currentCalendar.id); bsModal.hide(); onSuccess(); } catch (error) { console.error('[CalendarManageModal] Delete failed:', error); errorEl.textContent = error.message || 'Не удалось удалить календарь'; errorEl.classList.remove('d-none'); } finally { deleteBtn.disabled = false; } } // Event listeners // Синхронизация цвета colorInput.addEventListener('input', (e) => { colorTextInput.value = e.target.value; }); colorTextInput.addEventListener('input', (e) => { const value = e.target.value; if (/^#[0-9A-Fa-f]{6}$/.test(value)) { colorInput.value = value; } }); // Изменение типа календаря typeInputs.forEach(input => { input.addEventListener('change', updateTypeVisibility); }); // Сохранить saveBtn.addEventListener('click', save); // Удалить deleteBtn.addEventListener('click', remove); // Сброс при закрытии modal.addEventListener('hidden.bs.modal', resetForm); // Слушать событие редактирования из других компонентов document.addEventListener('calendar:edit', (e) => { openForEdit(e.detail); }); // Инициализация loadDepartments(); // Public API return { openForCreate, openForEdit, show: () => bsModal.show(), hide: () => bsModal.hide() }; }