From 586a436f3d53eba9c1e8da4df7769b37afba9a43 Mon Sep 17 00:00:00 2001 From: ls-root Date: Tue, 3 Feb 2026 12:11:03 +0100 Subject: [PATCH] fix(frontend): decouple table pagination from summary fetching (#11495) Prevent the summary data from refetching unnecessarily when log pagination changes. - Split the data fetching into two separate useEffect hooks. - Summary is now fetched only on mount. - Logs refetch only when page or limit dependencies change. - Decoupled loading states to prevent chart loading animation during log updates. --- frontend/src/app/data/page.tsx | 48 +++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/frontend/src/app/data/page.tsx b/frontend/src/app/data/page.tsx index b4969e4ec..374aac0da 100644 --- a/frontend/src/app/data/page.tsx +++ b/frontend/src/app/data/page.tsx @@ -94,7 +94,8 @@ const chartConfigApps = { export default function DataPage() { const [data, setData] = useState([]); const [summary, setSummary] = useState(null); - const [loading, setLoading] = useState(true); + const [summaryLoading, setSummaryLoading] = useState(true); + const [dataLoading, setDataLoading] = useState(true); const [error, setError] = useState(null); const [currentPage, setCurrentPage] = useState(1); const [itemsPerPage, setItemsPerPage] = useState(25); @@ -105,35 +106,40 @@ export default function DataPage() { const nf = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 }); + // Fetch summary only once on mount useEffect(() => { - const fetchData = async () => { - setLoading(true); + const fetchSummary = async () => { try { - const [summaryRes, dataRes] = await Promise.all([ - fetch("https://api.htl-braunau.at/data/summary"), - fetch( - `https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${ - itemsPerPage === 0 ? "" : itemsPerPage - }`, - ), - ]); - + const summaryRes = await fetch("https://api.htl-braunau.at/data/summary"); if (!summaryRes.ok) { throw new Error(`Failed to fetch summary: ${summaryRes.statusText}`); } + const summaryData: SummaryData = await summaryRes.json(); + setSummary(summaryData); + } catch (err) { + setError((err as Error).message); + } finally { + setSummaryLoading(false); + } + }; + + fetchSummary(); + }, []); + + useEffect(() => { + const fetchData = async () => { + setDataLoading(true); + try { + const dataRes = await fetch(`https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${itemsPerPage}`); if (!dataRes.ok) { throw new Error(`Failed to fetch data: ${dataRes.statusText}`); } - - const summaryData: SummaryData = await summaryRes.json(); const pageData: DataModel[] = await dataRes.json(); - - setSummary(summaryData); setData(pageData); } catch (err) { setError((err as Error).message); } finally { - setLoading(false); + setDataLoading(false); } }; @@ -306,7 +312,7 @@ export default function DataPage() {
- {loading ? ( + {summaryLoading ? (
@@ -411,7 +417,7 @@ export default function DataPage() { - {loading ? ( + {dataLoading ? (
@@ -478,7 +484,7 @@ export default function DataPage() { variant="outline" size="sm" onClick={() => setCurrentPage((prev) => Math.max(prev - 1, 1))} - disabled={currentPage === 1 || loading} + disabled={currentPage === 1 || dataLoading} > Previous @@ -488,7 +494,7 @@ export default function DataPage() { variant="outline" size="sm" onClick={() => setCurrentPage((prev) => prev + 1)} - disabled={loading || sortedData.length < itemsPerPage} + disabled={dataLoading || sortedData.length < itemsPerPage} > Next