// Ждём полной загрузки DOM перед выполнением кода
document.addEventListener("DOMContentLoaded", function () {
  // Находим элемент контейнера для календаря по ID
  var calendarContainer = document.getElementById("kt_calendar_app");

  // Проверяем, существует ли контейнер для календаря
  if (!calendarContainer) {
    // Если контейнер не найден, выводим ошибку в консоль и останавливаем выполнение
    console.error(
      "Ошибка: контейнер для календаря с ID 'kt_calendar_app' не найден."
    );
    return;
  }

  // Создаём новый экземпляр календаря FullCalendar
  var calendar = new FullCalendar.Calendar(calendarContainer, {
    initialView: "dayGridMonth", // Устанавливаем начальный вид как месячный календарь
    locale: "ru", // Устанавливаем русский язык для интерфейса
    timeZone: "UTC", // Устанавливаем часовой пояс UTC
    headerToolbar: {
      // Настраиваем панель инструментов календаря
      left: "prev,next today", // Кнопки "предыдущий", "следующий" и "сегодня" слева
      center: "title", // Заголовок (название месяца/недели) в центре
      right: "dayGridMonth,timeGridWeek,timeGridDay" // Переключатели видов справа
    },
    editable: true, // Разрешаем редактировать события (перетаскивание)
    eventDurationEditable: true, // Разрешаем изменять длительность событий
    eventResizableFromStart: true, // Разрешаем изменять размер события с начала
    events: "get_events.php", // URL для получения событий через AJAX
    eventClick: function (info) {
      // Обработчик клика по событию
      openEventModal(info); // Открываем модальное окно с деталями события
    },
    eventDrop: function (info) {
      // Обработчик перемещения события
      console.log("Перемещение:", info.event.start, info.event.end); // Логируем новые даты
      updateEvent(info); // Обновляем событие на сервере
    },
    eventResize: function (info) {
      // Обработчик изменения размера события
      console.log("Растягивание:", info.event.start, info.event.end); // Логируем новые даты
      updateEvent(info); // Обновляем событие на сервере
    },
    eventConstraint: {
      // Ограничения времени для событий
      start: "00:00", // Начало дня
      end: "24:00" // Конец дня
    },
    displayEventTime: false, // Скрываем отображение времени в событиях
    // Преобразуем данные событий перед отображением
    eventDataTransform: function (eventData) {
      eventData.allDay = true; // Все события в dayGridMonth становятся цельнодневными
      eventData.editable = true; // Разрешаем редактирование
      eventData.durationEditable = true; // Разрешаем изменение длительности
      eventData.startEditable = true; // Разрешаем изменение начала
      return eventData; // Возвращаем изменённые данные события
    }
  });

  // Рендерим календарь на странице
  calendar.render();

  // Инициализируем Flatpickr для выбора начальной даты
  var startDatePicker = flatpickr("#kt_calendar_datepicker_start_date", {
    enableTime: false, // Отключаем выбор времени
    dateFormat: "Y-m-d", // Формат даты: ГГГГ-ММ-ДД
    defaultDate: "2025-03-04" // Устанавливаем дату по умолчанию
  });

  // Инициализируем Flatpickr для выбора конечной даты
  var endDatePicker = flatpickr("#kt_calendar_datepicker_end_date", {
    enableTime: false, // Отключаем выбор времени
    dateFormat: "Y-m-d", // Формат даты: ГГГГ-ММ-ДД
    defaultDate: "2025-03-08" // Устанавливаем дату по умолчанию
  });

  // Инициализируем Flatpickr для выбора начального времени
  var startTimePicker = flatpickr("#kt_calendar_datepicker_start_time", {
    enableTime: true, // Включаем выбор времени
    noCalendar: true, // Отключаем календарь
    dateFormat: "H:i", // Формат времени: ЧЧ:ММ
    time_24hr: true, // Используем 24-часовой формат
    defaultHour: 15, // Устанавливаем часы по умолчанию
    defaultMinute: 30 // Устанавливаем минуты по умолчанию
  });

  // Инициализируем Flatpickr для выбора конечного времени
  var endTimePicker = flatpickr("#kt_calendar_datepicker_end_time", {
    enableTime: true, // Включаем выбор времени
    noCalendar: true, // Отключаем календарь
    dateFormat: "H:i", // Формат времени: ЧЧ:ММ
    time_24hr: true, // Используем 24-часовой формат
    defaultHour: 17, // Устанавливаем часы по умолчанию
    defaultMinute: 20 // Устанавливаем минуты по умолчанию
  });

  // Находим элементы управления для переключения "весь день"
  var allDayCheckbox = document.getElementById("kt_calendar_datepicker_allday");
  var startTimeInput = document.getElementById(
    "kt_calendar_datepicker_start_time"
  );
  var endTimeInput = document.getElementById("kt_calendar_datepicker_end_time");

  // Добавляем обработчик изменения состояния чекбокса "весь день"
  allDayCheckbox.addEventListener("change", function () {
    if (this.checked) {
      // Если выбрано "весь день"
      startTimeInput.disabled = true; // Отключаем поле начального времени
      endTimeInput.disabled = true; // Отключаем поле конечного времени
      startTimePicker.setDate(null); // Очищаем начальное время
      endTimePicker.setDate(null); // Очищаем конечное время
    } else {
      // Если "весь день" отключён
      startTimeInput.disabled = false; // Включаем поле начального времени
      endTimeInput.disabled = false; // Включаем поле конечного времени
      startTimePicker.setDate("15:30"); // Устанавливаем начальное время по умолчанию
      endTimePicker.setDate("17:20"); // Устанавливаем конечное время по умолчанию
    }
  });

  // Добавляем обработчик нажатия на кнопку отправки формы добавления события
  document
    .getElementById("kt_modal_add_event_submit")
    .addEventListener("click", function (event) {
      event.preventDefault(); // Предотвращаем стандартную отправку формы

      // Собираем данные формы
      var form = document.getElementById("kt_modal_add_event_form");
      var formData = new FormData(form);

      // Функция форматирования даты и времени для отправки на сервер
      function formatDateTime(dateStr, timeStr, isAllDay) {
        if (!dateStr) return null; // Если дата не указана, возвращаем null
        // Преобразуем дату из формата ДД.ММ.ГГГГ в ГГГГ-ММ-ДД, если нужно
        const date = dateStr.includes(".")
          ? dateStr.split(".").reverse().join("-")
          : dateStr;
        if (isAllDay || !timeStr) return date; // Для событий "весь день" возвращаем только дату
        return `${date} ${timeStr}:00`; // Добавляем время в формате ЧЧ:ММ:СС
      }

      // Получаем значения из полей формы
      const startDate = document.getElementById(
        "kt_calendar_datepicker_start_date"
      ).value;
      const startTime = document.getElementById(
        "kt_calendar_datepicker_start_time"
      ).value;
      const endDate = document.getElementById("kt_calendar_datepicker_end_date")
        .value;
      const endTime = document.getElementById("kt_calendar_datepicker_end_time")
        .value;
      const isAllDay = allDayCheckbox.checked;

      // Форматируем даты и добавляем их в formData
      formData.set(
        "cnc_event_start_date",
        formatDateTime(startDate, startTime, isAllDay)
      );
      formData.set(
        "cnc_event_end_date",
        formatDateTime(endDate, endTime, isAllDay)
      );

      // Отправляем данные на сервер через AJAX
      fetch("save_events.php", {
        method: "POST", // Используем метод POST
        body: formData // Передаём данные формы
      })
        .then((response) => response.json()) // Парсим ответ как JSON
        .then((result) => {
          // Обрабатываем результат
          if (result.success) {
            // Если событие успешно добавлено
            alert("Событие успешно добавлено!"); // Показываем уведомление
            form.reset(); // Сбрасываем форму

            // Закрываем модальное окно
            var modalElement = document.getElementById("kt_modal_add_event");
            var modalInstance = bootstrap.Modal.getInstance(modalElement);
            if (modalInstance) {
              modalInstance.hide();
            }

            // Создаём объект нового события для добавления в календарь
            var newEvent = {
              id: result.event_id, // ID события с сервера
              title: formData.get("cnc_event_title"), // Заголовок события
              start: formData.get("cnc_event_start_date").replace(" ", "T"), // Начало события
              end: formData.get("cnc_event_end_date").replace(" ", "T"), // Конец события
              description: formData.get("cnc_event_description"), // Описание
              location: formData.get("cnc_event_location"), // Место
              color: formData.get("cnc_event_color"), // Цвет события
              allDay: true, // Устанавливаем как цельнодневное
              editable: true, // Разрешаем редактирование
              durationEditable: true, // Разрешаем изменение длительности
              startEditable: true // Разрешаем изменение начала
            };

            // Добавляем событие в календарь
            calendar.addEvent(newEvent);
            // Показываем уведомление об успехе
            showAlert("Подію збережено", "Подію збережено. Гарного дня!");
          } else {
            // Если произошла ошибка
            alert("Ошибка: " + result.error); // Показываем сообщение об ошибке
          }
        })
        .catch((error) => {
          // Обрабатываем ошибки AJAX-запроса
          console.error("Ошибка при добавлении события:", error);
        });
    });
});

// Функция открытия модального окна с деталями события
function openEventModal(info) {
  // Заполняем данные события в модальном окне
  document.querySelector('[data-kt-calendar="cnc_event_name"]').textContent =
    info.event.title || "Без названия";
  document.querySelector(
    '[data-kt-calendar="cnc_event_description"]'
  ).textContent = info.event.extendedProps.description || "Нет описания";
  document.querySelector(
    '[data-kt-calendar="cnc_event_location"]'
  ).textContent = info.event.extendedProps.location || "Не указано";

  // Форматируем даты и время для отображения
  const startDate = info.event.start.toLocaleDateString("ru-RU");
  const endDate = info.event.end
    ? info.event.end.toLocaleDateString("ru-RU")
    : "Не указано";
  const startTime = info.event.allDay
    ? ""
    : info.event.start.toLocaleTimeString("ru-RU", {
        hour: "2-digit",
        minute: "2-digit"
      });
  const endTime =
    info.event.allDay || !info.event.end
      ? ""
      : info.event.end.toLocaleTimeString("ru-RU", {
          hour: "2-digit",
          minute: "2-digit"
        });

  // Отображаем даты и время в модальном окне
  document.querySelector(
    '[data-kt-calendar="cnc_event_start_date"]'
  ).textContent = startDate + (startTime ? ` ${startTime}` : "");
  document.querySelector(
    '[data-kt-calendar="cnc_event_end_date"]'
  ).textContent = endDate + (endTime ? ` ${endTime}` : "");

  // Открываем модальное окно с помощью Bootstrap
  var eventModal = new bootstrap.Modal(
    document.getElementById("kt_modal_view_event")
  );
  eventModal.show();
}

