Skip to content

feat(explore): surface policy bills as top-level data source tab#184

Merged
William-Hill merged 6 commits into
mainfrom
feat/183-policy-bills-tab
Apr 11, 2026
Merged

feat(explore): surface policy bills as top-level data source tab#184
William-Hill merged 6 commits into
mainfrom
feat/183-policy-bills-tab

Conversation

@William-Hill

@William-Hill William-Hill commented Apr 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • Promote Policy Bills from a buried per-state badge to a top-level tab in the explore page's DataSourceTabs, matching the design direction in refactor(explore): surface policy bills as a top-level data source tab #183. The D4BL founder didn't know the feature existed when shown the tool; this PR makes it discoverable in zero clicks.
  • Bills-first layout: recency-colored state map (green hot = recent, dark = dormant) + filter rail (state / status / topic) + activity feed sorted by last_action_date DESC with stagger-fade on the first 5 rows.
  • Every bill row gets a 4-segment PhaseGlyph showing where it sits in the legislative lifecycle (introduced / passed / signed / failed), mapped to the exact 5 status values the ingestion pipeline emits.

What changed

New components (ui-nextjs/components/explore/)

  • PhaseGlyph.tsx — 4-segment monospace lifecycle indicator with tone-mapped colors (active green / signed bright / failed red / dormant gray), optional pulse on the last filled segment
  • BillFeedRow.tsx — one feed row with phase glyph, bill number, topic chips, title, relative last-action timestamp, view link
  • PolicyFilterPanel.tsx — state selector + status chips (with inline phase glyphs) + topic chips, narrowed types (Set<BillStatus>, Set<PolicyTopic>)
  • PolicyExploreView.tsx — owns its own fetch lifecycle, composes StateMap + PolicyFilterPanel + activity feed

Modified

  • ui-nextjs/lib/explore-config.ts — added ABBREV_TO_FIPS, aggregateBillsByState, daysSinceLastAction, billAggregateToIndicatorRow, formatRelativeDate, BILL_STATUSES / BillStatus, POLICY_TOPICS / PolicyTopic, statusToPhase + PhaseGlyph types, plus a policy entry in DATA_SOURCES
  • ui-nextjs/app/explore/page.tsx — early-return in fetchData when activeSource.key === 'policy'; branch render to <PolicyExploreView /> in place of the metric-map layout
  • ui-nextjs/app/globals.css@keyframes billFadeIn + .bill-fade-in utility class + prefers-reduced-motion override
  • ui-nextjs/components/explore/PolicyTable.tsx — import POLICY_TOPICS from explore-config.ts (dedup with new filter panel)

Design direction

The tab intentionally defaults to a state view, not a national aggregate — bills are event-shaped data (status + timestamps), not a continuous metric, so a choropleth of raw counts would just reward populous states. The map is recolored by recency of last bill action instead. Full design rationale is in #183's body.

What's explicitly out of scope

  • Unifying PolicyTable.STATUS_COLORS with PhaseGlyph.TONE_COLORS (would change the visual of the existing per-state drawer on other tabs — valid follow-up, not this PR)
  • Shared <FilterChip> / <BillRow> primitive across PolicyTable / PolicyFilterPanel / MetricFilterPanel (same reasoning)
  • Server-side aggregation endpoints, URL deep-linking, new font family
  • Bill detail pages

Test plan

  • npm run lint in ui-nextjs/ — clean (0 errors, 1 pre-existing warning unrelated to this PR)
  • npm run build in ui-nextjs//explore route compiles
  • Visit /explore → click "Policy Bills" tab → bills load, feed shows most recent 50
  • Toggle status chips → feed filters, no re-fetch
  • Toggle topic chips → feed filters
  • Pick a state from the dropdown OR click a state on the map → feed narrows, header updates to show ${State} — ${N} bills tracked · last action Xd ago
  • Click the same state again → deselects, feed returns to "all states"
  • Switch back to Census / CDC / any other tab → per-state PolicyBadge still appears and opens the slide-out drawer as before (no regression)
  • prefers-reduced-motion active → stagger-fade animation disabled
  • First row's phase glyph pulses subtly on its last filled segment
  • States with no recent bill activity appear dark on the map; recent states appear bright green

Closes #183

Summary by CodeRabbit

  • New Features

    • Policy Bills exploration view with interactive state map, filters, and activity feed
    • Filter panel for state/status/topic selection and a clear-filters action
  • UI

    • Phase glyphs and bill feed rows with entrance animation, stagger/pulse cues, and reduced-motion support
  • Bug Fixes

    • Feed shows newest bills first
    • Policy tab hides unrelated error banner and stops unnecessary metric loads
  • Tweaks

    • Unified topic list across policy views

