[Frontend] Give the dashboard a "needs you" attention surface #368
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Impact: CRITICAL
Found in the August 2026 session lifecycle review (#319).
What the user experiences
A GM or player who logs into the web app sees nothing but a list of campaigns. There is no way to tell, at a glance, that a vote is waiting on you, a session needs an RSVP, a transcript is ready for GM approval, or a recording is in progress right now. Every one of those facts only reaches the user through Discord, or not at all. The only in-app hint of anything pending is a non-clickable "Next session in 3d 4h" line on each campaign card.
Evidence
webapp/frontend/src/pages/Dashboard.jsx:234-446— the dashboard renders a campaign list and nothing else; no unread state, no inbox, no pending-action count anywhere.webapp/frontend/src/pages/Dashboard.jsx:67-71— the countdown line ("Next session in Nd Nh") is plain text, not itself a link to the session; the whole card links to/campaigns/:idinstead (:76-78).webapp/frontend/srcfornotification|unread|inbox|badgereturns only admin settings, status pills, and one badge atCampaignDetail.jsx:2599-2603(on a tab that opens a new browser tab — see the nav-bar issue in this milestone).Why it matters for a hosted product
The product never surfaces work that is waiting, in either channel. Every "is it done?" and "did my vote count?" becomes a support message to the owner instead of something the app already knows and could show.
Proposed fix
Add a "Needs you" block above the campaign list on
Dashboard.jsx, driven by one new aggregate endpoint that returns: open votes the current user hasn't voted in, confirmed sessions they haven't RSVP'd to (once the web RSVP control ships — see the companion RSVP issue), transcripts inreadystatus awaiting GM approval, lore proposals pending count, and any session currentlyin_progress/recording. Every row deep-links to the relevant page. Make the campaign countdown line (Dashboard.jsx:67-71) itself a clickable link to the session while this is built.Acceptance criteria
Dashboard.jsxrenders a "Needs you" section above the campaign list when the user has at least one pending item.Picking this up as v4.3.0 phase 4 (#514), last on the lane so it can use #370's RSVP data. Decision: one aggregate endpoint for the signed-in user returning typed items (open vote without your vote, confirmed session without your RSVP, transcript awaiting GM approval, pending suggested wiki updates, session in progress), each with a deep link, computed in one query per kind scoped to your memberships. The dashboard renders a "Needs you" block above the campaign list only when there is something in it, and the countdown line becomes a link to the session.
Done in PR #526 (auto-merging on green); ships with v4.3.0.
GET /api/me/attentionreturns all five kinds in one response:in_progress,vote,rsvp,approve_transcript,wiki_suggestions. An aggregate rather than five client calls per campaign, because the dashboard has to know whether anything is pending before it can decide to render a section at all.Six round trips regardless of how many campaigns you are in: memberships once, then one query per kind scoped by
campaign_id IN (...), with "has this user already answered?" as a correlatedEXISTSand the vote's date as a correlatedmin(proposed_time). No N+1. The two GM-only kinds are skipped entirely when you GM nothing. Archived and trashed campaigns contribute nothing: archiving is how a group says it has stopped playing (#479), and a dashboard that kept nagging about its open votes would undo that.The section is absent, not empty, when nothing is pending; a block that is there every day is a block people stop reading. Each row deep-links to its destination, and the kind labels come from
vocabulary.js, so a suggested wiki update is called the same thing here as on the page it links to (#379). Thersvpkind uses #370's nullablersvp_status, so a GM marking somebody present does not count as that person having answered.The "Next session in Nd Nh" line is now a link to the session. That required making the campaign card a container with the campaign link inside it rather than one big link, since an anchor cannot nest in an anchor.
Tests: 22 backend (
test_attention.py: each kind for the right user and not for others, empty-list shape, scoping), 7 component, 3 page tests. One discrepancy found and filed as #524:count_bot_proposalson the campaign page does not filter soft-deleted proposals, so its number can exceed this endpoint's.