Avoid Olist detail render cascade

This commit is contained in:
Cauê Faleiros
2026-08-11 09:25:31 -03:00
parent f836319041
commit 3664a94722

View File

@@ -72,7 +72,7 @@ const OlistSync = () => {
};
}, [loadStatus]);
const loadRunDetails = useCallback(async (runId: number, pages = detailsPages) => {
const loadRunDetails = useCallback(async (runId: number, pages: { events: number; products: number }) => {
setIsDetailsLoading(true);
try {
setRunDetails(await fetchOlistRunDetails(runId, pages.events, pages.products));
@@ -81,18 +81,13 @@ const OlistSync = () => {
} finally {
setIsDetailsLoading(false);
}
}, [detailsPages]);
useEffect(() => {
if (!selectedRunId) return;
void loadRunDetails(selectedRunId);
}, [selectedRunId, detailsPages, loadRunDetails]);
}, []);
useEffect(() => {
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);
}, [selectedRunId, runDetails?.run.status, loadRunDetails]);
}, [selectedRunId, runDetails?.run.status, detailsPages, loadRunDetails]);
const latestRun = status?.runs[0] || null;
const completionPercent = useMemo(() => {
@@ -137,8 +132,10 @@ const OlistSync = () => {
};
const openRunDetails = (runId: number) => {
setDetailsPages({ events: 1, products: 1 });
const initialPages = { events: 1, products: 1 };
setDetailsPages(initialPages);
setSelectedRunId(runId);
void loadRunDetails(runId, initialPages);
};
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.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 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 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>
@@ -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.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 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>
</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>}