Corp/backend/static/js/components/createPostModal.js
Игорь Надеин dd56953e89 Исправлена разметка и стили страницы профиля
- Заменен лишний div.container на стандартный container для единообразия
- Заменен класс .card на .ios-card в секции активности для устранения конфликтов стилей
- Добавлен card-list.css в base.html для корректного отображения карточек новостей
- Добавлены CSS правила для правильного поведения .row и колонок в grid-layout
- Исправлена проблема с выходом календаря за границы страницы
- Убраны видимые скроллбары у modal-body и modal-content для чистого UI
2025-11-29 13:52:21 +03:00

207 lines
6.7 KiB
JavaScript
Raw Permalink 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.

/**
* createPostModal.js
* Обработчик модального окна создания публикации через API
*/
export function initCreatePostModal(options = {}) {
const {
modalId = 'createPostModal',
formId = 'createPostForm',
errorsId = 'createPostErrors',
submitBtnId = 'createPostSubmit',
apiUrl = '/api/v1/posts/'
} = options;
const modal = document.getElementById(modalId);
const form = document.getElementById(formId);
const errorsDiv = document.getElementById(errorsId);
const submitBtn = document.getElementById(submitBtnId);
if (!modal || !form) {
console.error('Modal or form not found!', { modalId, formId });
return;
}
console.log('Create post modal initialized with API:', apiUrl);
// Получаем токен доступа
const accessMeta = document.querySelector('meta[name="api-access"]');
const ACCESS = accessMeta ? accessMeta.content : '';
const headers = ACCESS ? { 'Authorization': 'Bearer ' + ACCESS } : {};
// Маппинг полей для человекочитаемых названий
const fieldLabels = {
'title': 'Заголовок',
'body': 'Содержание',
'image': 'Изображение',
'attachment': 'Вложение',
'type': 'Тип публикации'
};
/**
* Очистка формы и ошибок
*/
function clearFormErrors() {
errorsDiv.classList.add('d-none');
errorsDiv.innerHTML = '';
form.querySelectorAll('.is-invalid').forEach(el => el.classList.remove('is-invalid'));
form.querySelectorAll('.invalid-feedback').forEach(el => el.remove());
}
/**
* Валидация обязательных полей
*/
function validateRequiredFields() {
const title = form.querySelector('[name="title"]');
const body = form.querySelector('[name="body"]');
let hasErrors = false;
if (!title.value.trim()) {
title.classList.add('is-invalid');
const feedback = document.createElement('div');
feedback.className = 'invalid-feedback';
feedback.textContent = 'Заголовок обязателен для заполнения';
title.parentElement.appendChild(feedback);
hasErrors = true;
}
if (!body.value.trim()) {
body.classList.add('is-invalid');
const feedback = document.createElement('div');
feedback.className = 'invalid-feedback';
feedback.textContent = 'Содержание обязательно для заполнения';
body.parentElement.appendChild(feedback);
hasErrors = true;
}
return !hasErrors;
}
/**
* Отображение ошибок по полям
*/
function displayFieldErrors(errors) {
const errorMessages = [];
for (const [fieldName, messages] of Object.entries(errors)) {
const field = form.querySelector(`[name="${fieldName}"]`);
const errorText = Array.isArray(messages) ? messages.join(', ') : messages;
const label = fieldLabels[fieldName] || fieldName;
errorMessages.push(`<strong>${label}:</strong> ${errorText}`);
if (field) {
field.classList.add('is-invalid');
const feedback = document.createElement('div');
feedback.className = 'invalid-feedback';
feedback.textContent = errorText;
field.parentElement.appendChild(feedback);
}
}
if (errorMessages.length > 0) {
errorsDiv.innerHTML = errorMessages.join('<br>');
errorsDiv.classList.remove('d-none');
}
}
/**
* Показать общее сообщение об ошибке
*/
function displayGeneralError(message) {
errorsDiv.textContent = message;
errorsDiv.classList.remove('d-none');
}
/**
* Показать уведомление об успехе
*/
function showSuccessNotification(message) {
const toast = document.createElement('div');
toast.className = 'toast align-items-center text-bg-success border-0 position-fixed top-0 start-50 translate-middle-x mt-3';
toast.setAttribute('role', 'alert');
toast.setAttribute('aria-live', 'assertive');
toast.setAttribute('aria-atomic', 'true');
toast.style.zIndex = '9999';
toast.innerHTML = `
<div class="d-flex">
<div class="toast-body">
<i class="bi-check-circle me-2"></i>${message}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
`;
document.body.appendChild(toast);
const bsToast = new bootstrap.Toast(toast, { delay: 3000 });
bsToast.show();
toast.addEventListener('hidden.bs.toast', () => {
toast.remove();
});
}
/**
* Отправка формы через API
*/
async function submitForm(e) {
e.preventDefault();
clearFormErrors();
if (!validateRequiredFields()) {
return false;
}
// Отключаем кнопку и показываем загрузку
submitBtn.disabled = true;
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Публикация...';
const formData = new FormData(form);
try {
// Для multipart/form-data НЕ передаём Content-Type, браузер установит сам с boundary
const fetchHeaders = ACCESS ? { 'Authorization': 'Bearer ' + ACCESS } : {};
const response = await fetch(apiUrl, {
method: 'POST',
headers: fetchHeaders,
body: formData
});
if (response.ok) {
showSuccessNotification('Публикация создана!');
bootstrap.Modal.getInstance(modal).hide();
form.reset();
// Перезагружаем страницу для отображения новой публикации
setTimeout(() => window.location.reload(), 500);
} else {
const error = await response.json();
if (typeof error === 'object' && error !== null) {
displayFieldErrors(error);
} else {
displayGeneralError('Ошибка создания публикации');
}
}
} catch (error) {
console.error('Error creating post:', error);
displayGeneralError('Ошибка сети при создании публикации');
} finally {
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
}
return false;
}
// Обработчик отправки формы
form.addEventListener('submit', submitForm);
// Очистка ошибок при открытии модала
modal.addEventListener('show.bs.modal', () => {
clearFormErrors();
form.reset();
});
}