IntersectMBO / IntersectMBO/govtool

Live Voting - Refactor filtering of voted on proposals

Open
#4,105 0 comments 0 reactions 1 assignee Claimed by @Ojly View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.