The policy bills feature was previously buried as a small badge next to
a selected state on other data source tabs, below five other components.
The D4BL founder didn't know the feature existed when shown the tool.

Promote Policy Bills to a top-level entry in DataSourceTabs, with a
bills-first layout that doesn't require a state click to discover:

- Recency-colored state map (green hot = recent action, dark = dormant)
- Filter rail for state / status / topic (narrowed via BillStatus /
  PolicyTopic types so typos become compile errors)
- Activity feed sorted by last_action_date DESC with stagger-fade
  entrance on the first 5 rows
- 4-segment PhaseGlyph per bill showing legislative lifecycle
  (introduced / passed / signed / failed), mapped to the 5 statuses
  the ingestion pipeline actually emits
- Empty-state placeholder in terminal-style monospace

The existing per-state PolicyBadge on other tabs is preserved unchanged.
PolicyExploreView owns its own fetch lifecycle; page.tsx short-circuits
the metric-oriented fetchData when activeSource.key === 'policy'.
POLICY_TOPICS is hoisted into explore-config.ts as the single source of
truth for both PolicyTable and PolicyFilterPanel.

Closes #183
@coderabbitai

coderabbitai Bot commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a top-level "policy" data source and a bills-first view. When the policy tab is active ExplorePage renders PolicyExploreView (map colored by bill recency, PolicyFilterPanel, and an activity feed with phase glyphs); metric fetch/render is short-circuited for the policy tab.

Changes

Cohort / File(s) Summary
Policy UI components
ui-nextjs/components/explore/BillFeedRow.tsx, ui-nextjs/components/explore/PhaseGlyph.tsx, ui-nextjs/components/explore/PolicyExploreView.tsx, ui-nextjs/components/explore/PolicyFilterPanel.tsx
New client components implementing the bills-focused UX: feed rows (stagger/pulse), 5‑segment phase glyph, PolicyExploreView (auth, fetch, aggregate, map, feed) and filter rail (state/status/topic).
Page integration
ui-nextjs/app/explore/page.tsx
Conditional rendering: when activeSource.key === 'policy' render PolicyExploreView; metric-oriented fetchData short-circuits for policy and the global error banner is suppressed for this tab.
Config & domain logic
ui-nextjs/lib/explore-config.ts
Added policy domain types/constants (BILL_STATUSES, POLICY_TOPICS, BillPhase, PHASE_GLYPH_SEGMENTS), aggregation/utilities (aggregateBillsByState, billAggregateToIndicatorRow, formatRelativeDate, daysSinceLastAction), ABBREV_TO_FIPS, and a policy entry in DATA_SOURCES.
API ordering tweak
src/d4bl/app/api.py
get_policies now orders by last_action_date.desc().nullslast() so newest bills are selected before applying the limit.
PolicyTable small change
ui-nextjs/components/explore/PolicyTable.tsx
Topic chip list now imports shared POLICY_TOPICS instead of a local array.
Styling / animation
ui-nextjs/app/globals.css
Added @keyframes bill-fade-in and .bill-fade-in utility (360ms ease-out) with prefers-reduced-motion opt-out.

Sequence Diagram

sequenceDiagram
    participant User
    participant ExplorePage
    participant PolicyExploreView
    participant API_Server as API_Server
    participant StateMap
    participant PolicyFilterPanel
    participant BillFeed as BillFeedRow

    User->>ExplorePage: select "Policy" tab
    ExplorePage->>PolicyExploreView: render (activeSource.key === 'policy')
    PolicyExploreView->>API_Server: GET /api/explore/policies?limit=...
    API_Server-->>PolicyExploreView: bills[]
    PolicyExploreView->>PolicyExploreView: aggregateBillsByState(), compute indicators
    PolicyExploreView->>StateMap: render with recency coloring
    PolicyExploreView->>PolicyFilterPanel: render filters (state/status/topic)
    User->>PolicyFilterPanel: update filters
    PolicyFilterPanel->>PolicyExploreView: onChange(filters)
    PolicyExploreView->>PolicyExploreView: filter & sort bills (last_action_date DESC)
    PolicyExploreView->>BillFeed: render feed (staggered animation, pulse newest)
    BillFeed->>User: display bill rows with PhaseGlyph and links
    User->>StateMap: click state
    StateMap->>PolicyExploreView: toggle stateFips
    PolicyExploreView->>BillFeed: re-render filtered feed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: surfacing policy bills as a top-level data source tab in the explore interface.
