feat(ui): marketplace_external skeletons, empty states, toast notifications, Cmd+K
This commit is contained in:
@@ -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();
|
||||
});
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
<div class="meli-card" style="max-width:600px;">
|
||||
<h3 style="margin:0 0 var(--space-4);font-family:var(--font-heading);">Conexión con MercadoLibre</h3>
|
||||
<div id="configStatus">
|
||||
<p>Cargando estado...</p>
|
||||
<div class="skeleton skeleton--text" style="width:120px;"></div>
|
||||
</div>
|
||||
<div id="configForm" style="display:none;margin-top:var(--space-4);">
|
||||
<p style="margin-bottom:var(--space-3);font-size:var(--text-body-sm);color:var(--color-text-secondary);">
|
||||
@@ -316,8 +316,9 @@
|
||||
|
||||
<script src="/pos/static/js/i18n.js" defer></script>
|
||||
<script src="/pos/static/js/app-init.js" defer></script>
|
||||
<script src="/pos/static/js/pos-utils.js?v=2" defer></script>
|
||||
<script src="/pos/static/js/sidebar.js" defer></script>
|
||||
<script src="/pos/static/js/marketplace_external.js?v=3" defer></script>
|
||||
<script src="/pos/static/js/marketplace_external.js?v=4" defer></script>
|
||||
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user