Skip to content

feat(meet): add interactive polling to meeting chat#76

Open
dankgarlic1 wants to merge 8 commits into
frappe:developfrom
dankgarlic1:feat/meet/polling-in-meeting-chat
Open

feat(meet): add interactive polling to meeting chat#76
dankgarlic1 wants to merge 8 commits into
frappe:developfrom
dankgarlic1:feat/meet/polling-in-meeting-chat

Conversation

@dankgarlic1

@dankgarlic1 dankgarlic1 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

This ports the new polling feature into the Frappe Suite monorepo architecture

closes #93

JAM: https://jam.dev/c/c42e3c51-6258-4f16-99b5-f8bff43f2a39

REF: frappe/meet#62 (comment)

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

This is close, but the late-join poll flow should be fixed before merging.

  • Late joiners can miss the one-time existing poll sync.
  • The server-side poll validation and acknowledgement paths now cover the previously reported cases.

frontend/src/apps/meet/pages/Meeting.vue

Important Files Changed

Filename Overview
frontend/src/apps/meet/pages/Meeting.vue Wires the poll service into the meeting page, but registers poll listeners after the room join flow.
frontend/src/apps/meet/components/ChatPanel.vue Adds poll creation controls and renders active poll cards inside the chat panel.
suite/meet/sfu-server/src/server/handlers/PollHandlers.ts Adds poll creation and voting handlers with role checks, validation, and failure acknowledgements.
suite/meet/sfu-server/src/server/handlers/RoomJoinHandlers.ts Sends personalized existing poll state to full-access participants during room join.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
frontend/src/apps/meet/pages/Meeting.vue:677
**Late poll listener** `existing_polls` is emitted as part of joining the room, but this listener is registered only after the connection and join setup has completed. When a participant joins a meeting that already has an active poll, that one-shot event can be missed, leaving the chat panel with an empty poll store until another poll event happens.

Reviews (8): Last reviewed commit: "fix: moved from local state of votes to ..." | Re-trigger Greptile

Comment thread suite/meet/sfu-server/src/server/handlers/PollHandlers.ts
Comment thread suite/meet/sfu-server/src/server/handlers/PollHandlers.ts
Comment thread suite/meet/sfu-server/src/server/handlers/PollHandlers.ts
Comment thread frontend/src/apps/meet/composables/usePoll.ts
Comment thread suite/meet/sfu-server/src/server/RoomRegistry.ts
Comment thread frontend/src/apps/meet/components/PollMessageCard.vue Outdated
Comment thread frontend/src/apps/meet/composables/usePoll.ts Outdated
Comment thread suite/meet/sfu-server/src/server/handlers/PollHandlers.ts

const pollService = inject("poll") as any;

const localVotedOption = ref<string | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Lost Vote State This state is only local to the card, while existing_polls and poll:update do not include whether the current participant already voted. When a user votes, refreshes, and rejoins, the card renders all options as clickable; the server rejects the duplicate vote, the catch resets this back to null, and the user stays in an endless unvoted state. Include current-user vote state in the poll payload or derive it before rendering the card.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/apps/meet/components/PollMessageCard.vue
Line: 58

Comment:
**Lost Vote State** This state is only local to the card, while `existing_polls` and `poll:update` do not include whether the current participant already voted. When a user votes, refreshes, and rejoins, the card renders all options as clickable; the server rejects the duplicate vote, the catch resets this back to `null`, and the user stays in an endless unvoted state. Include current-user vote state in the poll payload or derive it before rendering the card.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BreadGenie this has been fixed, any signed in user after refreshing and joining again would not be able to vote fi they have already voted however their is an edge case

If someone joins as a guest, if they vote and refresh and join again, they can vote again which messes up the votes

I am not able to figure out a solution for this other than only allowing signed in users to vote

because everytime a guest re joins their user id is different, so i am unable to track their vote status, if they have voted or not

can you suggest what to do?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should guests be able to do a vote? their ids are pretty much ephemeral

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I was thinking as well. The current implementation tracks votes by participant ID, which is stable for authenticated users but regenerated for guests on every rejoin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, so the cleanest path is to gate voting behind authentication. Guests can still see the poll and watch results update in real time, they just can't cast a vote.

On the UI side, for guests you'd render the buttons as disabled with a small tooltip or inline note like "Sign in to vote" instead of the current !!localVotedOption disabled state. That way the feature is still visible and useful to guests without the integrity problem.

On the server side, the vote handler should check frappe.session.user != "Guest" and return an explicit error (not just silently reject) so the client can surface the right message rather than treating it as a duplicate-vote failure.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a reliable way to prevent duplicate guest votes across refreshes, what do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't one — not reliably. Any client-side token (localStorage, cookie, fingerprint) can be cleared or spoofed, and guest participant IDs are ephemeral by design. The only durable identity is an authenticated session.

The practical options are:

  1. Gate voting on auth (recommended) — guests see the poll and live results but can't vote. Cheapest to implement, no integrity risk.

  2. localStorage token — on first vote, write a UUID to localStorage keyed by pollId. On load, check if that key exists and mark the option as voted. This survives refreshes on the same browser but not private tabs, different devices, or cleared storage. It's a soft deterrent, not a real fix.

  3. Fingerprinting — fragile, privacy-hostile, and still bypassable.

Option 1 is the right call here. The implementation is straightforward:

Server (vote handler):

if frappe.session.user == "Guest":
    frappe.throw("Please sign in to vote", frappe.PermissionError)

Client (PollMessageCard.vue):

<button
    v-for="option in poll.options"
    :key="option.id"
    @click="handleVote(option.id)"
    :disabled="!!localVotedOption || isGuest"
    :title="isGuest ? 'Sign in to vote' : ''"
    ...
>

Where isGuest comes from your existing session/auth state. The guest sees the poll updating live, which is still valuable, just without voting access.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i feel, we should not allow guests to vote

@dankgarlic1 dankgarlic1 Jun 28, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BreadGenie agree?should i gate voting to authenticated users only or should i DO this in another PR, seems like i have addressed every other comment, so it can be reviewed by you too

This ports the new polling feature into the Frappe Suite monorepo architecture and aligns the UI with the Espresso design system.

- Ported SFU server poll handlers and registry logic to the nested backend
- Added CreatePollModal and PollMessageCard to the unified Vite frontend
- Removed custom colors and shadows to strictly match the Espresso grayscale UI
- Replaced deprecated Feather icons with Lucide icons (lucide-bar-chart-2)
- Wired up real-time socket events and Pinia store for live voting updates
Comment thread frontend/src/apps/meet/composables/usePoll.ts
@dankgarlic1 dankgarlic1 force-pushed the feat/meet/polling-in-meeting-chat branch from f4067fb to 4ea615c Compare June 28, 2026 13:52
Comment thread suite/meet/api/meeting.py Outdated
Comment thread frontend/src/apps/meet/composables/usePoll.ts
Comment thread suite/meet/sfu-server/src/server/RoomRegistry.ts
Comment thread suite/meet/sfu-server/src/server/handlers/PollHandlers.ts
Comment thread frontend/src/apps/meet/components/PollMessageCard.vue
Comment thread suite/meet/sfu-server/src/server/RoomRegistry.ts
@dankgarlic1 dankgarlic1 force-pushed the feat/meet/polling-in-meeting-chat branch from aa4e99c to 3ff55cf Compare June 28, 2026 15:56
Comment thread frontend/src/apps/meet/pages/Meeting.vue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Real-time Polling via Control Bar with In-Chat Voting

2 participants