Linked Issues check ✅ Passed The PR comprehensively implements all primary coding objectives from issue #183: adds policy to DATA_SOURCES [#183], implements bills-focused layout with state view [#183], decouples bills fetch [#183], creates activity feed with last_action_date sorting [#183], implements phase glyphs [#183], adds stagger-fade animation respecting prefers-reduced-motion [#183], and preserves existing PolicyBadge behavior [#183].
Out of Scope Changes check ✅ Passed All changes remain within stated scope: no backend schema modifications, no bill detail pages, no server-side aggregation, no URL deep-linking, no new fonts, and no new backend endpoints—only client-side integration of existing /api/explore/policies.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/183-policy-bills-tab

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ade1ada02f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx Outdated
Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx Outdated
@greptile-apps

greptile-apps Bot commented Apr 11, 2026

Copy link
Copy Markdown

Greptile Summary

This PR promotes Policy Bills from a buried per-state drawer to a top-level explore tab, wiring up a new PolicyExploreView that owns its own fetch lifecycle, a recency-heat state map, a filter rail, and an activity feed sorted by last_action_date. New components (PhaseGlyph, BillFeedRow, PolicyFilterPanel) are well-structured and follow existing patterns. The integration in page.tsx — early-returning in fetchData and branching render — is clean and doesn't regress the existing metric-view layout.

Key changes:

  • explore-config.ts gains FIPS_TO_ABBREV / ABBREV_TO_FIPS lookup maps, aggregateBillsByState, billAggregateToIndicatorRow, statusToPhase, formatRelativeDate, and the policy entry in DATA_SOURCES.
  • PolicyExploreView fetches up to 5 000 bills client-side, filters and sorts in useMemo, and slices to 50 for display.
  • PhaseGlyph renders a 4-segment monospace lifecycle bar with tone-mapped colors (active / signed / failed / dormant) and an optional pulse on the most-recent row.
  • globals.css adds a billFadeIn keyframe with a correct prefers-reduced-motion override.
  • PolicyTable.tsx is updated to import POLICY_TOPICS from the shared config (deduplication).

Three minor P2 items worth addressing:

  • The activity-feed section shows '// select a state to begin monitoring' while the initial fetch is still in flight (loading=true, allBills=null), which is misleading because no user action is actually required.
  • stateNameByFips is rebuilt on every render; wrapping it in useMemo prevents unnecessary re-renders of PolicyFilterPanel.
  • Bill rows are keyed by state + bill_number, which may collide across legislative sessions if the API ever returns multi-session data.

Confidence Score: 4/5

PR is on the happy path to merge; all three remaining items are P2 polish with no production-reliability risk.

The core implementation is solid — correct data flow, clean component boundaries, proper AbortController usage, accessibility attributes, and no regression to existing tabs. The three P2 issues (misleading loading empty-state, missing useMemo on stateNameByFips, potential key collision) are low-severity and don't affect correctness in the current data volume. None block merge.

ui-nextjs/components/explore/PolicyExploreView.tsx — the three P2 items all live here.

Important Files Changed

Filename Overview
ui-nextjs/components/explore/PolicyExploreView.tsx New top-level view component — owns fetch lifecycle, state filtering, map + feed composition. Minor: stateNameByFips not memoized; feed shows wrong empty-state text during initial load; bill key may collide across sessions.
ui-nextjs/lib/explore-config.ts Adds FIPS/ABBREV maps, bill aggregation helpers, statusToPhase mapping, formatRelativeDate, and a 'policy' entry in DATA_SOURCES. Logic is correct; statusToPhase correctly collapses 'other' to the default dormant case.
ui-nextjs/components/explore/PhaseGlyph.tsx New 4-segment lifecycle indicator with tone-mapped colors and optional pulse. Clean, accessible (role='img' + aria-label). No issues.
ui-nextjs/components/explore/BillFeedRow.tsx Feed row with phase glyph, topic chips, title, relative timestamp, and external link. Solid implementation; staggerIndex non-null assertion is safe given the shouldStagger guard.
ui-nextjs/components/explore/PolicyFilterPanel.tsx Filter panel with state selector, status chips (with inline phase glyphs), and topic chips. Properly uses aria-pressed for accessibility. No issues.
ui-nextjs/app/explore/page.tsx Early return in fetchData correctly skips metric fetch for the policy tab; conditional render delegates to PolicyExploreView. Error display correctly gated to non-policy tabs.
ui-nextjs/app/globals.css Adds billFadeIn keyframes and .bill-fade-in utility class with correct prefers-reduced-motion override. Clean addition.
ui-nextjs/components/explore/PolicyTable.tsx Minor change to import POLICY_TOPICS from explore-config.ts instead of a local definition. Deduplication is correct.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant EP as ExplorePage
    participant PEV as PolicyExploreView
    participant API as /api/explore/policies

    U->>EP: clicks "Policy Bills" tab
    EP->>EP: handleSourceChange('policy')
    EP->>EP: fetchData() → early return (setLoading false)
    EP->>PEV: render PolicyExploreView
    PEV->>API: GET /api/explore/policies?limit=5000
    API-->>PEV: PolicyBill[]
    PEV->>PEV: aggregateBillsByState → mapIndicators (useMemo)
    PEV->>PEV: filteredBills (useMemo, sorted by last_action_date DESC, sliced to 50)
    PEV-->>U: StateMap (recency heat) + PolicyFilterPanel + BillFeed

    U->>PEV: clicks state on map / selects state dropdown
    PEV->>PEV: setFilters({ stateFips })
    PEV->>PEV: filteredBills re-derived (client-side, no re-fetch)
    PEV-->>U: feed narrowed to selected state

    U->>PEV: toggles status / topic chip
    PEV->>PEV: setFilters({ statuses / topics })
    PEV->>PEV: filteredBills re-derived (client-side)
    PEV-->>U: feed filtered, no re-fetch
Loading

Reviews (1): Last reviewed commit: "feat(explore): surface policy bills as t..." | Re-trigger Greptile

Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx Outdated
Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx Outdated
Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui-nextjs/app/globals.css`:
- Around line 109-123: The keyframes name billFadeIn violates
keyframes-name-pattern; rename the `@keyframes` identifier to kebab-case (e.g.,
bill-fade-in) and update the corresponding .bill-fade-in rule's animation
property to reference the new kebab-case name so the `@keyframes` declaration and
the animation usage match (update the symbol `@keyframes` billFadeIn and the
.bill-fade-in animation value).

In `@ui-nextjs/components/explore/BillFeedRow.tsx`:
- Around line 66-74: The "view" link currently uses generic link text and must
include an accessible name; update the anchor rendered in BillFeedRow (the <a>
that checks bill.url) to include an aria-label that embeds identifying bill
context (for example using bill.bill_number or bill.title) such as
`aria-label={`View details for ${bill.bill_number}`}` so screen readers hear a
unique, descriptive label for each bill row; ensure the field used exists on the
passed bill object (bill.bill_number or bill.title) and falls back to a safe
value if missing.

In `@ui-nextjs/components/explore/PhaseGlyph.tsx`:
- Around line 45-47: In PhaseGlyph, the pulsing segment class uses
'animate-pulse' without respecting reduced-motion preferences; update the
conditional that builds the class for pulse && isLastFilled (referenced
variables pulse and isLastFilled in the PhaseGlyph component) to append
'motion-reduce:animate-none' alongside 'animate-pulse' so the string becomes
'inline-block w-2 h-2.5 rounded-[1px] animate-pulse motion-reduce:animate-none'
when pulsing, leaving the non-pulse branch unchanged.

In `@ui-nextjs/components/explore/PolicyExploreView.tsx`:
- Around line 27-31: The feed defaults to national because filters.stateFips is
initialized as null; update PolicyExploreView to auto-select a state after
initial data load (or make the feed conditional on filters.stateFips) by: when
bills/state list is available, setFilters to a non-null stateFips (e.g., the
user's selectedState or first state in the available states) via a useEffect
that watches the loaded state list, or alter the filteredBills computation to
return an empty/state-scoped list when filters.stateFips is null; specifically
modify the useState<PolicyFilters> initialization and add a useEffect that calls
setFilters({ ...filters, stateFips: chosenFips }) or adjust the filteredBills
logic to guard on filters.stateFips (references: PolicyFilters, filters,
setFilters, filteredBills, PolicyExploreView).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ead69e5d-4a0e-4bf3-b507-e45c228705eb

📥 Commits

Reviewing files that changed from the base of the PR and between 3c76108 and ade1ada.

📒 Files selected for processing (8)
  • ui-nextjs/app/explore/page.tsx
  • ui-nextjs/app/globals.css
  • ui-nextjs/components/explore/BillFeedRow.tsx
  • ui-nextjs/components/explore/PhaseGlyph.tsx
  • ui-nextjs/components/explore/PolicyExploreView.tsx
  • ui-nextjs/components/explore/PolicyFilterPanel.tsx
  • ui-nextjs/components/explore/PolicyTable.tsx
  • ui-nextjs/lib/explore-config.ts

Comment thread ui-nextjs/app/globals.css
Comment thread ui-nextjs/components/explore/BillFeedRow.tsx
Comment thread ui-nextjs/components/explore/PhaseGlyph.tsx
Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx
Backend:
- Add ORDER BY last_action_date DESC NULLS LAST to /api/explore/policies
  so the 5000-row limit returns the actual newest bills, not an arbitrary
  subset. Without this, the client-side sort in PolicyExploreView was
  slicing an unordered sample.

Frontend accessibility:
- Add aria-label on BillFeedRow "view" links with bill number + title,
  so screen readers no longer hear a stream of identical "view" links.
- Add motion-reduce:animate-none to the PhaseGlyph pulse segment; the
  global prefers-reduced-motion override only covered .bill-fade-in.

Frontend correctness:
- Rename @Keyframes billFadeIn → bill-fade-in (stylelint keyframes-name-
  pattern violation).
- Use bill.url as the primary React key in the activity feed, with a
  composite fallback including introduced_date. OpenStates reuses
  bill_numbers across legislative sessions, so state+bill_number is not
  a unique key.
- Memoize stateNameByFips so PolicyFilterPanel gets a stable prop
  reference across re-renders.
- Gate empty-state message on allBills !== null; the previous code
  showed "select a state to begin monitoring" during the initial load
  before bills fetched.
- Remove the dead "select a state" empty-state branch; the landing view
  intentionally shows the 50 newest bills nationally (discoverability
  goal from #183), so that branch was unreachable.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui-nextjs/components/explore/PolicyExploreView.tsx`:
