feat(ui): marketplace_external skeletons, empty states, toast notifications, Cmd+K

This commit is contained in:
2026-05-26 08:44:09 +00:00
parent 7020890b0e
commit 031c190635
2 changed files with 41 additions and 14 deletions

View File

@@ -105,7 +105,9 @@
window.loadListings = async function() {
var container = document.getElementById('listingsContainer');
container.innerHTML = '<p>Cargando...</p>';
container.innerHTML = '<div class="meli-card"><div class="skeleton skeleton--text"></div><div class="skeleton skeleton--text-sm" style="width:70%;"></div></div>'
+ '<div class="meli-card"><div class="skeleton skeleton--text"></div><div class="skeleton skeleton--text-sm" style="width:60%;"></div></div>'
+ '<div class="meli-card"><div class="skeleton skeleton--text"></div><div class="skeleton skeleton--text-sm" style="width:80%;"></div></div>';
try {
var res = await fetch(API + '/listings?page=1&per_page=50', { headers: headers() });
if (!res.ok) throw new Error('Failed to load listings');
@@ -113,7 +115,11 @@
listingsData = data.items || [];
renderListings();
} catch (e) {
container.innerHTML = '<p style="color:var(--color-danger);">Error cargando publicaciones</p>';
container.innerHTML = renderEmptyState({
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><path d="M8 21h8M12 17v4"/></svg>',
title: 'Error cargando publicaciones',
subtitle: 'No se pudieron obtener las publicaciones de MercadoLibre. Intenta de nuevo.'
});
}
};
@@ -129,7 +135,12 @@
});
if (!filtered.length) {
container.innerHTML = '<p style="color:var(--color-text-muted);padding:var(--space-4);">No hay publicaciones. Ve a Inventario y publica un producto.</p>';
container.innerHTML = renderEmptyState({
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><path d="M8 21h8M12 17v4"/></svg>',
title: 'Sin publicaciones',
subtitle: 'Aún no hay publicaciones en MercadoLibre. Ve a Inventario y publica un producto.',
action: '<a href="/pos/inventory" class="btn btn--meli btn--sm">Ir a Inventario</a>'
});
return;
}
@@ -159,13 +170,13 @@
var res = await fetch(API + '/listings/' + id + '/sync', { method: 'POST', headers: headers() });
var data = await res.json();
if (res.ok) {
alert('Sincronizado: $' + data.price + ' · Stock: ' + data.stock);
showToast('Sincronizado: $' + data.price + ' · Stock: ' + data.stock, 'ok', { title: 'Publicación actualizada' });
loadListings();
} else {
alert('Error: ' + (data.error || 'Unknown'));
showToast(data.error || 'Error desconocido', 'error', { title: 'Error de sincronización' });
}
} catch (e) {
alert('Error: ' + e.message);
showToast(e.message, 'error', { title: 'Error de red' });
}
};
@@ -197,7 +208,7 @@
window.loadOrders = async function() {
var tbody = document.getElementById('ordersTableBody');
tbody.innerHTML = '<tr><td colspan="6">Cargando...</td></tr>';
tbody.innerHTML = renderSkeletonRows(6, 5);
try {
var res = await fetch(API + '/orders?page=1&per_page=50', { headers: headers() });
if (!res.ok) throw new Error('Failed to load orders');
@@ -205,7 +216,11 @@
ordersData = data.items || [];
renderOrders();
} catch (e) {
tbody.innerHTML = '<tr><td colspan="6" style="color:var(--color-danger)">Error cargando órdenes</td></tr>';
tbody.innerHTML = '<tr><td colspan="6">' + renderEmptyState({
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><path d="M8 21h8M12 17v4"/></svg>',
title: 'Error cargando órdenes',
subtitle: 'No se pudieron obtener las órdenes de MercadoLibre.'
}) + '</td></tr>';
}
};
@@ -221,7 +236,11 @@
});
if (!filtered.length) {
tbody.innerHTML = '<tr><td colspan="6" style="color:var(--color-text-muted)">No hay órdenes.</td></tr>';
tbody.innerHTML = '<tr><td colspan="6">' + renderEmptyState({
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><path d="M8 21h8M12 17v4"/></svg>',
title: 'Sin órdenes',
subtitle: 'No hay órdenes de MercadoLibre en este momento.'
}) + '</td></tr>';
return;
}
@@ -296,13 +315,13 @@
});
var data = await res.json();
if (res.ok) {
alert('Orden convertida a venta #' + data.sale_id);
showToast('Orden convertida a venta #' + data.sale_id, 'ok', { title: 'Venta creada' });
loadOrders();
} else {
alert('Error: ' + (data.error || 'Unknown'));
showToast(data.error || 'Error desconocido', 'error', { title: 'Error al convertir' });
}
} catch (e) {
alert('Error: ' + e.message);
showToast(e.message, 'error', { title: 'Error de red' });
}
};
@@ -361,6 +380,13 @@
})();
}
// Register Cmd+K items
if (typeof registerCmdKItem === 'function') {
registerCmdKItem({ group: 'MercadoLibre', label: 'Configuración ML', href: '/pos/marketplace-external', icon: '⚙️' });
registerCmdKItem({ group: 'MercadoLibre', label: 'Publicaciones ML', href: '/pos/marketplace-external#listings', icon: '📦' });
registerCmdKItem({ group: 'MercadoLibre', label: 'Órdenes ML', href: '/pos/marketplace-external#orders', icon: '🛒' });
}
document.addEventListener('DOMContentLoaded', function() {
loadConfig();
});