diff --git a/src/components/campaign/municipality/MunicipalityListPageChrome.tsx b/src/components/campaign/municipality/MunicipalityListPageChrome.tsx index e1860d69..005dce95 100644 --- a/src/components/campaign/municipality/MunicipalityListPageChrome.tsx +++ b/src/components/campaign/municipality/MunicipalityListPageChrome.tsx @@ -1,32 +1,15 @@ 'use client' -import { usePathname, useSearchParams } from 'next/navigation' -import { useMemo } from 'react' - -import { useMunicipalitySavedFilters } from '@/components/campaign/shared/useMunicipalitySavedFilters' +import { useActiveMunicipalitySavedFilter } from '@/components/campaign/shared/useMunicipalitySavedFilters' import { SetCampaignPageChrome } from '@/components/campaign/shell/CampaignPageChromeContext' import { campaignPageChromeCatalog } from '@/lib/campaignPageChrome' -import { isSameListHref } from '@/lib/listQueryMatch' - -/** A page is a position inside a recorte, not part of it (B18). */ -const IGNORED_PARAMS = ['page'] /** * When the current URL matches a saved municipality filter, the filter name * becomes the page subtitle (B133) — the bar keeps chips as the editable recorte. */ export const MunicipalityListPageChrome = () => { - const savedFilters = useMunicipalitySavedFilters() - const pathname = usePathname() - const searchParams = useSearchParams() - - const activeFilter = useMemo(() => { - const query = searchParams.toString() - const currentHref = query ? `${pathname}?${query}` : pathname - return savedFilters.find((entry) => - isSameListHref(currentHref, entry.href, IGNORED_PARAMS), - ) - }, [pathname, searchParams, savedFilters]) + const activeFilter = useActiveMunicipalitySavedFilter() if (!activeFilter) return null diff --git a/src/components/campaign/shared/useMunicipalitySavedFilters.ts b/src/components/campaign/shared/useMunicipalitySavedFilters.ts index 0738b2f9..0783a1a0 100644 --- a/src/components/campaign/shared/useMunicipalitySavedFilters.ts +++ b/src/components/campaign/shared/useMunicipalitySavedFilters.ts @@ -1,13 +1,19 @@ 'use client' +import { usePathname, useSearchParams } from 'next/navigation' +import { useMemo } from 'react' import { useSyncExternalStore } from 'react' +import { isSameListHref } from '@/lib/listQueryMatch' import { listMunicipalitySavedFilters, subscribeMunicipalitySavedFilters, type MunicipalitySavedFilter, } from '@/utilities/municipality/municipalitySavedFilters' +/** A page is a position inside a recorte, not part of it (B18). */ +export const MUNICIPALITY_SAVED_FILTER_IGNORED_PARAMS = ['page'] as const + /** * Stable reference for the render that has no `localStorage` to read. Returning * a fresh `[]` here is the classic `useSyncExternalStore` render loop. @@ -26,3 +32,18 @@ export const useMunicipalitySavedFilters = (): readonly MunicipalitySavedFilter[ listMunicipalitySavedFilters, () => NO_SAVED_FILTERS, ) + +/** The saved filter whose href matches the current list URL, if any (B18/B133). */ +export const useActiveMunicipalitySavedFilter = (): MunicipalitySavedFilter | undefined => { + const savedFilters = useMunicipalitySavedFilters() + const pathname = usePathname() + const searchParams = useSearchParams() + + return useMemo(() => { + const query = searchParams.toString() + const currentHref = query ? `${pathname}?${query}` : pathname + return savedFilters.find((entry) => + isSameListHref(currentHref, entry.href, MUNICIPALITY_SAVED_FILTER_IGNORED_PARAMS), + ) + }, [pathname, searchParams, savedFilters]) +} diff --git a/src/components/campaign/shell/MunicipalityNavSavedFilters.tsx b/src/components/campaign/shell/MunicipalityNavSavedFilters.tsx index ea2e8dc6..af7ebebe 100644 --- a/src/components/campaign/shell/MunicipalityNavSavedFilters.tsx +++ b/src/components/campaign/shell/MunicipalityNavSavedFilters.tsx @@ -2,26 +2,24 @@ import { Trash2Icon } from 'lucide-react' import Link from 'next/link' -import { usePathname, useSearchParams } from 'next/navigation' import { toast } from 'sonner' -import { useMunicipalitySavedFilters } from '@/components/campaign/shared/useMunicipalitySavedFilters' +import { + useActiveMunicipalitySavedFilter, + useMunicipalitySavedFilters, +} from '@/components/campaign/shared/useMunicipalitySavedFilters' import { SidebarMenuAction, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, } from '@/components/ui/Sidebar' -import { isSameListHref } from '@/lib/listQueryMatch' import { removeMunicipalitySavedFilter, saveMunicipalitySavedFilter, type MunicipalitySavedFilter, } from '@/utilities/municipality/municipalitySavedFilters' -/** A page is a position inside a recorte, not part of it. */ -const IGNORED_PARAMS = ['page'] - /** * The saved filters of `/campanha/municipios` (B18), hung under that nav item. * @@ -31,14 +29,7 @@ const IGNORED_PARAMS = ['page'] */ export const MunicipalityNavSavedFilters = ({ onNavigate }: { onNavigate: () => void }) => { const savedFilters = useMunicipalitySavedFilters() - const pathname = usePathname() - const searchParams = useSearchParams() - - const query = searchParams.toString() - const currentHref = query ? `${pathname}?${query}` : pathname - const activeHref = savedFilters.find((entry) => - isSameListHref(currentHref, entry.href, IGNORED_PARAMS), - )?.href + const activeFilter = useActiveMunicipalitySavedFilter() if (!savedFilters.length) return null @@ -75,7 +66,7 @@ export const MunicipalityNavSavedFilters = ({ onNavigate }: { onNavigate: () => return ( {savedFilters.map((entry) => { - const isActive = entry.href === activeHref + const isActive = entry.href === activeFilter?.href return (