fix(dashboard): fix kebab menu delete/resync and status dot refresh
Kebab dropdown delete/resync used inlineConfirmAction which breaks inside Bootstrap dropdowns (dropdown closes on click, hiding confirm state). Replaced with confirm() dialog + direct async action with row feedback. Detail modal resync/delete/retry now trigger onStatusChange callback to refresh the orders table, so status dots update without page reload. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -572,6 +572,7 @@ function openDashOrderDetail(orderNumber) {
|
||||
_sharedModalQuickMapFn = openDashQuickMap;
|
||||
renderOrderDetailModal(orderNumber, {
|
||||
onQuickMap: openDashQuickMap,
|
||||
onStatusChange: loadDashOrders,
|
||||
onAfterRender: function() { /* nothing extra needed */ }
|
||||
});
|
||||
}
|
||||
@@ -598,67 +599,51 @@ function openDashQuickMap(sku, productName, orderNumber, itemIdx) {
|
||||
|
||||
// ── Dashboard row action handlers ────────────────
|
||||
|
||||
function dashResyncOrder(orderNumber, btn) {
|
||||
inlineConfirmAction(btn, '?', async (b) => {
|
||||
try {
|
||||
const res = await fetch(`/api/orders/${encodeURIComponent(orderNumber)}/resync`, { method: 'POST' });
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
b.innerHTML = '<i class="bi bi-check-circle"></i>';
|
||||
b.className = 'btn btn-xs btn-success';
|
||||
setTimeout(() => loadDashOrders(), 1500);
|
||||
} else {
|
||||
b.innerHTML = '<i class="bi bi-exclamation-triangle"></i>';
|
||||
b.className = 'btn btn-xs btn-danger';
|
||||
b.title = data.message || 'Eroare';
|
||||
setTimeout(() => {
|
||||
b.innerHTML = '<i class="bi bi-arrow-repeat"></i>';
|
||||
b.className = 'btn btn-xs btn-outline-warning';
|
||||
b.disabled = false;
|
||||
b.title = 'Resync';
|
||||
}, 3000);
|
||||
}
|
||||
} catch (err) {
|
||||
b.innerHTML = '<i class="bi bi-exclamation-triangle"></i>';
|
||||
b.disabled = false;
|
||||
async function dashResyncOrder(orderNumber, btn) {
|
||||
// Close dropdown immediately
|
||||
const dd = btn.closest('.dropdown-menu');
|
||||
if (dd) bootstrap.Dropdown.getInstance(dd.previousElementSibling)?.hide();
|
||||
// Find the table row for visual feedback
|
||||
const row = document.querySelector(`tr[data-order="${orderNumber}"]`) ||
|
||||
btn.closest('tr');
|
||||
try {
|
||||
if (row) row.style.opacity = '0.5';
|
||||
const res = await fetch(`/api/orders/${encodeURIComponent(orderNumber)}/resync`, { method: 'POST' });
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
loadDashOrders();
|
||||
} else {
|
||||
if (row) row.style.opacity = '';
|
||||
alert(data.message || 'Eroare la resync');
|
||||
}
|
||||
}, {
|
||||
defaultHtml: '<i class="bi bi-arrow-repeat"></i>',
|
||||
loadingText: '',
|
||||
confirmClass: 'btn-warning',
|
||||
defaultBtnClass: 'btn-outline-warning'
|
||||
});
|
||||
} catch (err) {
|
||||
if (row) row.style.opacity = '';
|
||||
alert('Eroare conexiune la resync');
|
||||
}
|
||||
}
|
||||
|
||||
function dashDeleteOrder(orderNumber, btn) {
|
||||
inlineConfirmAction(btn, '?', async (b) => {
|
||||
try {
|
||||
const res = await fetch(`/api/orders/${encodeURIComponent(orderNumber)}/delete`, { method: 'POST' });
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
b.innerHTML = '<i class="bi bi-check-circle"></i>';
|
||||
b.className = 'btn btn-xs btn-danger';
|
||||
setTimeout(() => loadDashOrders(), 1500);
|
||||
} else {
|
||||
b.innerHTML = '<i class="bi bi-exclamation-triangle"></i>';
|
||||
b.className = 'btn btn-xs btn-danger';
|
||||
b.title = data.message || 'Eroare';
|
||||
setTimeout(() => {
|
||||
b.innerHTML = '<i class="bi bi-trash"></i>';
|
||||
b.className = 'btn btn-xs btn-outline-danger';
|
||||
b.disabled = false;
|
||||
b.title = 'Sterge din ROA';
|
||||
}, 3000);
|
||||
}
|
||||
} catch (err) {
|
||||
b.innerHTML = '<i class="bi bi-exclamation-triangle"></i>';
|
||||
b.disabled = false;
|
||||
async function dashDeleteOrder(orderNumber, btn) {
|
||||
// Close dropdown immediately
|
||||
const dd = btn.closest('.dropdown-menu');
|
||||
if (dd) bootstrap.Dropdown.getInstance(dd.previousElementSibling)?.hide();
|
||||
// Confirm before delete
|
||||
if (!confirm(`Stergi comanda ${orderNumber} din ROA?`)) return;
|
||||
// Find the table row for visual feedback
|
||||
const row = document.querySelector(`tr[data-order="${orderNumber}"]`) ||
|
||||
btn.closest('tr');
|
||||
try {
|
||||
if (row) row.style.opacity = '0.5';
|
||||
const res = await fetch(`/api/orders/${encodeURIComponent(orderNumber)}/delete`, { method: 'POST' });
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
loadDashOrders();
|
||||
} else {
|
||||
if (row) row.style.opacity = '';
|
||||
alert(data.message || 'Eroare la stergere');
|
||||
}
|
||||
}, {
|
||||
defaultHtml: '<i class="bi bi-trash"></i>',
|
||||
loadingText: '',
|
||||
confirmClass: 'btn-danger',
|
||||
defaultBtnClass: 'btn-outline-danger'
|
||||
});
|
||||
} catch (err) {
|
||||
if (row) row.style.opacity = '';
|
||||
alert('Eroare conexiune la stergere');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -751,6 +751,7 @@ async function renderOrderDetailModal(orderNumber, opts) {
|
||||
if (data.success) {
|
||||
retryBtn.innerHTML = '<i class="bi bi-check-circle"></i> ' + (data.message || 'Reimportat');
|
||||
retryBtn.className = 'btn btn-sm btn-success';
|
||||
if (opts.onStatusChange) opts.onStatusChange();
|
||||
// Refresh modal after short delay
|
||||
setTimeout(() => renderOrderDetailModal(orderNumber, opts), 1500);
|
||||
} else {
|
||||
@@ -795,6 +796,7 @@ async function renderOrderDetailModal(orderNumber, opts) {
|
||||
if (data.success) {
|
||||
btn.innerHTML = '<i class="bi bi-check-circle"></i> Reimportat';
|
||||
btn.className = 'btn btn-sm btn-success';
|
||||
if (opts.onStatusChange) opts.onStatusChange();
|
||||
setTimeout(() => renderOrderDetailModal(orderNumber, opts), 1500);
|
||||
} else {
|
||||
btn.innerHTML = '<i class="bi bi-exclamation-triangle"></i> ' + (data.message || 'Eroare');
|
||||
@@ -845,6 +847,7 @@ async function renderOrderDetailModal(orderNumber, opts) {
|
||||
if (data.success) {
|
||||
btn.innerHTML = '<i class="bi bi-check-circle"></i> Sters';
|
||||
btn.className = 'btn btn-sm btn-danger';
|
||||
if (opts.onStatusChange) opts.onStatusChange();
|
||||
setTimeout(() => renderOrderDetailModal(orderNumber, opts), 1500);
|
||||
} else {
|
||||
btn.innerHTML = '<i class="bi bi-exclamation-triangle"></i> ' + (data.message || 'Eroare');
|
||||
|
||||
Reference in New Issue
Block a user