feat(plans): sync search and status filters to the URL (closes #1086) - #1204
Open
bilhokista wants to merge 1 commit into
Open
feat(plans): sync search and status filters to the URL (closes #1086)#1204bilhokista wants to merge 1 commit into
bilhokista wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1086.
What already existed
The page already held
searchandstatusFilterstate and applied both infiltered, so the toolbar was not missing. Two things genuinely were.No URL sync at all. There was no
useSearchParamsanywhere in the file, so a filtered view could not be shared or survive a refresh. That is the substance of this issue.The search matched the wrong fields. It matched
p.idandp.token_address. The issue asks for Plan Name and Beneficiary address, neither of which was searched.Changes
searchandstatusread from the query string, so a shared link opens in the same view.p.title(the Plan Name) and to beneficiarywallet_address, keeping the existingidandtoken_addressmatching.filteredmoved into auseMemo, since it now walks the beneficiaries array per plan rather than comparing two strings.Decisions worth reviewing
replace, notpush. Typing a search term one character at a time withpushwould add a history entry per keystroke and effectively break the back button. The URL write is also debounced by 300ms, while the input itself stays immediate — the field does not lag.Suspense boundary.
useSearchParams()opts a route into dynamic rendering, and Next.js fails the build for a statically rendered page that calls it without a boundary. The page body moved intoPlansPageContent, wrapped in<Suspense>. This keeps the page building regardless of render mode. If this route is already forced dynamic elsewhere, the wrapper is harmless but can be dropped.Status matching is case-insensitive on read.
?status=activeresolves to the canonicalActivefromSTATUS_FILTERSso the active tab highlights correctly, rather than silently falling back toAll.The first render does not write. Without that guard, mounting would immediately rewrite the URL and strip any other query parameters an inbound link carried.
Beneficiary access is guarded.
beneficiariesis typedany[]and is optional, so the lookup uses(p.beneficiaries ?? []).some(...)with optional chaining onwallet_address. A plan with no beneficiaries filters normally instead of throwing.One mismatch I did not act on
The issue lists status tabs as Active, Inactive, Pending Claim and Disputed. The page's
STATUS_FILTERSareAll, Active, Pending, Triggered, Completed, andStatusBadgemaps those. I kept the existing set rather than renaming statuses, since changing them would touch the badge and likely the backend contract. Happy to follow up if the issue's list is the intended direction.Verification
Parses clean as TSX via the TypeScript compiler API. I did not run the suite — the repository is ~955 MB and I worked from the individual file rather than a full clone, so please treat CI as the authority.
Behaviour with no query string is unchanged:
searchstarts empty,statusFilterstartsAll, and nothing is written to the URL until the user interacts.🤖 Generated with Claude Code
https://claude.ai/code/session_01CrfEY1tvXrbeMDAUzxfuk7