diff --git a/src/app/(dashboard)/finance/rm-pricing/costs/rm-costs-page-client.tsx b/src/app/(dashboard)/finance/rm-pricing/costs/rm-costs-page-client.tsx index 85fd482..80c001a 100644 --- a/src/app/(dashboard)/finance/rm-pricing/costs/rm-costs-page-client.tsx +++ b/src/app/(dashboard)/finance/rm-pricing/costs/rm-costs-page-client.tsx @@ -55,9 +55,15 @@ function RMCostsPageContent() { // Track whether the initial auto-select has fired (declared before listLoading uses it). const autoSelectedRef = useRef(false) + // Keep a ref to the latest filters.period so the auto-select effect always + // reads the most up-to-date value (avoids stale-closure issues). + const filtersPeriodRef = useRef(filters.period) + filtersPeriodRef.current = filters.period + // Once autoSelectedRef is true the user has either received a default period // or deliberately picked "All Periods" (period=""), so we no longer block on - // !filters.period. + // !filters.period. Also skip the "waiting" gate when a period is already + // present from the URL (e.g. after a page reload with ?period=202604). const listLoading = periodsLoading || (!autoSelectedRef.current && availablePeriods.length > 0 && !filters.period) || isLoading // Auto-select the latest available period ONCE on first load when the user @@ -68,7 +74,9 @@ function RMCostsPageContent() { if (autoSelectedRef.current) return if (availablePeriods.length === 0) return autoSelectedRef.current = true - if (!filters.period) { + // Read period from ref to guarantee we see the latest value (the URL may + // already carry a period param after a page reload). + if (!filtersPeriodRef.current) { setFilters((prev) => ({ ...prev, period: availablePeriods[0], page: 1 })) } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/src/lib/hooks/use-url-state.ts b/src/lib/hooks/use-url-state.ts index f11e733..17c993d 100644 --- a/src/lib/hooks/use-url-state.ts +++ b/src/lib/hooks/use-url-state.ts @@ -1,7 +1,7 @@ "use client" import { useSearchParams, useRouter, usePathname } from "next/navigation" -import { useCallback, useMemo, useRef, useEffect } from "react" +import { useCallback, useEffect, useMemo, useRef } from "react" /** * Configuration for URL state serialization @@ -121,10 +121,10 @@ export function useUrlState( }, [searchParams, defaultValues, deserialize]) // Use ref to access current state in callback without adding it to dependencies - // This prevents setState from changing reference on every state change + // This prevents setState from changing reference on every state change. + // Sync the ref during render (not in an effect) so that setState always reads + // the latest state, even when called from other effects in the same cycle. const stateRef = useRef(state) - - // Sync ref in effect to satisfy ESLint rules while keeping the pattern useEffect(() => { stateRef.current = state }, [state])