Skip to content

Local-government decision UI, starting with San José - #308

Open
ThatXliner wants to merge 7 commits into
codex/issue-282-legistar-pipelinefrom
codex/issue-282-local-decisions-ui
Open

Local-government decision UI, starting with San José#308
ThatXliner wants to merge 7 commits into
codex/issue-282-legistar-pipelinefrom
codex/issue-282-local-decisions-ui

Conversation

@ThatXliner

Copy link
Copy Markdown
Collaborator

Closes #282 (UI). Stacked on #302 — the decision-oriented tRPC endpoints.

What

Replaces the buried "Local Bills" prototype with a decision-oriented local-government experience:

  • Entry pointLocalDecisionsPreview near the top of the Elections tab (plus a replacement preview on "Where & How to Vote"), jurisdiction-aware wording from the saved address, live upcoming items
  • List (/local-decisions) — Upcoming / Recently decided, topic filters (only when data exists), cursor pagination, pull-to-refresh, skeletons, stale-sync / source-error / empty states, one card per Matter
  • Detail (/local-decision-detail?id=…) — plain-language lifecycle, key facts, official source link, multi-meeting occurrence timeline with per-occurrence action/tally/named votes, published history, typed official documents, link-only public comments, labeled general participation guidance, provenance footer

Shared, jurisdiction-neutral building blocks live in components/local-government/; all presentation logic is pure and RN-free in utils/local-government.ts, typed from the real tRPC outputs (30 tests). Prototype components (LocalBillsSection, UpcomingMeetingsSection, VotingRecordsSection) are removed.

Small backend corrections in legistar.listDecisions (see first commit): the district-less ORDER BY 0 crash and an optional cursor alias for offset so tRPC infinite queries work.

Truthfulness rules baked in

  • Missing votes → "Individual votes have not been published", never "nobody voted"
  • Missing scope/fiscal/outcome → omitted or "unknown", never inferred
  • No AI/official summaries exist yet — official titles shown verbatim, labeled honestly
  • Public-comment letters: count + official link only, no names or contents
  • Participation is labeled general guidance with a verify-the-agenda warning; no manufactured deadlines or links

Screenshots (390×844, live tRPC endpoints)

Entry (Elections tab) List — upcoming (dark)
Entry List dark
List — recently decided (lifecycle variety) List — light theme
Recent Light
Detail — approved with named votes Detail — documents, privacy, participation
Detail votes Detail docs
Source-error + stale-sync state
Error

Verification

  • pnpm --filter @acme/expo format|lint|typecheck clean; test 30 pass
  • pnpm --filter @acme/api format|lint|typecheck clean; test 22 pass
  • pnpm --filter @acme/scraper test 135 pass (no regressions)
  • Full flow inspected in a mobile-sized browser against live endpoints: entry → list → detail → official source link, both themes

Backend-dependent gaps

  • No address→district GIS resolution yet (district relevance ranking exists in the API but the UI can't know the user's district); scope badges shown instead
  • No fiscal-impact field on local_decision — omitted rather than faked
  • Cited AI/official summaries remain a documented backend follow-up; OCR worker not yet running

…paginated

The relevance term fell back to `order by 0`, which Postgres rejects as an
ordinal reference, so every district-less query failed. The relevance sort
now only applies when a district filter is present.

Also add an optional `cursor` alias for `offset` so tRPC's tanstack
infinite-query helpers can drive paging, matching the content.getByType
convention. The old `offset` input stays valid for compatibility.
Run `tsx --test` over src/**/*.test.ts so utility modules without React
Native dependencies can be unit tested like the scraper and api packages.
NavHeader and Pill hardcoded white-on-dark colors, so new light-theme
surfaces rendered invisible titles and pills. ExternalLink now accepts
runtime official-source URLs instead of literal routes only, and Icon
gains users/mic/link glyphs for the decision UI.
Replace the buried Local Bills prototype with a decision-oriented flow:
entry preview on the Elections tab, a jurisdiction-neutral list screen
(upcoming/recent, topic filters, pagination, pull-to-refresh, skeletons,
stale/error/empty states) and a detail screen with the multi-meeting
timeline, named votes, official documents, link-only public comments and
labeled participation guidance.

Presentation logic lives in a pure, RN-free utils module inferred from the
real tRPC outputs so lifecycle normalization, scope labels, timeline
ordering and missing-vote language are unit tested (30 tests). Missing
fields are always shown as unknown — never as a vote that didn't happen
or a summary nobody wrote.
Entry point, list (dark/light, upcoming/recent, error state) and detail
(documents, votes, participation) captured at 390x844 against the live
tRPC endpoints.
@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
billion-nextjs Ready Ready Preview Aug 25, 2026 1:55pm

The tRPC 11.16 upgrade (via main's Expo 57 release) no longer exposes
infiniteQueryOptions on procedures whose input schema is optional, which
broke the decision list's pagination typing. Every caller sends input,
so the schema no longer needs .optional().
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.

1 participant