diff --git a/resources/js/categories.js b/resources/js/categories.js index 22db55d..91c6263 100644 --- a/resources/js/categories.js +++ b/resources/js/categories.js @@ -104,6 +104,19 @@ function createTreeNode(node, source = 'm2') { label.appendChild(labelText); label.appendChild(badge); + // Add rename button for Magento 2 categories only (except system root) + if (canDelete && source === 'm2') { + const renameBtn = document.createElement('button'); + renameBtn.className = 'tree-rename-btn'; + renameBtn.textContent = 'Rename'; + renameBtn.title = 'Rename this category'; + renameBtn.onclick = function(e) { + e.stopPropagation(); + startRenameCategory(nodeDiv, node, source); + }; + label.appendChild(renameBtn); + } + if (canDelete) { const deleteBtn = document.createElement('button'); deleteBtn.className = 'tree-delete-btn'; @@ -253,6 +266,7 @@ function deleteCategory(categoryId, categoryName, source) { loadM1Tree(); } else { loadM2Tree(); + // Reload page to refresh statistics and M2 Categories Not Found in M1 section location.reload(); } } else { @@ -266,3 +280,260 @@ function deleteCategory(categoryId, categoryName, source) { }); } +// Start renaming a category +function startRenameCategory(nodeDiv, node, source) { + const label = nodeDiv.querySelector('.tree-label'); + const labelText = label.querySelector('.tree-label-text'); + const originalName = node.name || 'Unnamed Category'; + + // Hide the label text and badge + labelText.style.display = 'none'; + const badge = label.querySelector('.tree-badge'); + if (badge) badge.style.display = 'none'; + + // Hide rename and delete buttons + const renameBtn = label.querySelector('.tree-rename-btn'); + const deleteBtn = label.querySelector('.tree-delete-btn'); + if (renameBtn) renameBtn.style.display = 'none'; + if (deleteBtn) deleteBtn.style.display = 'none'; + + // Create input field + const input = document.createElement('input'); + input.type = 'text'; + input.className = 'tree-rename-input'; + input.value = originalName; + input.onclick = function(e) { + e.stopPropagation(); + }; + + // Create action buttons + const actionsDiv = document.createElement('div'); + actionsDiv.className = 'tree-rename-actions'; + + const saveBtn = document.createElement('button'); + saveBtn.className = 'tree-rename-save-btn'; + saveBtn.textContent = 'Save'; + saveBtn.onclick = function(e) { + e.stopPropagation(); + saveRenameCategory(nodeDiv, node, input.value, source); + }; + + const cancelBtn = document.createElement('button'); + cancelBtn.className = 'tree-rename-cancel-btn'; + cancelBtn.textContent = 'Cancel'; + cancelBtn.onclick = function(e) { + e.stopPropagation(); + cancelRenameCategory(nodeDiv, labelText, badge, renameBtn, deleteBtn); + }; + + actionsDiv.appendChild(saveBtn); + actionsDiv.appendChild(cancelBtn); + + label.appendChild(input); + label.appendChild(actionsDiv); + + // Focus and select input + input.focus(); + input.select(); + + // Handle Enter and Escape keys + input.onkeydown = function(e) { + if (e.key === 'Enter') { + e.preventDefault(); + saveRenameCategory(nodeDiv, node, input.value, source); + } else if (e.key === 'Escape') { + e.preventDefault(); + cancelRenameCategory(nodeDiv, labelText, badge, renameBtn, deleteBtn); + } + }; +} + +// Save category rename +function saveRenameCategory(nodeDiv, node, newName, source) { + const categoryId = node.id; + const label = nodeDiv.querySelector('.tree-label'); + const input = label.querySelector('.tree-rename-input'); + const actionsDiv = label.querySelector('.tree-rename-actions'); + + if (!newName || newName.trim() === '') { + alert('Category name cannot be empty'); + return; + } + + // Disable input and buttons + input.disabled = true; + const saveBtn = actionsDiv.querySelector('.tree-rename-save-btn'); + const cancelBtn = actionsDiv.querySelector('.tree-rename-cancel-btn'); + if (saveBtn) saveBtn.disabled = true; + if (cancelBtn) cancelBtn.disabled = true; + + const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content; + const renameRoute = routes.renameCategory.replace(':id', categoryId); + + fetch(renameRoute, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': csrfToken + }, + body: JSON.stringify({ name: newName.trim() }) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + // Update the node name + node.name = data.new_name; + + // Update the label text + const labelText = label.querySelector('.tree-label-text'); + labelText.textContent = `[${node.id}] ${data.new_name}`; + + // Restore display + labelText.style.display = ''; + const badge = label.querySelector('.tree-badge'); + if (badge) badge.style.display = ''; + const renameBtn = label.querySelector('.tree-rename-btn'); + const deleteBtn = label.querySelector('.tree-delete-btn'); + if (renameBtn) renameBtn.style.display = ''; + if (deleteBtn) deleteBtn.style.display = ''; + + // Remove input and actions + label.removeChild(input); + label.removeChild(actionsDiv); + + // Reload M2 Categories Not Found in M1 section + loadM2CategoriesNotInM1(); + } else { + alert('Error: ' + (data.message || 'Failed to rename category')); + // Re-enable input and buttons + input.disabled = false; + if (saveBtn) saveBtn.disabled = false; + if (cancelBtn) cancelBtn.disabled = false; + } + }) + .catch(error => { + alert('Error: ' + error.message); + // Re-enable input and buttons + input.disabled = false; + if (saveBtn) saveBtn.disabled = false; + if (cancelBtn) cancelBtn.disabled = false; + }); +} + +// Cancel category rename +function cancelRenameCategory(nodeDiv, labelText, badge, renameBtn, deleteBtn) { + const label = nodeDiv.querySelector('.tree-label'); + const input = label.querySelector('.tree-rename-input'); + const actionsDiv = label.querySelector('.tree-rename-actions'); + + // Restore display + labelText.style.display = ''; + if (badge) badge.style.display = ''; + if (renameBtn) renameBtn.style.display = ''; + if (deleteBtn) deleteBtn.style.display = ''; + + // Remove input and actions + if (input) label.removeChild(input); + if (actionsDiv) label.removeChild(actionsDiv); +} + +// Load M2 Categories Not Found in M1 section +function loadM2CategoriesNotInM1() { + const tbody = document.getElementById('m2-categories-not-in-m1-tbody'); + const wrapper = document.getElementById('m2-categories-not-in-m1-table-wrapper'); + const totalDiv = document.getElementById('m2-categories-not-in-m1-total'); + const emptyDiv = document.getElementById('m2-categories-not-in-m1-empty'); + + if (!tbody && !wrapper && !totalDiv && !emptyDiv) { + // Section doesn't exist on this page + return; + } + + fetch(routes.m2CategoriesNotInM1) + .then(response => response.json()) + .then(data => { + if (data.success) { + const categories = data.categories || []; + const count = data.count || 0; + + // Remove existing content + if (tbody) tbody.innerHTML = ''; + if (totalDiv) totalDiv.style.display = 'none'; + if (emptyDiv) emptyDiv.style.display = 'none'; + if (wrapper) wrapper.style.display = 'none'; + + if (count > 0) { + // Show table and populate it + if (wrapper) wrapper.style.display = 'block'; + if (totalDiv) { + totalDiv.style.display = 'block'; + totalDiv.innerHTML = `Total: ${count} ${count === 1 ? 'category' : 'categories'} found in Magento 2 but not in Magento 1.`; + } + + if (tbody) { + categories.forEach(category => { + const row = document.createElement('tr'); + row.style.borderBottom = '1px solid #dee2e6'; + + const activeClass = category.is_active ? 'active' : 'inactive'; + const activeText = category.is_active ? 'Active' : 'Inactive'; + + let rootCategoryHtml = 'N/A'; + if (category.root_category_name && category.root_category_name !== 'N/A') { + rootCategoryHtml = `${escapeHtml(category.root_category_name)}`; + if (category.root_category_id) { + rootCategoryHtml += ` (ID: ${category.root_category_id})`; + } + } + + // Create delete button with event listener + const deleteBtn = document.createElement('button'); + deleteBtn.className = 'tree-delete-btn'; + deleteBtn.textContent = 'Delete'; + deleteBtn.title = 'Delete this category'; + deleteBtn.onclick = function(e) { + e.stopPropagation(); + showDeleteConfirmPopup(deleteBtn, category.entity_id, category.name, 'm2', false, 0); + }; + + row.innerHTML = ` +