IntersectMBO / IntersectMBO/govtool
Live Voting - Refactor filtering of voted on proposals
- Dominant language
- HTML
- Stars
- 21
- Forks
- 29
- Avg merge
- 2d 22h
- Merged PRs (30d)
- 7
Description
### Area
Voting Pillar
### Domain
gov.tools
### Which wallet were you using?
No response
### Context
In the governance dashboard, the filtering of proposals a DRep has already voted on is currently implemented entirely on the frontend (within `DashboardGovernanceActionsVotedOn` and `GovernanceActionsToVote` components).
This logic involves complex filtering inside a React `useMemo` hook that processes `mappedData`, `votes`, and proposal details to exclude proposals already voted on. The code is difficult to maintain, causes unnecessary client-side computation, and should be handled by the backend/API instead.
By moving this logic to the backend, we can simplify the React components, reduce frontend data processing, and ensure consistency and scalability for future API consumers.
### Notes
* The backend should handle filtering of proposals so that the API directly returns:
* proposals **to vote on** (not yet voted), and
* proposals **already voted on**,
as distinct datasets or through clear filtering parameters.
* The frontend should simply display what the backend provides, without reproducing filtering logic.
* Preserve the current behavior and data integrity (i.e., the UI should look and work **exactly the same** after refactoring).
* Ensure API responses include any necessary metadata for frontend pagination or status updates.
* The current frontend filtering logic (below) should be fully removed:
```js
// TODO: Filtering here is some kind of craziness. It should be done on the backend.
const filteredProposals = useMemo(() => {
const list = mappedData ?? [];
if (!votes?.length) return list;
const proposalsFromVotes = votes
.flatMap((v) => v?.actions ?? [])
.map((a) => a?.proposal)
.filter(Boolean);
const votedKeys = new Set(
proposalsFromVotes
.map((p) => ({
id: p?.id ?? p?.id,
tx: p?.txHash ?? p?.txHash,
}))
.filter(({ id, tx }) => Boolean(id && tx))
.map(({ id, tx }) => `${id}:${tx}`),
);
if (votedKeys.size === 0) return list;
return list.filter((p) => {
const id = p?.id ?? p?.id;
const tx = p?.txHash ?? p?.txHash;
if (!id || !tx) return true;
return !votedKeys.has(`${id}:${tx}`);
});
}, [mappedData, voter?.isRegisteredAsDRep, isProposalsFetchingNextPage]);
```
### Steps to reproduce
1. Open the **Governance Dashboard**.
2. Observe the proposals shown under both **“Governance Actions to Vote On”** and **“Governance Actions Voted On”** sections.
3. Note that filtering between these sections currently happens client-side in React.
### Actual behavior
Filtering of voted/unvoted governance actions is done on the frontend using complex client-side logic, increasing code complexity and computation on the user’s browser.
### Expected behavior
Filtering should be performed by the backend:
* The frontend should receive pre-filtered data (voted vs not voted).
* The React components should only render data without additional filtering logic.
* Behavior, output, and visual presentation remain identical to current implementation.
Contributor guide
Assessment
This issue has not been assessed yet.