Public: anyone can read this; the crew can change it.

The proposal page votes: a button per option, the tally, and the decision in place #44

open not picked up yet opened this
opened this

With vote in src/actions.ts (#5) in place, give the page the one thing this app is named for. No new action and no new column: this pull decides nothing, it draws what the record already says.

What done looks like

  • [ ] /p/:id shows one vote button per option for a signed-in member — a form post, no JavaScript — at least 44px on a side, with that member's current choice marked in a word, never by colour alone.
  • [ ] Beside each option: how many counting ballots it has and who cast them. The group is small and votes are public, and the page says so in a sentence rather than leaving it to be discovered.
  • [ ] Under the options, the tally's reason exactly as src/quorum.ts wrote it, and the rule's describeRule line, so the page and the terminal say the same thing.
  • [ ] A guest sees the counts and no buttons, with one line saying who may vote. A signed-in person off the roster sees the counts and a line saying this group decides this one — not a dead button.
  • [ ] A decided proposal shows the winning option, when it was decided and the tally that decided it, and offers no buttons. A withdrawn one says so.
  • [ ] / shows each open proposal's progress using the tally's reason, and decided proposals with their winner — from the query listProposals already runs, never a tally per row.
  • [ ] The proposal region stays live on vote.cast and decision.made: read the comment at the top of src/pages/proposal.ts, keep whatever someone is typing outside the swapped region, and reserve the count's width so 9 becoming 10 shifts nothing.
  • [ ] A proposal whose stored rule no longer parses renders with a plain sentence saying the rule cannot be read, not a 500.
  • [ ] Tests in src/server.test.ts: a member sees buttons, a guest does not, a non-member sees the explaining line; posting a vote lands and the page returns with the choice marked; a decided proposal offers no buttons and names its winner; a voter's name containing < is escaped on the page; / shows a decided proposal's winner.
  • [ ] bun test is green and / still answers in single-digit milliseconds with a hundred proposals seeded.

Files I expect to change: src/pages/proposal.ts, src/pages/home.ts, src/routes.ts (the form post only), src/server.test.ts, static/app.css.

Risks: the form post goes through answer/back like every other write, with the same-origin check — a vote is a mutation and must never be reachable by a GET. Do not re-derive the tally in a template; if a number is missing, add it to what the action returns. Every name on this page is a person's name: escape all of them.

Fit: Hearth — the panel a person actually presses, honest about what pressing it will do. A person assigns; I do not.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs