// Product URLs comparison functionality
let currentPage = 0;
let currentM1Page = 0;
let currentM2Page = 0;
const pageSize = 100;
let currentComparisonData = [];
let currentM1Data = [];
let currentM2Data = [];
let currentFilter = 'all';
// Compare URLs between M1 and M2
window.compareUrls = async function compareUrls() {
const sku = document.getElementById('skuFilter').value.trim();
const btn = document.getElementById('compareUrlsBtn');
btn.disabled = true;
btn.textContent = 'Comparing...';
try {
const response = await fetch(window.productUrlsRoutes.compareUrls + '?sku=' + encodeURIComponent(sku) + '&limit=' + pageSize + '&offset=' + (currentPage * pageSize), {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
}
});
const data = await response.json();
if (data.success) {
currentComparisonData = data.comparison;
displayComparison(data);
updateSummary(data.summary);
document.getElementById('comparisonSection').style.display = 'block';
document.getElementById('summarySection').style.display = 'block';
} else {
alert('Error: ' + data.message);
}
} catch (error) {
console.error('Error comparing URLs:', error);
alert('Failed to compare URLs: ' + error.message);
} finally {
btn.disabled = false;
btn.textContent = 'Compare URLs';
}
}
// Display comparison results
function displayComparison(data) {
const tbody = document.getElementById('comparisonTableBody');
tbody.innerHTML = '';
if (data.comparison.length === 0) {
tbody.innerHTML = '
| No results found |
';
return;
}
data.comparison.forEach(item => {
const row = document.createElement('tr');
const statusClass = getStatusClass(item.status);
const statusLabel = getStatusLabel(item.status);
row.innerHTML = `
${escapeHtml(item.sku || 'N/A')} |
${item.m1_product_id || '-'} |
${item.m2_product_id || '-'} |
${item.store_id || '-'} |
${escapeHtml(item.m1_url || '-')} |
${escapeHtml(item.m2_url || '-')} |
${statusLabel} |
`;
tbody.appendChild(row);
});
// Update pagination
updatePagination(data.total, currentPage);
document.getElementById('resultsCount').textContent = `Showing ${data.comparison.length} of ${data.total} results`;
}
// Update summary statistics
function updateSummary(summary) {
document.getElementById('summaryMatch').textContent = summary.match || 0;
document.getElementById('summaryMissingM2').textContent = summary.missing_in_m2 || 0;
document.getElementById('summaryMissingM1').textContent = summary.missing_in_m1 || 0;
document.getElementById('summaryDifferent').textContent = summary.different || 0;
}
// Get status class for styling
function getStatusClass(status) {
switch(status) {
case 'match': return 'status-match';
case 'missing_in_m2': return 'status-warning';
case 'missing_in_m1': return 'status-info';
case 'different': return 'status-error';
default: return '';
}
}
// Get status label
function getStatusLabel(status) {
switch(status) {
case 'match': return 'Match';
case 'missing_in_m2': return 'Missing in M2';
case 'missing_in_m1': return 'Missing in M1';
case 'different': return 'Different';
default: return status;
}
}
// Filter results by status
window.filterResults = function filterResults() {
const filter = document.getElementById('statusFilter').value;
currentFilter = filter;
// Re-fetch with filter (or filter client-side)
// For now, we'll filter client-side if we have all data
// In a real implementation, you might want to pass filter to the server
compareUrls();
}
// Load Magento 1 URLs
window.loadM1Urls = async function loadM1Urls() {
const sku = document.getElementById('skuFilter').value.trim();
const btn = document.getElementById('loadM1UrlsBtn');
btn.disabled = true;
btn.textContent = 'Loading...';
try {
const response = await fetch(window.productUrlsRoutes.getM1Urls + '?sku=' + encodeURIComponent(sku) + '&limit=' + pageSize + '&offset=' + (currentM1Page * pageSize), {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
}
});
const data = await response.json();
if (data.success) {
currentM1Data = data;
displayM1Urls(data);
document.getElementById('m1UrlsSection').style.display = 'block';
} else {
alert('Error: ' + data.message);
}
} catch (error) {
console.error('Error loading M1 URLs:', error);
alert('Failed to load M1 URLs: ' + error.message);
} finally {
btn.disabled = false;
btn.textContent = 'Load M1 URLs';
}
}
// Display M1 URLs
function displayM1Urls(data) {
const tbody = document.getElementById('m1UrlsTableBody');
tbody.innerHTML = '';
if (data.urls.length === 0) {
tbody.innerHTML = '| No URLs found |
';
return;
}
data.urls.forEach(item => {
const row = document.createElement('tr');
row.innerHTML = `
${item.entity_id || '-'} |
${escapeHtml(item.sku || 'N/A')} |
${item.store_id || '-'} |
${escapeHtml(item.request_path || '-')} |
${escapeHtml(item.target_path || '-')} |
`;
tbody.appendChild(row);
});
updateM1Pagination(data.total, currentM1Page);
}
// Load Magento 2 URLs
window.loadM2Urls = async function loadM2Urls() {
const sku = document.getElementById('skuFilter').value.trim();
const btn = document.getElementById('loadM2UrlsBtn');
btn.disabled = true;
btn.textContent = 'Loading...';
try {
const response = await fetch(window.productUrlsRoutes.getM2Urls + '?sku=' + encodeURIComponent(sku) + '&limit=' + pageSize + '&offset=' + (currentM2Page * pageSize), {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
}
});
const data = await response.json();
if (data.success) {
currentM2Data = data;
displayM2Urls(data);
document.getElementById('m2UrlsSection').style.display = 'block';
} else {
alert('Error: ' + data.message);
}
} catch (error) {
console.error('Error loading M2 URLs:', error);
alert('Failed to load M2 URLs: ' + error.message);
} finally {
btn.disabled = false;
btn.textContent = 'Load M2 URLs';
}
}
// Display M2 URLs
function displayM2Urls(data) {
const tbody = document.getElementById('m2UrlsTableBody');
tbody.innerHTML = '';
if (data.urls.length === 0) {
tbody.innerHTML = '| No URLs found |
';
return;
}
data.urls.forEach(item => {
const row = document.createElement('tr');
row.innerHTML = `
${item.entity_id || '-'} |
${escapeHtml(item.sku || 'N/A')} |
${item.store_id || '-'} |
${escapeHtml(item.request_path || '-')} |
${escapeHtml(item.target_path || '-')} |
`;
tbody.appendChild(row);
});
updateM2Pagination(data.total, currentM2Page);
}
// Pagination functions
window.changePage = function changePage(direction) {
currentPage += direction;
if (currentPage < 0) currentPage = 0;
compareUrls();
}
window.changeM1Page = function changeM1Page(direction) {
currentM1Page += direction;
if (currentM1Page < 0) currentM1Page = 0;
loadM1Urls();
}
window.changeM2Page = function changeM2Page(direction) {
currentM2Page += direction;
if (currentM2Page < 0) currentM2Page = 0;
loadM2Urls();
}
function updatePagination(total, currentPage) {
const totalPages = Math.ceil(total / pageSize);
const pageInfo = document.getElementById('pageInfo');
const prevBtn = document.getElementById('prevPageBtn');
const nextBtn = document.getElementById('nextPageBtn');
pageInfo.textContent = `Page ${currentPage + 1} of ${totalPages}`;
prevBtn.disabled = currentPage === 0;
nextBtn.disabled = currentPage >= totalPages - 1;
}
function updateM1Pagination(total, currentPage) {
const totalPages = Math.ceil(total / pageSize);
const pageInfo = document.getElementById('m1PageInfo');
const prevBtn = document.getElementById('m1PrevPageBtn');
const nextBtn = document.getElementById('m1NextPageBtn');
pageInfo.textContent = `Page ${currentPage + 1} of ${totalPages}`;
prevBtn.disabled = currentPage === 0;
nextBtn.disabled = currentPage >= totalPages - 1;
}
function updateM2Pagination(total, currentPage) {
const totalPages = Math.ceil(total / pageSize);
const pageInfo = document.getElementById('m2PageInfo');
const prevBtn = document.getElementById('m2PrevPageBtn');
const nextBtn = document.getElementById('m2NextPageBtn');
pageInfo.textContent = `Page ${currentPage + 1} of ${totalPages}`;
prevBtn.disabled = currentPage === 0;
nextBtn.disabled = currentPage >= totalPages - 1;
}
// Utility function to escape HTML
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Compare single product SKU
window.compareSingleSku = async function compareSingleSku() {
const sku = document.getElementById('singleSkuInput').value.trim();
const btn = document.getElementById('compareSingleSkuBtn');
const section = document.getElementById('singleProductComparisonSection');
const content = document.getElementById('singleProductComparisonContent');
if (!sku) {
alert('Please enter a product SKU');
return;
}
btn.disabled = true;
btn.textContent = 'Comparing...';
content.innerHTML = 'Loading...
';
section.style.display = 'block';
document.getElementById('singleSkuDisplay').textContent = sku;
try {
const response = await fetch(window.productUrlsRoutes.compareSingleSku + '?sku=' + encodeURIComponent(sku), {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
}
});
const data = await response.json();
if (data.success) {
displaySingleProductComparison(data);
} else {
content.innerHTML = 'Error: ' + escapeHtml(data.message) + '
';
}
} catch (error) {
console.error('Error comparing single SKU:', error);
content.innerHTML = 'Failed to compare URLs: ' + escapeHtml(error.message) + '
';
} finally {
btn.disabled = false;
btn.textContent = 'Compare Product URLs';
}
}
// Display single product comparison results
function displaySingleProductComparison(data) {
const content = document.getElementById('singleProductComparisonContent');
if (!data.comparison || data.comparison.length === 0) {
content.innerHTML = 'No URLs found for this product SKU.
';
return;
}
let html = '';
html += '
';
html += '
';
html += '
' + (data.summary.match || 0) + '
';
html += '
Matching Stores
';
html += '
';
html += '
' + (data.summary.missing_in_m2 || 0) + '
';
html += '
Missing in M2
';
html += '
';
html += '
' + (data.summary.missing_in_m1 || 0) + '
';
html += '
Missing in M1
';
html += '
';
html += '
' + (data.summary.different || 0) + '
';
html += '
Different URLs
';
html += '
';
html += '
';
html += '
Product IDs: M1: ' + (data.m1_product_id || 'N/A') + ' | M2: ' + (data.m2_product_id || 'N/A') + '
';
html += '
Total URLs: M1: ' + (data.summary.total_m1_urls || 0) + ' | M2: ' + (data.summary.total_m2_urls || 0) + ' | Stores: ' + (data.summary.total_stores || 0) + '
';
html += '
';
html += '
';
// Group by store
data.comparison.forEach(storeData => {
const statusClass = getStatusClass(storeData.status);
const statusLabel = getStatusLabel(storeData.status);
const storeId = storeData.store_id || 'Default';
html += '';
html += '
';
html += '
Store ID: ' + storeId + '
';
html += '
' + statusLabel + '
';
html += '
';
html += '
';
html += '
';
// Magento 1 URLs
html += '
';
html += '
Magento 1 URLs (' + (storeData.m1_urls.length || 0) + ')
';
if (storeData.m1_urls.length > 0) {
html += '
';
storeData.m1_urls.forEach((urlData, index) => {
html += '
';
html += '
URL ' + (index + 1) + ':
';
html += '
' + escapeHtml(urlData.url || '-') + '
';
if (urlData.target_path) {
html += '
Target: ' + escapeHtml(urlData.target_path) + '
';
}
html += '
';
});
html += '
';
} else {
html += '
No URLs found in Magento 1
';
}
html += '
';
// Magento 2 URLs
html += '
';
html += '
Magento 2 URLs (' + (storeData.m2_urls.length || 0) + ')
';
if (storeData.m2_urls.length > 0) {
html += '
';
storeData.m2_urls.forEach((urlData, index) => {
html += '
';
html += '
URL ' + (index + 1) + ':
';
html += '
' + escapeHtml(urlData.url || '-') + '
';
if (urlData.target_path) {
html += '
Target: ' + escapeHtml(urlData.target_path) + '
';
}
html += '
';
});
html += '
';
} else {
html += '
No URLs found in Magento 2
';
}
html += '
';
html += '
';
html += '
';
html += '
';
});
content.innerHTML = html;
}
// Allow Enter key to trigger search
document.addEventListener('DOMContentLoaded', function() {
const skuFilter = document.getElementById('skuFilter');
if (skuFilter) {
skuFilter.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
compareUrls();
}
});
}
const singleSkuInput = document.getElementById('singleSkuInput');
if (singleSkuInput) {
singleSkuInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
compareSingleSku();
}
});
}
});
// Fix / migrate product URLs from M1 to M2
window.fixProductUrls = async function fixProductUrls() {
const sku = document.getElementById('fixSkuInput').value.trim();
const dryRun = document.getElementById('fixDryRunInput').checked;
const btn = document.getElementById('fixUrlsBtn');
if (!dryRun && !confirm('This will INSERT URL rewrites into Magento 2. Continue?')) {
return;
}
btn.disabled = true;
btn.textContent = dryRun ? 'Previewing...' : 'Fixing...';
try {
const formData = new FormData();
if (sku) formData.append('sku', sku);
formData.append('dry_run', dryRun ? '1' : '0');
const response = await fetch(window.productUrlsRoutes.fixUrls, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
'Accept': 'application/json'
},
body: formData
});
const data = await response.json();
if (!data.success) {
alert('Error: ' + (data.message || 'unknown'));
return;
}
document.getElementById('fixAdded').textContent = data.added;
document.getElementById('fixAddedLabel').textContent = data.dry_run ? 'Would Add' : 'Added';
document.getElementById('fixSkippedExisting').textContent = data.skipped_existing;
document.getElementById('fixSkippedNoProduct').textContent = data.skipped_no_m2_product;
document.getElementById('fixErrors').textContent = data.errors;
document.getElementById('fixLogOutput').textContent =
(data.log || []).join('\n') ||
`(no log lines — ${data.total_m1_rewrites} M1 rewrites scanned)`;
document.getElementById('fixResultsSection').style.display = 'block';
} catch (error) {
console.error('fixProductUrls error:', error);
alert('Failed: ' + error.message);
} finally {
btn.disabled = false;
btn.textContent = 'Fix URLs';
}
};