Compare commits

..

2 Commits

Author SHA1 Message Date
Cauê Faleiros
a93068e86b Remove seller overview cards
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m30s
2026-08-11 09:25:31 -03:00
Cauê Faleiros
3664a94722 Avoid Olist detail render cascade 2026-08-11 09:25:31 -03:00
2 changed files with 9 additions and 35 deletions

View File

@@ -72,7 +72,7 @@ const OlistSync = () => {
}; };
}, [loadStatus]); }, [loadStatus]);
const loadRunDetails = useCallback(async (runId: number, pages = detailsPages) => { const loadRunDetails = useCallback(async (runId: number, pages: { events: number; products: number }) => {
setIsDetailsLoading(true); setIsDetailsLoading(true);
try { try {
setRunDetails(await fetchOlistRunDetails(runId, pages.events, pages.products)); setRunDetails(await fetchOlistRunDetails(runId, pages.events, pages.products));
@@ -81,18 +81,13 @@ const OlistSync = () => {
} finally { } finally {
setIsDetailsLoading(false); setIsDetailsLoading(false);
} }
}, [detailsPages]); }, []);
useEffect(() => {
if (!selectedRunId) return;
void loadRunDetails(selectedRunId);
}, [selectedRunId, detailsPages, loadRunDetails]);
useEffect(() => { useEffect(() => {
if (!selectedRunId || runDetails?.run.status !== 'running') return; if (!selectedRunId || runDetails?.run.status !== 'running') return;
const intervalId = window.setInterval(() => void loadRunDetails(selectedRunId), 5_000); const intervalId = window.setInterval(() => void loadRunDetails(selectedRunId, detailsPages), 5_000);
return () => window.clearInterval(intervalId); return () => window.clearInterval(intervalId);
}, [selectedRunId, runDetails?.run.status, loadRunDetails]); }, [selectedRunId, runDetails?.run.status, detailsPages, loadRunDetails]);
const latestRun = status?.runs[0] || null; const latestRun = status?.runs[0] || null;
const completionPercent = useMemo(() => { const completionPercent = useMemo(() => {
@@ -137,8 +132,10 @@ const OlistSync = () => {
}; };
const openRunDetails = (runId: number) => { const openRunDetails = (runId: number) => {
setDetailsPages({ events: 1, products: 1 }); const initialPages = { events: 1, products: 1 };
setDetailsPages(initialPages);
setSelectedRunId(runId); setSelectedRunId(runId);
void loadRunDetails(runId, initialPages);
}; };
if (isLoading && !status) { if (isLoading && !status) {
@@ -252,7 +249,7 @@ const OlistSync = () => {
{!runDetails.events.items.length && <p className="p-5 text-sm font-semibold text-dark-muted">Nenhum evento registrado ainda.</p>} {!runDetails.events.items.length && <p className="p-5 text-sm font-semibold text-dark-muted">Nenhum evento registrado ainda.</p>}
{runDetails.events.items.map(event => <div key={event.id} className="p-4"><div className="flex items-start gap-2"><span className={`mt-1.5 h-2 w-2 shrink-0 rounded-full ${event.level === 'error' ? 'bg-red-400' : 'bg-sky-400'}`} /><div className="min-w-0"><p className="text-sm font-semibold text-dark-text">{event.message}</p>{event.sku && <p className="mt-1 truncate text-xs font-bold text-brand-primary">{event.sku} · {event.productDescription}</p>}<p className="mt-1 text-[11px] font-semibold text-dark-muted">{formatDateTime(event.createdAt)}</p></div></div></div>)} {runDetails.events.items.map(event => <div key={event.id} className="p-4"><div className="flex items-start gap-2"><span className={`mt-1.5 h-2 w-2 shrink-0 rounded-full ${event.level === 'error' ? 'bg-red-400' : 'bg-sky-400'}`} /><div className="min-w-0"><p className="text-sm font-semibold text-dark-text">{event.message}</p>{event.sku && <p className="mt-1 truncate text-xs font-bold text-brand-primary">{event.sku} · {event.productDescription}</p>}<p className="mt-1 text-[11px] font-semibold text-dark-muted">{formatDateTime(event.createdAt)}</p></div></div></div>)}
</div> </div>
<div className="flex items-center justify-between border-t border-dark-border p-3"><button type="button" onClick={() => setDetailsPages(pages => ({ ...pages, events: Math.max(1, pages.events - 1) }))} disabled={runDetails.events.page === 1 || isDetailsLoading} className="text-xs font-bold text-dark-muted disabled:opacity-40 cursor-pointer">Anterior</button><span className="text-xs font-semibold text-dark-muted">Página {runDetails.events.page}</span><button type="button" onClick={() => setDetailsPages(pages => ({ ...pages, events: pages.events + 1 }))} disabled={runDetails.events.page * runDetails.events.pageSize >= runDetails.events.total || isDetailsLoading} className="text-xs font-bold text-brand-primary disabled:opacity-40 cursor-pointer">Próxima</button></div> <div className="flex items-center justify-between border-t border-dark-border p-3"><button type="button" onClick={() => { const pages = { ...detailsPages, events: Math.max(1, detailsPages.events - 1) }; setDetailsPages(pages); void loadRunDetails(runDetails.run.id, pages); }} disabled={runDetails.events.page === 1 || isDetailsLoading} className="text-xs font-bold text-dark-muted disabled:opacity-40 cursor-pointer">Anterior</button><span className="text-xs font-semibold text-dark-muted">Página {runDetails.events.page}</span><button type="button" onClick={() => { const pages = { ...detailsPages, events: detailsPages.events + 1 }; setDetailsPages(pages); void loadRunDetails(runDetails.run.id, pages); }} disabled={runDetails.events.page * runDetails.events.pageSize >= runDetails.events.total || isDetailsLoading} className="text-xs font-bold text-brand-primary disabled:opacity-40 cursor-pointer">Próxima</button></div>
</section> </section>
<section className="overflow-hidden rounded-xl border border-dark-border"> <section className="overflow-hidden rounded-xl border border-dark-border">
<div className="border-b border-dark-border px-4 py-3"><h3 className="text-sm font-bold text-dark-text">Produtos afetados</h3><p className="mt-0.5 text-xs font-semibold text-dark-muted">{runDetails.affectedProducts.total.toLocaleString('pt-BR')} composições importadas nesta execução</p></div> <div className="border-b border-dark-border px-4 py-3"><h3 className="text-sm font-bold text-dark-text">Produtos afetados</h3><p className="mt-0.5 text-xs font-semibold text-dark-muted">{runDetails.affectedProducts.total.toLocaleString('pt-BR')} composições importadas nesta execução</p></div>
@@ -260,7 +257,7 @@ const OlistSync = () => {
{!runDetails.affectedProducts.items.length && <p className="p-5 text-sm font-semibold text-dark-muted">Nenhuma composição importada nesta execução.</p>} {!runDetails.affectedProducts.items.length && <p className="p-5 text-sm font-semibold text-dark-muted">Nenhuma composição importada nesta execução.</p>}
{runDetails.affectedProducts.items.map(product => <div key={product.id} className="p-4"><p className="text-sm font-bold text-dark-text">{product.productDescription || product.sku || product.productId}</p><p className="mt-1 text-xs font-semibold text-brand-primary">{product.sku || `ID ${product.productId}`}</p><p className="mt-2 text-xs font-semibold text-dark-muted">{Number(product.metadata.componentCount || 0).toLocaleString('pt-BR')} componentes · {Number(product.metadata.referenceCount || 0).toLocaleString('pt-BR')} referências</p></div>)} {runDetails.affectedProducts.items.map(product => <div key={product.id} className="p-4"><p className="text-sm font-bold text-dark-text">{product.productDescription || product.sku || product.productId}</p><p className="mt-1 text-xs font-semibold text-brand-primary">{product.sku || `ID ${product.productId}`}</p><p className="mt-2 text-xs font-semibold text-dark-muted">{Number(product.metadata.componentCount || 0).toLocaleString('pt-BR')} componentes · {Number(product.metadata.referenceCount || 0).toLocaleString('pt-BR')} referências</p></div>)}
</div> </div>
<div className="flex items-center justify-between border-t border-dark-border p-3"><button type="button" onClick={() => setDetailsPages(pages => ({ ...pages, products: Math.max(1, pages.products - 1) }))} disabled={runDetails.affectedProducts.page === 1 || isDetailsLoading} className="text-xs font-bold text-dark-muted disabled:opacity-40 cursor-pointer">Anterior</button><span className="text-xs font-semibold text-dark-muted">Página {runDetails.affectedProducts.page}</span><button type="button" onClick={() => setDetailsPages(pages => ({ ...pages, products: pages.products + 1 }))} disabled={runDetails.affectedProducts.page * runDetails.affectedProducts.pageSize >= runDetails.affectedProducts.total || isDetailsLoading} className="text-xs font-bold text-brand-primary disabled:opacity-40 cursor-pointer">Próxima</button></div> <div className="flex items-center justify-between border-t border-dark-border p-3"><button type="button" onClick={() => { const pages = { ...detailsPages, products: Math.max(1, detailsPages.products - 1) }; setDetailsPages(pages); void loadRunDetails(runDetails.run.id, pages); }} disabled={runDetails.affectedProducts.page === 1 || isDetailsLoading} className="text-xs font-bold text-dark-muted disabled:opacity-40 cursor-pointer">Anterior</button><span className="text-xs font-semibold text-dark-muted">Página {runDetails.affectedProducts.page}</span><button type="button" onClick={() => { const pages = { ...detailsPages, products: detailsPages.products + 1 }; setDetailsPages(pages); void loadRunDetails(runDetails.run.id, pages); }} disabled={runDetails.affectedProducts.page * runDetails.affectedProducts.pageSize >= runDetails.affectedProducts.total || isDetailsLoading} className="text-xs font-bold text-brand-primary disabled:opacity-40 cursor-pointer">Próxima</button></div>
</section> </section>
</div> </div>
) : <div className="p-8 text-center text-sm font-semibold text-dark-muted">Não foi possível carregar os detalhes desta execução.</div>} ) : <div className="p-8 text-center text-sm font-semibold text-dark-muted">Não foi possível carregar os detalhes desta execução.</div>}

View File

@@ -51,10 +51,6 @@ const Sellers = () => {
if (!term) return sellers; if (!term) return sellers;
return sellers.filter(seller => `${seller.name} ${seller.id}`.toLocaleLowerCase('pt-BR').includes(term)); return sellers.filter(seller => `${seller.name} ${seller.id}`.toLocaleLowerCase('pt-BR').includes(term));
}, [search, sellers]); }, [search, sellers]);
const totalRevenue = sellers.reduce((sum, seller) => sum + seller.revenue, 0);
const totalOrders = sellers.reduce((sum, seller) => sum + seller.orderCount, 0);
const totalCustomers = sellers.reduce((sum, seller) => sum + seller.customerCount, 0);
const topSeller = sellers[0];
const totalPages = Math.ceil(visibleSellers.length / itemsPerPage); const totalPages = Math.ceil(visibleSellers.length / itemsPerPage);
const safeCurrentPage = Math.min(currentPage, totalPages || 1); const safeCurrentPage = Math.min(currentPage, totalPages || 1);
const startIndex = (safeCurrentPage - 1) * itemsPerPage; const startIndex = (safeCurrentPage - 1) * itemsPerPage;
@@ -72,25 +68,6 @@ const Sellers = () => {
<RefreshStatus isRefreshing={isLoading && sellers.length > 0} /> <RefreshStatus isRefreshing={isLoading && sellers.length > 0} />
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
<div className="rounded-2xl border border-dark-border bg-dark-card p-5 shadow-sm">
<p className="text-xs font-bold uppercase tracking-widest text-dark-muted">Receita da equipe</p>
{isLoading && !sellers.length ? <div className="skeleton mt-3 h-7 w-36" /> : <p className="mt-2 text-2xl font-bold text-brand-primary">{formatCurrency(totalRevenue)}</p>}
</div>
<div className="rounded-2xl border border-dark-border bg-dark-card p-5 shadow-sm">
<p className="text-xs font-bold uppercase tracking-widest text-dark-muted">Pedidos</p>
{isLoading && !sellers.length ? <div className="skeleton mt-3 h-8 w-20" /> : <p className="mt-2 text-3xl font-bold text-dark-text">{formatNumber(totalOrders)}</p>}
</div>
<div className="rounded-2xl border border-dark-border bg-dark-card p-5 shadow-sm">
<p className="text-xs font-bold uppercase tracking-widest text-dark-muted">Clientes atendidos</p>
{isLoading && !sellers.length ? <div className="skeleton mt-3 h-8 w-20" /> : <p className="mt-2 text-3xl font-bold text-dark-text">{formatNumber(totalCustomers)}</p>}
</div>
<div className="rounded-2xl border border-dark-border bg-dark-card p-5 shadow-sm">
<p className="text-xs font-bold uppercase tracking-widest text-dark-muted">Maior receita</p>
{isLoading && !sellers.length ? <><div className="skeleton mt-3 h-5 w-40" /><div className="skeleton mt-2 h-3 w-24" /></> : <><p className="mt-2 truncate text-lg font-bold text-dark-text">{topSeller ? formatDisplayName(removeTrailingSellerId(topSeller.name)) : '—'}</p><p className="mt-1 text-xs font-semibold text-dark-muted">{topSeller ? formatCurrency(topSeller.revenue) : 'Sem vendas no período'}</p></>}
</div>
</div>
<div className="rounded-2xl border border-dark-border bg-dark-card shadow-sm"> <div className="rounded-2xl border border-dark-border bg-dark-card shadow-sm">
<div className="flex flex-col gap-4 border-b border-dark-border p-4 sm:p-5 lg:flex-row lg:items-center lg:justify-between"> <div className="flex flex-col gap-4 border-b border-dark-border p-4 sm:p-5 lg:flex-row lg:items-center lg:justify-between">
<div> <div>