- Around line 72-96: Compute the total number of matching bills before applying
FEED_LIMIT so the header shows the real filtered count: inside the useMemo that
defines filteredBills, derive a variable (e.g., totalFiltered = result.length)
immediately after filtering and before result.slice(...) and expose that value
to the UI (for example return an object {items: result.slice(0, FEED_LIMIT),
totalFiltered} or set a separate state/selector) then update the header to read
totalFiltered instead of allBills.length; touch the same logic referenced by
filteredBills, allBills, FEED_LIMIT, and filters so both the list and the
“showing X of Y” use the pre-slice total.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ea1d14a3-da58-42b5-a966-c770ff95286d

📥 Commits

Reviewing files that changed from the base of the PR and between ade1ada and 47fa3d2.

📒 Files selected for processing (5)
  • src/d4bl/app/api.py
  • ui-nextjs/app/globals.css
  • ui-nextjs/components/explore/BillFeedRow.tsx
  • ui-nextjs/components/explore/PhaseGlyph.tsx
  • ui-nextjs/components/explore/PolicyExploreView.tsx

Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx Outdated
The feed header was showing 'showing {filteredBills.length} of {allBills.length}',
which was misleading once filters were active — it could display 'showing 12 of
5000' when only 12 bills actually matched the filter. Split the useMemo into
matchingBills (full filtered result, pre-slice) and filteredBills (sliced to
FEED_LIMIT), and use matchingBills.length as the denominator so the header now
honestly reports the filtered count.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui-nextjs/components/explore/PolicyExploreView.tsx`:
- Around line 35-36: In PolicyExploreView, ensure loading is cleared whenever
you bail out due to missing auth: before any early return that checks
session?.access_token (and the other similar early return around lines 50-51),
call setLoading(false) so loading cannot remain true; in practice add
setLoading(false) immediately before each `if (!session?.access_token) return;`
(and the other auth-return) or move the auth check earlier so you never
setLoading(true) before confirming session, ensuring setLoading(false) is always
invoked on all exit paths.
- Around line 129-131: The error message div in PolicyExploreView should be made
screen-reader announceable: update the JSX for the error block in the
PolicyExploreView component to include semantic alert attributes (e.g.,
role="alert", aria-live="assertive", aria-atomic="true") so assistive tech
announces fetch failures immediately, and ensure the error value is safely
stringified (e.g., use error?.message ?? String(error)) to satisfy TypeScript
strictness before rendering.
- Line 39: The frontend currently calls
fetch(`${API_BASE}/api/explore/policies?limit=5000`) in PolicyExploreView.tsx
which silently truncates results and feeds incomplete data into
aggregateBillsByState(); either implement proper pagination or surface the limit
to users: update the fetch flow in PolicyExploreView (and any caller of
aggregateBillsByState()) to support cursor/offset pagination by requesting
batches (e.g., while the API returns a nextCursor/hasMore) and merge results
before calling aggregateBillsByState(), or if the backend cannot be changed now,
add a clear UI badge/text near the map/feed stating “Showing first 5000 bills
(results limited)” and pass that metadata into aggregateBillsByState()/map
rendering so counts are not presented as complete. Ensure you reference the API
response fields (nextCursor/hasMore or offset+total) when implementing the loop
and update calls to aggregateBillsByState() to use the concatenated result set.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 97f5e99f-6974-4f5e-8ad4-65421669f9c6

📥 Commits

Reviewing files that changed from the base of the PR and between 47fa3d2 and 313deb2.

📒 Files selected for processing (1)
  • ui-nextjs/components/explore/PolicyExploreView.tsx

Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx Outdated
Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx Outdated
Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx Outdated
- Prevent loading from getting stuck at true when auth disappears
  mid-fetch. If the request was aborted during an auth change, the
  finally block skipped setLoading(false) (signal.aborted), and the
  next call returned early at the !session?.access_token check before
  setLoading(false) could run — leaving the UI spinning forever. Now
  the early-return path explicitly clears loading and allBills.

- Surface the 5000-bill API cap in the feed header when the response
  hits the limit. Shows 'showing newest 5000' in amber with a tooltip
  explaining that per-state counts may be incomplete for dormant bills.
  Full cursor-based pagination is out of scope for this PR; this is
  the honest-label interim fix CodeRabbit suggested as an alternative.

- Add role='alert' + aria-live='polite' to the error container so fetch
  failures are announced to screen readers.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui-nextjs/components/explore/PolicyExploreView.tsx`:
- Around line 177-183: The truncation warning that currently only uses a `title`
attribute is inaccessible on touch and for many screen readers; update the UI in
PolicyExploreView around the conditional that checks `allBills.length >=
API_BILL_LIMIT` to expose the cap explanation to assistive tech by adding an
accessible label (e.g., an `aria-label` on the outer span) and/or a
visually-hidden text node (using your app's `sr-only` utility class) with the
same message ("Response hit the {API_BILL_LIMIT}-bill cap; per-state counts may
be incomplete for dormant bills.") so the information is available to screen
readers and touch users while retaining the visible "showing newest
{API_BILL_LIMIT}" text; ensure any added attributes comply with TypeScript
strict typing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3a11404f-3fcf-4c75-b5a7-c3ae414a5972

📥 Commits

Reviewing files that changed from the base of the PR and between 313deb2 and 2eaf2e6.

📒 Files selected for processing (1)
  • ui-nextjs/components/explore/PolicyExploreView.tsx

Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx
The round-3 truncation warning used a `title` attribute alone for the
cap explanation, but tooltips are unreliable for screen readers and
absent on touch devices. Add aria-label with the full cap message so
the context is announced by assistive tech while keeping the title for
hover on desktop pointer devices.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui-nextjs/components/explore/PolicyExploreView.tsx`:
- Around line 39-42: In PolicyExploreView, the early-return branch that handles
missing session access_token calls setLoading(false) and setAllBills(null) but
doesn't clear the previous error, leaving the error banner visible; update that
branch to also call the error state setter (e.g., setError(null) or
setError(undefined) depending on your state shape) before returning so any prior
fetch error is cleared when auth is gone.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b59d71b2-b514-4e7c-a850-40f5318acf08

📥 Commits

Reviewing files that changed from the base of the PR and between 2eaf2e6 and e2c054c.

📒 Files selected for processing (1)
  • ui-nextjs/components/explore/PolicyExploreView.tsx

Comment thread ui-nextjs/components/explore/PolicyExploreView.tsx
@coderabbitai

coderabbitai Bot commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 2 file(s) based on 1 unresolved review comment.

Files modified:

  • ui-nextjs/components/explore/PolicyExploreView.tsx
  • ui-nextjs/next.config.ts

Commit: 2b202dc182e13f481f64b5bd4ac43713847fecbe

The changes have been pushed to the feat/183-policy-bills-tab branch.

Time taken: 7m 8s

Fixed 2 file(s) based on 1 unresolved review comment.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
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.

refactor(explore): surface policy bills as a top-level data source tab

1 participant