$(function () { var modalEl = document.getElementById('category-modal'); if (!modalEl) { return; } var modal = new bootstrap.Modal(modalEl); var $form = $('#category-form'); var $error = $('#category-form-error'); var archiveEl = document.getElementById('category-archive-modal'); var archiveModal = archiveEl ? new bootstrap.Modal(archiveEl) : null; var categoriesModalEl = document.getElementById('categories-modal'); var categoriesModal = categoriesModalEl ? new bootstrap.Modal(categoriesModalEl) : null; var groupModalEl = document.getElementById('group-modal'); var groupModal = groupModalEl ? new bootstrap.Modal(groupModalEl) : null; var $groupForm = $('#group-form'); var $groupError = $('#group-form-error'); // Внешняя модалка «Статьи» — обычный Bootstrap Modal, открывается поверх страницы /budgets; // add/edit (category-modal/group-modal) и архив (category-archive-modal) открываются уже // поверх неё — штатный для Bootstrap 5 стек модалок, закрытие/Escape/клик по backdrop у // каждой работает независимо через data-bs-dismiss/её собственный bootstrap.Modal instance. $(document).on('click', '.js-categories-open', function () { if (categoriesModal) { categoriesModal.show(); } }); function filterGroupOptions(type) { $('#category-group option[data-type]').each(function () { var match = $(this).data('type') === type; $(this).prop('hidden', !match).prop('disabled', !match); }); var $selected = $('#category-group option:selected'); if ($selected.data('type') && $selected.data('type') !== type) { $('#category-group').val(''); } } function toggleFormulaGroup(type) { $('#category-formula-group').toggle(type === 'income'); } function resetForm() { $form[0].reset(); $form.find('[name=id]').val(''); $error.hide().text(''); } $(document).on('click', '.js-category-add', function () { var type = $(this).data('type'); resetForm(); $form.data('mode', 'create').attr('action', '/categories/create'); $('#category-modal-title').text(type === 'income' ? 'Новая статья дохода' : 'Новая статья расхода'); $('#category-type').val(type); filterGroupOptions(type); toggleFormulaGroup(type); modal.show(); }); $(document).on('click', '.js-category-edit', function (e) { e.preventDefault(); var $row = $(this).closest('.category-row'); var type = $row.data('type'); resetForm(); $form.data('mode', 'edit').attr('action', '/categories/edit/' + $row.data('id')); $form.find('[name=title]').val($row.data('title')); $('#category-type').val(type); $('#category-modal-title').text('Редактировать статью'); filterGroupOptions(type); $('#category-group').val($row.data('group_id') || ''); toggleFormulaGroup(type); $('#category-linked').val($row.data('linked') || ''); $form.find('[name=formula_pct]').val($row.data('pct') || ''); modal.show(); }); $(document).on('click', '.js-category-archive-open', function () { if (archiveModal) { archiveModal.show(); } }); $(document).on('click', '.js-category-restore', function () { var $row = $(this).closest('.archive-row'); var csrf = $form.find('[name=csrf_token]').val(); $.post('/categories/restore/' + $row.data('id'), {csrf_token: csrf}) .done(function () { window.location.reload(); }) .fail(function () { window.alert('Не удалось восстановить статью'); }); }); $(document).on('click', '.js-category-delete', function (e) { e.preventDefault(); var $row = $(this).closest('.category-row'); var title = $row.data('title'); var csrf = $form.find('[name=csrf_token]').val(); if (!window.confirm('Архивировать статью «' + title + '»?')) { return; } $.post('/categories/delete/' + $row.data('id'), {csrf_token: csrf}) .done(function () { window.location.reload(); }) .fail(function () { window.alert('Не удалось архивировать статью'); }); }); $(document).on('submit', '#category-form', function (e) { e.preventDefault(); $error.hide().text(''); $.post($form.attr('action'), $form.serialize()) .done(function () { window.location.reload(); }) .fail(function (xhr) { var data = xhr.responseJSON; if (data && data.archived) { if (window.confirm('Статья «' + data.archived.title + '» уже есть в архиве. Восстановить её вместо создания новой?')) { var csrf = $form.find('[name=csrf_token]').val(); $.post('/categories/restore/' + data.archived.id, {csrf_token: csrf}) .done(function () { window.location.reload(); }) .fail(function () { window.alert('Не удалось восстановить статью'); }); } return; } var errors = data && data.errors; var message = errors ? Object.values(errors).join(' ') : 'Не удалось сохранить статью'; $error.text(message).show(); }); }); $(document).on('change', '.js-category-move', function () { var $select = $(this); var newGroup = $select.val(); if (newGroup === '') { return; } var $row = $select.closest('.category-row'); var csrf = $form.find('[name=csrf_token]').val(); $.post('/categories/edit/' + $row.data('id'), { csrf_token: csrf, title: $row.data('title'), type: $row.data('type'), group_id: newGroup, linked_expense_categorie_id: $row.data('linked') || '', formula_pct: $row.data('pct') || '' }) .done(function () { window.location.reload(); }) .fail(function (xhr) { var errors = xhr.responseJSON && xhr.responseJSON.errors; var message = errors ? Object.values(errors).join(' ') : 'Не удалось перенести статью'; window.alert(message); $select.val(''); }); }); // ---------- группы (App\Controller\CategoryGroupsController) ---------- $(document).on('click', '.js-group-add', function () { if (!groupModal) { return; } var type = $(this).data('type'); $groupForm[0].reset(); $groupForm.find('[name=id]').val(''); $groupError.hide().text(''); $groupForm.data('mode', 'create').attr('action', '/categorygroups/create'); $('#group-modal-title').text(type === 'income' ? 'Новая группа доходов' : 'Новая группа расходов'); $('#group-type').val(type); groupModal.show(); }); $(document).on('click', '.js-group-edit', function (e) { e.preventDefault(); if (!groupModal) { return; } var $row = $(this).closest('.category-row'); $groupForm[0].reset(); $groupError.hide().text(''); $groupForm.data('mode', 'edit').attr('action', '/categorygroups/edit/' + $row.data('id')); $groupForm.find('[name=title]').val($row.data('title')); $('#group-type').val($row.data('type')); $('#group-modal-title').text('Редактировать группу'); groupModal.show(); }); $(document).on('submit', '#group-form', function (e) { e.preventDefault(); $groupError.hide().text(''); $.post($groupForm.attr('action'), $groupForm.serialize()) .done(function () { window.location.reload(); }) .fail(function (xhr) { var data = xhr.responseJSON; if (data && data.archived) { if (window.confirm('Группа «' + data.archived.title + '» уже есть в архиве. Восстановить её вместо создания новой?')) { var csrf = $groupForm.find('[name=csrf_token]').val(); $.post('/categorygroups/restore/' + data.archived.id, {csrf_token: csrf}) .done(function () { window.location.reload(); }) .fail(function () { window.alert('Не удалось восстановить группу'); }); } return; } var errors = data && data.errors; var message = errors ? Object.values(errors).join(' ') : 'Не удалось сохранить группу'; $groupError.text(message).show(); }); }); $(document).on('click', '.js-group-delete', function (e) { e.preventDefault(); var $row = $(this).closest('.category-row'); var title = $row.data('title'); var csrf = $form.find('[name=csrf_token]').val(); if (!window.confirm('Архивировать группу «' + title + '»? Статьи внутри останутся, но без группы.')) { return; } $.post('/categorygroups/delete/' + $row.data('id'), {csrf_token: csrf}) .done(function () { window.location.reload(); }) .fail(function () { window.alert('Не удалось архивировать группу'); }); }); $(document).on('click', '.js-group-restore', function () { var $row = $(this).closest('.archive-row'); var csrf = $form.find('[name=csrf_token]').val(); $.post('/categorygroups/restore/' + $row.data('id'), {csrf_token: csrf}) .done(function () { window.location.reload(); }) .fail(function () { window.alert('Не удалось восстановить группу'); }); }); $(document).on('click', '.room-menu-btn', function () { $(this).closest('.room-menu').toggleClass('open'); }); $(document).on('click', function (e) { if (!$(e.target).closest('.room-menu').length) { $('.room-menu.open').removeClass('open'); } }); });