/** * @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(), }; }