Skip to content

Persist category filter selection in URL - #193

Merged
lauriechammah merged 1 commit into
developfrom
feature/140-category-filters-url-persist
Aug 27, 2026
Merged

Persist category filter selection in URL#193
lauriechammah merged 1 commit into
developfrom
feature/140-category-filters-url-persist

Conversation

@marccsaada

@marccsaada marccsaada commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Closes #140

Overview

Persisted the category filter selection in the URL so filtered map views survive a refresh and are shareable. Added encode and decode helpers in filters.ts, and wired MapFiltersProvider to read the selection from the URL on load and sync it back on every change.

Testing

Manual testing on /carte:

  • Unchecking a category updates the URL immediately
  • Refreshing preserves the filter state, including Faune/flore, which needed a fix since the reused helper was dropping that group's state
  • Re-checking everything clears the param
  • A filtered URL loads correctly in a new incognito window

Ran npm run lint, npx tsc --noEmit, and npm run test, all pass.

Screenshots / Screencasts

N/A

Checklist

  • Code is neat, readable, and works
  • Code is commented where appropriate and well-documented
  • Commit messages follow our guidelines
  • Issue number is linked
  • Branch is linked
  • Reviewers are assigned (one of your tech leads)

Notes

None.

@marccsaada marccsaada added this to the sprint-4 milestone Aug 26, 2026
@marccsaada marccsaada self-assigned this Aug 26, 2026
@marccsaada marccsaada added the back-end back-end related issue label Aug 26, 2026
@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
canopee-project Ready Ready Preview Aug 26, 2026 2:16pm

@marccsaada marccsaada linked an issue Aug 26, 2026 that may be closed by this pull request
5 tasks
Comment on lines +56 to +78
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()

const [selection, setSelection] = useState<CategorySelection>(() =>
paramToSelection(searchParams.get('categories')),
)

useEffect(() => {
const params = new URLSearchParams(searchParams.toString())
const value = selectionToUrlParam(selection)

if (value === null) {
params.delete('categories')
} else {
params.set('categories', value)
}

const query = params.toString()
router.replace(query ? `${pathname}?${query}` : pathname, { scroll: false })
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selection])

@lauriechammah lauriechammah Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping filter state and query params bidirectionally synchronized. Right now, filters don't truly persist when you reload the page.

Suggested change
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
const [selection, setSelection] = useState<CategorySelection>(() =>
paramToSelection(searchParams.get('categories')),
)
useEffect(() => {
const params = new URLSearchParams(searchParams.toString())
const value = selectionToUrlParam(selection)
if (value === null) {
params.delete('categories')
} else {
params.set('categories', value)
}
const query = params.toString()
router.replace(query ? `${pathname}?${query}` : pathname, { scroll: false })
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selection])
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
const [selection, setSelection] = useState<CategorySelection>(() =>
paramToSelection(searchParams.get('categories')),
)
useEffect(() => {
const next = paramToSelection(searchParams.get('categories'))
setSelection((prev) => {
const sameSize = next.size === prev.size
const sameValues = sameSize && [...next].every((c) => prev.has(c))
return sameValues ? prev : next
})
}, [searchParams])
useEffect(() => {
const params = new URLSearchParams(searchParams.toString())
const nextValue = selectionToUrlParam(selection)
const currentValue = searchParams.get('categories')
if (nextValue === null) params.delete('categories')
else params.set('categories', nextValue)
const normalizedCurrent = currentValue ?? null
if (normalizedCurrent === nextValue) return
const query = params.toString()
router.replace(query ? `${pathname}?${query}` : pathname, { scroll: false })
}, [selection, searchParams, pathname, router])

@lauriechammah lauriechammah left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Behavior is not exactly as expected. When the page is reloaded, all filters are reactivated. The state doesn't quite persist

@anis022
anis022 removed their request for review August 27, 2026 00:22
@lauriechammah
lauriechammah merged commit ca2eeb3 into develop Aug 27, 2026
7 checks passed
@lauriechammah
lauriechammah deleted the feature/140-category-filters-url-persist branch August 27, 2026 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

back-end back-end related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Issue]: Persist filter selection in URL

2 participants