Avoid Olist detail render cascade
This commit is contained in:
@@ -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>}
|
||||
|
||||
Reference in New Issue
Block a user