// Функция обновления события после перемещения или изменения размера
function updateEvent(info) {
  // Создаём объект FormData для отправки данных на сервер
  var formData = new FormData();
  formData.append("event_id", info.event.id); // ID события для идентификации в базе

  // Функция форматирования даты и времени для отправки на сервер
  const formatDateTime = (date) => {
    if (!date) return null; // Если дата отсутствует, возвращаем null
    if (info.event.allDay) {
      // Если событие цельнодневное
      return date.toISOString().split("T")[0]; // Формат: ГГГГ-ММ-ДД
    }
    // Формат с временем: ГГГГ-ММ-ДД ЧЧ:ММ:СС
    return date.toISOString().slice(0, 19).replace("T", " ");
  };

  // Получаем новые даты начала и окончания события
  const newStart = formatDateTime(info.event.start);
  let newEnd = formatDateTime(info.event.end);

  // Если событие не имеет конца (однодневное), используем дату начала как конец
  if (!newEnd && info.event.allDay) {
    newEnd = newStart;
  } else if (!newEnd && !info.event.allDay) {
    // Если событие с временем, но конец не указан, можно установить значение по умолчанию
    const originalEvent = calendar.getEventById(info.event.id);
    const originalEndTime = originalEvent.end
      ? originalEvent.end.toISOString().slice(11, 16)
      : "17:20"; // Например, "17:20"
    newEnd = `${newStart.split(" ")[0]} ${originalEndTime}:00`;
  }

  // Добавляем новые даты в FormData
  formData.append("new_start_date", newStart);
  formData.append("new_end_date", newEnd);

  // Отправляем запрос на сервер для обновления события
  fetch("update_event.php", {
    method: "POST", // Метод POST
    body: formData // Данные формы
  })
    .then((response) => response.json()) // Парсим ответ как JSON
    .then((result) => {
      if (result.success) {
        // Если сервер подтвердил успешное обновление
        // Показываем уведомление об успешном обновлении
        showAlert(
          "Событие обновлено",
          "Событие успешно обновлено в базе данных!"
        );
      } else {
        // Если произошла ошибка на сервере
        console.error("Ошибка при обновлении:", result.error); // Логируем ошибку
        info.revert(); // Откатываем изменения в календаре
        showAlert("Ошибка", "Не удалось обновить событие: " + result.error); // Уведомление об ошибке
      }
    })
    .catch((error) => {
      // Обрабатываем ошибки сетевого запроса
      console.error("Ошибка AJAX:", error);
      info.revert(); // Откатываем изменения
      showAlert("Ошибка", "Произошла ошибка при обновлении события."); // Уведомление об ошибке
    });
}

// Убедимся, что обработчики вызывают updateEvent корректно
var calendar = new FullCalendar.Calendar(calendarContainer, {
  // ... (остальные настройки остаются без изменений)
  eventDrop: function (info) {
    // Обработчик перетаскивания события
    console.log("Перемещение:", info.event.start, info.event.end); // Логируем для отладки
    updateEvent(info); // Вызываем функцию обновления
  },
  eventResize: function (info) {
    // Обработчик изменения размера события
    console.log("Растягивание:", info.event.start, info.event.end); // Логируем для отладки
    updateEvent(info); // Вызываем функцию обновления
  }
  // ... (остальные настройки)
});

// Функция отображения уведомления на странице
function showAlert(title, message) {
  // Создаём HTML-код для уведомления
  var alertHtml = `
        <div class="alert alert-dismissible bg-light-primary border border-primary d-flex flex-column flex-sm-row p-5 mb-10 position-fixed top-0 end-0 m-3 shadow" style="z-index: 1050;">
            <i class="ki-duotone ki-search-list fs-2hx text-success me-4 mb-5 mb-sm-0"></i>
            <div class="d-flex flex-column pe-0 pe-sm-10">
                <h5 class="mb-1">${title}</h5>
                <span>${message}</span>
            </div>
            <button type="button" class="btn btn-icon ms-sm-auto" data-bs-dismiss="alert">
                <i class="ki-duotone ki-cross fs-1 text-success"></i>
            </button>
        </div>
    `;

  // Создаём элемент и добавляем его в DOM
  var alertContainer = document.createElement("div");
  alertContainer.innerHTML = alertHtml;
  document.body.appendChild(alertContainer);

  // Удаляем уведомление через 5 секунд
  setTimeout(() => {
    alertContainer.remove();
  }, 5000);
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.