Skip to content

Live Voting - Refactor filtering of voted on proposals #4105

@Ojly

Description

@Ojly

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:

    // 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.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

To do

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions