Skip to content

Add Live Vote Tally Updates on Milestone Detail via SSE #648

Description

@Samuel1505

Description

The Milestone Detail page (/grants/[id]/milestones/[idx]) shows a vote tally in VotePanel. When a reviewer votes in another window, the tally on screen stays stale until manual refresh. With useContractEvents (issue #78) available, this issue wires live vote updates to the milestone detail page.

Technical Requirements

Files to update

  • app/grants/[id]/milestones/[idx]/page.tsx
  • components/milestones/VotePanel.tsx

Wire useContractEvents

In the milestone detail page:

const { events } = useContractEvents({ grantId })
const { refetch } = useMilestone(grantId, Number(idx))  // (issue #49)

useEffect(() => {
  const latest = events[events.length - 1]
  if (
    latest?.type === 'MilestoneApproved' || latest?.type === 'MilestoneRejected'
  ) {
    const eventMilestoneIdx = Number(latest.data.milestone_idx)
    if (eventMilestoneIdx === Number(idx)) {
      refetch()  // refetch the milestone to get the new vote
    }
  }
}, [events])

Optimistic display for the current user's vote

When the connected wallet submits a vote (via useVoting — issue #35), update VotePanel optimistically before the refetch completes:

  • Immediately add the wallet's vote to the local votes array
  • The vote row shows with a "pending" indicator (amber dot) instead of the final approved/rejected icon
  • When the confirmed data arrives (via refetch), the pending indicator disappears

Connection status in VotePanel

Add a "● LIVE" indicator to the VotePanel header (similar to the funding panel in issue #86):

REVIEWER VOTE                    ● LIVE   3 / 5 needed

connectionStatus from useContractEvents drives the live indicator.

Announce vote updates to screen readers

When the approval count changes, update an aria-live="polite" region:

<div aria-live="polite" className="sr-only">
  {`Vote updated: ${approvalCount} of ${quorum} approvals`}
</div>

This is part of the accessibility audit from issue #97.

Quorum reached animation

When approvalCount >= quorum changes from false to true (milestone just reached quorum):

  • Show a Framer Motion banner animation: a green "✓ Quorum reached" banner slides down from the top of the VotePanel
  • Fire a toast: "Milestone approved by quorum! Payout will be processed."

This event may come from SSE (MilestoneApproved event with quorum_reached: true in the payload) or be derived locally when approvalCount crosses the threshold.

No duplicate subscriptions

The milestone detail page opens a useContractEvents subscription filtered to grantId. The Grant Detail page (if open in another tab) has its own subscription. Each subscription is scoped and independent — verify with the Network tab that there is only one SSE connection per page.

Acceptance Criteria

  • Opening the milestone detail page in two windows: voting in one window updates the tally in the other within 5 seconds.
  • Connected wallet's pending vote shows with an amber dot before confirmation.
  • ● LIVE indicator appears in the VotePanel header.
  • When quorum is reached, the green quorum banner animates in.
  • Screen reader announcement fires when vote count changes.

Estimated Effort

Beginner: 5 hours
Intermediate: 2.5 hours
Expert: 1.5 hours

Metadata

Metadata

Assignees

Labels

Stellar WaveIssues in the Stellar wave program

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions