From 5a68762510b663f71f1feaf3de1c914b7e506193 Mon Sep 17 00:00:00 2001 From: SathvikaSingoti Date: Thu, 9 Jul 2026 02:37:00 +0530 Subject: [PATCH 1/2] fix(frontend): replace Findings API response any with typed contract --- frontend/src/pages/Findings.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/Findings.tsx b/frontend/src/pages/Findings.tsx index dceb1248c..ea6a89956 100644 --- a/frontend/src/pages/Findings.tsx +++ b/frontend/src/pages/Findings.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useMemo, useRef, useState } from 'react' import { AnimatePresence, motion } from 'framer-motion' import { useVirtualizer } from '@tanstack/react-virtual' -import { getFindings } from '../api' +import { getFindings, FindingsResponse } from '../api' import { formatLocaleDate, parseDateSafe, getCurrentTimeZone } from '../utils/date' import SavedViewsPanel from '../components/SavedViewsPanel' import { useSavedViews, FilterPreset } from '../hooks/useSavedViews' @@ -249,8 +249,10 @@ export default function Findings() { useEffect(() => { setLoading(true) getFindings(1, perPage) - .then((data: any) => { - const nextFindings = data.findings || [] + .then((data: FindingsResponse) => { + const nextFindings = (data.findings || []).filter( + (finding) => typeof finding.id === 'string', + ) as Finding[] setFindings(nextFindings) setTotalItems(data.total ?? nextFindings.length) setPage(1) @@ -601,7 +603,9 @@ export default function Findings() { const nextPage = page + 1 try { const data = await getFindings(nextPage, perPage) - const moreFindings = (data.findings || []) as Finding[] + const moreFindings = (data.findings || []).filter( + (finding) => typeof finding.id === 'string', + ) as Finding[] if (moreFindings.length > 0) { setFindings((prev) => [...prev, ...moreFindings]) setPage(nextPage) From 6080852508dc775f2c6e6901fa52b17a725f2a4d Mon Sep 17 00:00:00 2001 From: SathvikaSingoti Date: Sat, 11 Jul 2026 02:59:28 +0530 Subject: [PATCH 2/2] fix(frontend): advance page based on raw fetch, not filtered count Fixes an infinite-refetch bug flagged in review: if a page's findings all lacked a valid id, moreFindings.length was 0 and page never advanced, causing Load More to repeatedly refetch the same page. --- frontend/src/pages/Findings.tsx | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/frontend/src/pages/Findings.tsx b/frontend/src/pages/Findings.tsx index ea6a89956..cbfa7b210 100644 --- a/frontend/src/pages/Findings.tsx +++ b/frontend/src/pages/Findings.tsx @@ -598,22 +598,23 @@ export default function Findings() { } async function loadMore() { - if (loadingMore) return - setLoadingMore(true) - const nextPage = page + 1 - try { - const data = await getFindings(nextPage, perPage) - const moreFindings = (data.findings || []).filter( - (finding) => typeof finding.id === 'string', - ) as Finding[] - if (moreFindings.length > 0) { - setFindings((prev) => [...prev, ...moreFindings]) - setPage(nextPage) - } - } finally { - setLoadingMore(false) + if (loadingMore) return + setLoadingMore(true) + const nextPage = page + 1 + try { + const data = await getFindings(nextPage, perPage) + const rawFindings = data.findings || [] + const moreFindings = rawFindings.filter( + (finding) => typeof finding.id === 'string', + ) as Finding[] + if (rawFindings.length > 0) { + setFindings((prev) => [...prev, ...moreFindings]) + setPage(nextPage) } + } finally { + setLoadingMore(false) } +} // ─── Keyboard navigation ──────────────────────────────────────────────────── function handleListKeyDown(e: React.KeyboardEvent) {