fix(products): improve bulk category modal and batch selection handling
- Add null check for selectAllCheckbox to avoid errors in batch-selection.js - Replace clear existing categories toggle with radio buttons for add, replace, and clear modes - Disable category search input and fade category list when 'clear' mode is selected - Update mode hint text dynamically based on selected mode with explanatory messages - Enable apply button when 'clear' mode is selected regardless of category selection - Remove clear all categories button from modal footer - Add event listeners for mode radio buttons to update UI and error states on change - Initialize mode UI and apply button state on modal setup - Bump static JS files versions for batch-selection and bulk-category-modal to 1.2 and 1.4 respectively
This commit is contained in:
@@ -101,6 +101,11 @@
|
|||||||
* Update the "Select All" checkbox state based on individual checkboxes
|
* Update the "Select All" checkbox state based on individual checkboxes
|
||||||
*/
|
*/
|
||||||
function updateSelectAllCheckbox() {
|
function updateSelectAllCheckbox() {
|
||||||
|
// Проверяем наличие чекбокса перед работой с ним
|
||||||
|
if (!selectAllCheckbox) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const itemCheckboxes = document.querySelectorAll('.item-checkbox');
|
const itemCheckboxes = document.querySelectorAll('.item-checkbox');
|
||||||
const totalCheckboxes = itemCheckboxes.length;
|
const totalCheckboxes = itemCheckboxes.length;
|
||||||
const checkedCheckboxes = document.querySelectorAll('.item-checkbox:checked').length;
|
const checkedCheckboxes = document.querySelectorAll('.item-checkbox:checked').length;
|
||||||
|
|||||||
@@ -15,13 +15,13 @@
|
|||||||
const modal = document.getElementById('bulkCategoryModal');
|
const modal = document.getElementById('bulkCategoryModal');
|
||||||
const bulkCategoryAction = document.getElementById('bulk-category-action');
|
const bulkCategoryAction = document.getElementById('bulk-category-action');
|
||||||
const applyBtn = document.getElementById('applyBulkCategoriesBtn');
|
const applyBtn = document.getElementById('applyBulkCategoriesBtn');
|
||||||
const clearAllBtn = document.getElementById('clearAllCategoriesBtn');
|
|
||||||
const categoryListContainer = document.getElementById('categoryListContainer');
|
const categoryListContainer = document.getElementById('categoryListContainer');
|
||||||
const categorySearchInput = document.getElementById('categorySearchInput');
|
const categorySearchInput = document.getElementById('categorySearchInput');
|
||||||
const clearExistingToggle = document.getElementById('clearExistingCategoriesToggle');
|
|
||||||
const errorAlert = document.getElementById('bulkCategoryError');
|
const errorAlert = document.getElementById('bulkCategoryError');
|
||||||
const selectedItemsCountSpan = document.getElementById('selectedItemsCount');
|
const selectedItemsCountSpan = document.getElementById('selectedItemsCount');
|
||||||
const selectedItemsBreakdownSpan = document.getElementById('selectedItemsBreakdown');
|
const selectedItemsBreakdownSpan = document.getElementById('selectedItemsBreakdown');
|
||||||
|
const modeHint = document.getElementById('bulkCategoryModeHint');
|
||||||
|
const categoryListSection = document.getElementById('bulkCategoryListSection');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the bulk category modal functionality
|
* Initialize the bulk category modal functionality
|
||||||
@@ -38,12 +38,27 @@
|
|||||||
// Event listeners
|
// Event listeners
|
||||||
bulkCategoryAction.addEventListener('click', handleOpenModal);
|
bulkCategoryAction.addEventListener('click', handleOpenModal);
|
||||||
applyBtn.addEventListener('click', handleApply);
|
applyBtn.addEventListener('click', handleApply);
|
||||||
clearAllBtn.addEventListener('click', handleClearAll);
|
if (categorySearchInput) {
|
||||||
categorySearchInput.addEventListener('input', handleCategorySearch);
|
categorySearchInput.addEventListener('input', handleCategorySearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for mode changes
|
||||||
|
const modeRadios = document.querySelectorAll('input[name="bulkCategoryMode"]');
|
||||||
|
modeRadios.forEach(radio => {
|
||||||
|
radio.addEventListener('change', () => {
|
||||||
|
hideError();
|
||||||
|
updateModeUI();
|
||||||
|
updateApplyButtonState();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Listen for modal close to reset state
|
// Listen for modal close to reset state
|
||||||
modal.addEventListener('hidden.bs.modal', resetModalState);
|
modal.addEventListener('hidden.bs.modal', resetModalState);
|
||||||
|
|
||||||
|
// Initial UI state
|
||||||
|
updateModeUI();
|
||||||
|
updateApplyButtonState();
|
||||||
|
|
||||||
console.log('Bulk category modal initialized');
|
console.log('Bulk category modal initialized');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +135,43 @@
|
|||||||
selectedItemsBreakdownSpan.textContent = breakdown;
|
selectedItemsBreakdownSpan.textContent = breakdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current mode: add | replace | clear
|
||||||
|
*/
|
||||||
|
function getCurrentMode() {
|
||||||
|
const checked = document.querySelector('input[name="bulkCategoryMode"]:checked');
|
||||||
|
return checked ? checked.value : 'add';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update UI depending on selected mode
|
||||||
|
*/
|
||||||
|
function updateModeUI() {
|
||||||
|
const mode = getCurrentMode();
|
||||||
|
|
||||||
|
if (categorySearchInput) {
|
||||||
|
categorySearchInput.disabled = (mode === 'clear');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (categoryListSection) {
|
||||||
|
if (mode === 'clear') {
|
||||||
|
categoryListSection.classList.add('opacity-50');
|
||||||
|
} else {
|
||||||
|
categoryListSection.classList.remove('opacity-50');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modeHint) {
|
||||||
|
if (mode === 'add') {
|
||||||
|
modeHint.textContent = 'Добавленные категории будут присоединены к уже существующим.';
|
||||||
|
} else if (mode === 'replace') {
|
||||||
|
modeHint.textContent = 'Существующие категории будут полностью заменены выбранными ниже.';
|
||||||
|
} else if (mode === 'clear') {
|
||||||
|
modeHint.textContent = 'Все категории будут удалены. Список ниже будет проигнорирован.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load categories from server
|
* Load categories from server
|
||||||
*/
|
*/
|
||||||
@@ -265,9 +317,16 @@
|
|||||||
* Update apply button state
|
* Update apply button state
|
||||||
*/
|
*/
|
||||||
function updateApplyButtonState() {
|
function updateApplyButtonState() {
|
||||||
// Кнопка Применить активна только если выбрана хотя бы одна категория
|
const mode = getCurrentMode();
|
||||||
|
|
||||||
|
if (mode === 'clear') {
|
||||||
|
// В режиме очистки категории не требуются
|
||||||
|
applyBtn.disabled = false;
|
||||||
|
} else {
|
||||||
|
// Для add/replace нужна хотя бы одна выбранная категория
|
||||||
applyBtn.disabled = selectedCategoryIds.size === 0;
|
applyBtn.disabled = selectedCategoryIds.size === 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle apply button click
|
* Handle apply button click
|
||||||
|
|||||||
@@ -415,22 +415,41 @@
|
|||||||
<span id="selectedItemsBreakdown" class="ms-2 text-muted"></span>
|
<span id="selectedItemsBreakdown" class="ms-2 text-muted"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Опции применения -->
|
<!-- Режим изменения категорий -->
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<div class="form-check form-switch">
|
<label class="form-label fw-bold">Что сделать с категориями выбранных товаров?</label>
|
||||||
<input class="form-check-input" type="checkbox" id="clearExistingCategoriesToggle" role="switch">
|
|
||||||
<label class="form-check-label" for="clearExistingCategoriesToggle">
|
<div class="form-check">
|
||||||
<i class="bi bi-trash"></i> Очистить существующие категории перед сохранением
|
<input class="form-check-input" type="radio" name="bulkCategoryMode"
|
||||||
|
id="bulkCategoryModeAdd" value="add" checked>
|
||||||
|
<label class="form-check-label" for="bulkCategoryModeAdd">
|
||||||
|
Добавить выбранные категории к существующим
|
||||||
</label>
|
</label>
|
||||||
<div class="form-text text-warning">
|
|
||||||
<i class="bi bi-exclamation-triangle"></i>
|
|
||||||
При включении все текущие категории товаров будут удалены, а затем применены только выбранные ниже
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mt-2">
|
||||||
|
<input class="form-check-input" type="radio" name="bulkCategoryMode"
|
||||||
|
id="bulkCategoryModeReplace" value="replace">
|
||||||
|
<label class="form-check-label" for="bulkCategoryModeReplace">
|
||||||
|
Заменить существующие категории выбранными
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mt-2">
|
||||||
|
<input class="form-check-input" type="radio" name="bulkCategoryMode"
|
||||||
|
id="bulkCategoryModeClear" value="clear">
|
||||||
|
<label class="form-check-label text-danger" for="bulkCategoryModeClear">
|
||||||
|
<strong>Удалить все категории</strong>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="bulkCategoryModeHint" class="form-text text-muted mt-2">
|
||||||
|
Добавленные категории будут присоединены к уже существующим.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Выбор категорий -->
|
<!-- Выбор категорий -->
|
||||||
<div class="mb-3">
|
<div class="mb-3" id="bulkCategoryListSection">
|
||||||
<label class="form-label fw-bold">Выберите категории:</label>
|
<label class="form-label fw-bold">Выберите категории:</label>
|
||||||
|
|
||||||
<!-- Поиск по категориям -->
|
<!-- Поиск по категориям -->
|
||||||
@@ -452,9 +471,6 @@
|
|||||||
<div id="bulkCategoryError" class="alert alert-danger d-none" role="alert"></div>
|
<div id="bulkCategoryError" class="alert alert-danger d-none" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-danger me-auto" id="clearAllCategoriesBtn">
|
|
||||||
<i class="bi bi-trash3"></i> Очистить все категории
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||||
<i class="bi bi-x-circle"></i> Отмена
|
<i class="bi bi-x-circle"></i> Отмена
|
||||||
</button>
|
</button>
|
||||||
@@ -469,6 +485,6 @@
|
|||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<script src="{% static 'products/js/batch-selection.js' %}?v=1.1"></script>
|
<script src="{% static 'products/js/batch-selection.js' %}?v=1.2"></script>
|
||||||
<script src="{% static 'products/js/bulk-category-modal.js' %}?v=1.3"></script>
|
<script src="{% static 'products/js/bulk-category-modal.js' %}?v=1.4"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user