mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 12:42:38 +00:00
fix(web): advance dashboard pagination on first Next click
Driving loadMore() from the auto-load effect in page.tsx left a one-render gap where loadingMore was still false, so the snap-back effect in useDashboardFilters fired first and reverted currentPage from 2 back to totalPages=1 before the fetch even started. The fetch then ran (the auto-load effect saw the captured currentPage=2 from that render) and the list grew to totalPages=2, but currentPage had already been snapped to 1 — giving the visible "Page 1 of 2+" state and forcing the user to click Next a second time to actually see the new batch. Now handleNextPage calls loadMore() in the same click handler as setCurrentPage(prev+1), so React 18's automatic batching commits both state changes in the same render. Snap-back's `if (loadingMore) return` guard then correctly skips, currentPage stays at the overshoot, and once the fetch resolves totalPages catches up and the new batch renders. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ interface UseDashboardFiltersParams {
|
||||
tenantIdFilter: string;
|
||||
hasMore: boolean;
|
||||
loadingMore: boolean;
|
||||
loadMore: () => void;
|
||||
}
|
||||
|
||||
interface DashboardStats {
|
||||
@@ -61,6 +62,7 @@ export function useDashboardFilters({
|
||||
tenantIdFilter,
|
||||
hasMore,
|
||||
loadingMore,
|
||||
loadMore,
|
||||
}: UseDashboardFiltersParams): UseDashboardFiltersReturn {
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [statusFilter, setStatusFilter] = useState<string | null>(null);
|
||||
@@ -217,20 +219,28 @@ export function useDashboardFilters({
|
||||
}, [sortedSessions, currentPage, sessionsPerPage]);
|
||||
|
||||
const handlePreviousPage = () => setCurrentPage((prev) => Math.max(1, prev - 1));
|
||||
// Allow advancing past totalPages when the server has more pages; the auto-load
|
||||
// effect in page.tsx will fetch the next batch and totalPages catches up. Without
|
||||
// this overshoot the user could never trigger a load while staying inside a single
|
||||
// Prev/Next control — they would have to click a separate "Load more" button.
|
||||
const handleNextPage = () => setCurrentPage((prev) => {
|
||||
if (prev < totalPages) return prev + 1;
|
||||
if (hasMore && !loadingMore) return prev + 1;
|
||||
return prev;
|
||||
});
|
||||
// When advancing past locally-loaded pages, fire loadMore() in the SAME event
|
||||
// handler so React batches setLoadingMore(true) with setCurrentPage(prev+1).
|
||||
// If we relied on a follow-up effect to trigger the fetch, the snap-back effect
|
||||
// below would race ahead (loadingMore still false at that point) and reset
|
||||
// currentPage to totalPages — leaving the user on the previous page even though
|
||||
// a load was in flight, forcing a second click to actually advance.
|
||||
const handleNextPage = () => {
|
||||
if (currentPage < totalPages) {
|
||||
setCurrentPage((prev) => prev + 1);
|
||||
return;
|
||||
}
|
||||
if (hasMore && !loadingMore) {
|
||||
loadMore();
|
||||
setCurrentPage((prev) => prev + 1);
|
||||
}
|
||||
};
|
||||
|
||||
// Snap currentPage back to the last valid page once a load finishes that did NOT
|
||||
// grow totalPages (e.g. an active filter narrowed the new batch to zero matches).
|
||||
// Without this the user would be stuck on an empty paginated slice with no way
|
||||
// to recover except clicking Prev.
|
||||
// to recover except clicking Prev. Gated on !loadingMore so it never fires
|
||||
// mid-fetch and reverts a legitimate overshoot.
|
||||
useEffect(() => {
|
||||
if (loadingMore) return;
|
||||
if (totalPages > 0 && currentPage > totalPages) setCurrentPage(totalPages);
|
||||
|
||||
@@ -68,6 +68,7 @@ export default function Home() {
|
||||
tenantIdFilter,
|
||||
hasMore,
|
||||
loadingMore,
|
||||
loadMore,
|
||||
});
|
||||
|
||||
// Redirect regular users (non-admin, non-operator) to progress portal – they must never see the session list
|
||||
|
||||
Reference in New Issue
Block a user