Skip to content

Convert Streamlit app to React + Vite with GitHub Pages deployment#100

Merged
PavelMakarchuk merged 24 commits intomainfrom
daphnehanse11/issue99
Feb 13, 2026
Merged

Convert Streamlit app to React + Vite with GitHub Pages deployment#100
PavelMakarchuk merged 24 commits intomainfrom
daphnehanse11/issue99

Conversation

@daphnehanse11
Copy link
Copy Markdown
Collaborator

@daphnehanse11 daphnehanse11 commented Feb 10, 2026

Summary

Converts the marriage incentive calculator from a Python/Streamlit app to a React + Vite single-page app using the PolicyEngine REST API directly. Designed for deployment to GitHub Pages.

Features

  • Income comparison: Compares married vs. unmarried filing for any head/spouse income combination
  • Benefit breakdown tabs: Summary, Benefits, Healthcare, Credits, Taxes, State — each with individual program rows and "Other" reconciliation rows
  • Head/Spouse columns: Breakdown tables show individual Head (Single) and Spouse (Single) values alongside combined totals
  • Healthcare toggle: Headline banner toggle to include/exclude the cash value of healthcare coverage (Medicaid, CHIP, ACA premium subsidies). These are separate from household_net_income in PolicyEngine and tracked via healthcare_benefit_value
  • Heatmap: 33x33 grid showing marriage bonus/penalty across income combinations, with a "You" marker at the user's exact situation. Dynamically scales range based on inputs
  • Fullscreen heatmap: Expand button opens a full-viewport overlay (Esc to close)
  • Inputs: State, year (2024–2028), head/spouse income, head/spouse age, disability status, pregnancy status, children (with age and disability)
  • Shareable URLs: All inputs encoded in the URL hash for sharing/bookmarking
  • Valentine's Day mode: Press V to toggle (easter egg)
  • Code-split Plotly: ~4.7MB Plotly chunk lazy-loaded only when heatmap renders

Key technical decisions

  • household_benefits does NOT include Medicaid, CHIP, or PTC — those are healthcare benefits tracked separately via healthcare_benefit_value
  • household_net_income does NOT include healthcare value; household_net_income_including_health_benefits adds it
  • Heatmap grid must be transposed from API's head-major order to Plotly's z[row][col] = y[row], x[col] orientation
  • Exact marker delta computed from summary API results to avoid grid-snapping inaccuracy

After merge: GitHub Pages setup

  1. In the repo Settings > Pages, set source to "GitHub Actions"
  2. Add a .github/workflows/deploy.yml workflow that runs npm ci && npm run build and deploys the dist/ folder
  3. vite.config.js already sets base: '/us-marriage-incentive/' for the Pages path
  4. The public/ folder contains favicon.svg — it will be copied to dist/ at build time

Test plan

  • Verify calculations match PolicyEngine for a few scenarios (e.g., $30k head, $0 spouse, CA, 1 child age 0)
  • Toggle healthcare checkbox and confirm headline number changes by the healthcare benefit delta
  • Check Benefits tab: individual programs + Other Benefits = Summary Benefits row
  • Check Healthcare tab: Medicaid + CHIP + PTC + Other Healthcare = Summary Healthcare Benefits row
  • Test heatmap marker shows correct value matching headline
  • Test fullscreen heatmap (Expand button, Esc to close)
  • Test shareable URL (copy link, open in new tab)
  • Test with high incomes ($200k+) to verify dynamic heatmap range

🤖 Generated with Claude Code

daphnehanse11 and others added 10 commits February 10, 2026 09:26
Replace the Python/Streamlit frontend with a Vite + React app that calls
the PolicyEngine API directly, enabling static hosting on GitHub Pages.

- React app with form inputs, tabbed results, and Plotly heatmap
- Uses live PolicyEngine API (api.policyengine.org) for all calculations
- PolicyEngine appv2 teal color scheme
- Lazy-loaded Plotly for fast initial page load (158KB vs 4.9MB)
- Shareable URL state (auto-calculates from URL params)
- "You are here" marker on heatmap
- Mobile-responsive layout
- GitHub Actions workflow for automated deployment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add classy marriage bonus/penalty headline banner with left border accent
- Add year dropdown (2024-2028) defaulting to 2026, threaded through URL state and all API calls
- Fix program name display: EITC, SNAP, TANF, WIC, SSI, ACP, CTC, CDCC now show as acronyms
- Responsive headline banner layout for mobile

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Share button in headline banner copies URL to clipboard with "Copied!" feedback
- All number inputs select their value on focus so typing replaces the leading 0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Store income and age values as strings internally, convert to numbers
only on submit. Inputs start empty with placeholder "0".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pink theme with floating hearts background
- "Love & Taxes Calculator" header and Valentine tagline
- Heatmap swaps to pink/rose colorscale with heart marker
- Heart confetti burst animation on toggle
- Full color override for all UI elements
- Press V again to toggle off. Single commit for easy revert.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… fix benefit accounting

Major changes:
- Fix benefit/credit classification: Medicaid, CHIP, and PTC are healthcare
  benefits (not in household_benefits or household_refundable_tax_credits),
  tracked separately via healthcare_benefit_value
- Add healthcare toggle on headline banner to include/exclude healthcare
  coverage value (Medicaid, CHIP, ACA subsidies) from the net income figure
- Add Healthcare tab showing individual health program breakdown
- Add head/spouse age inputs (was hardcoded to 40, affects ACA calculations)
- Add head/spouse individual columns in breakdown tables
- Add State tab with state credits and taxes
- Add "Other" reconciliation rows ensuring breakdown totals match aggregates
- Add pregnancy inputs and URL hash persistence
- Increase heatmap resolution from 17x17 to 33x33 ($2.5k steps at $80k)
- Add fullscreen heatmap overlay (Expand button, Esc to close)
- Add head_start, early_head_start, social_security to tracked benefits
- Fix favicon path for GitHub Pages (use relative path)
- Fix heatmap axis transposition (head-major to Plotly row=spouse,col=head)
- Fix heatmap marker showing exact delta instead of snapped grid value
- Dynamic heatmap range based on actual incomes (no more $80k cap)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@daphnehanse11 daphnehanse11 changed the title Convert Streamlit app to React with GitHub Pages deployment Convert Streamlit app to React + Vite with GitHub Pages deployment Feb 12, 2026
PavelMakarchuk and others added 14 commits February 13, 2026 09:28
…down

- Request all per-program variables in heatmap API calls (no extra computation cost)
- Click a heatmap cell to update the table with that cell's full breakdown
- "You" marker moves to the clicked cell with adaptive text color for readability
- Sidebar income inputs update to reflect the selected cell's incomes
- Flip table back to programs-as-rows orientation
- Fix heatmap position with 1fr 1fr split so it doesn't shift with table width
- Move "Powered by policyengine-us" to its own line below header

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…visibility

- Add healthcare_benefit_value delta grid so Healthcare tab shows actual
  healthcare benefit changes, not Net Income
- Summary table responds to toggle: uses health-inclusive net income when on,
  hides separate Healthcare Benefits row
- Healthcare tab hidden when toggle is off, falls back to Summary if active

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Restyle table: right-aligned numbers, tabular-nums, uppercase headers,
  tinted delta cells, first-row highlight, smooth hover transitions
- Reduce font size and padding to prevent overflow into heatmap
- Allow program name column to wrap text
- Fix tooltips clipped by overflow containers (visible overflow + z-index 100)
- Merge stateTaxes into taxes tab so state income tax shows correct values
- Remove state income tax from State Credits tab (lives in Taxes only)
- Invert delta coloring for taxes: reductions green, increases red
- Hide Healthcare Benefits row from summary when toggle off, show when on
- Rename State tab to State Credits, spell out Disabled in child inputs
- Update headline to "No marriage incentive or penalty"
- Nudge colorbar label right with xpad

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fetch variable trees from PolicyEngine /us/metadata at build time,
eliminating fragile hard-coded lists and fixing several data bugs:

- ctc → refundable_ctc (refundable portion only)
- cdcc removed (nonrefundable, already in income tax)
- medicaid → medicaid_cost (dollar value, not eligibility bool)
- premium_tax_credit → aca_ptc (canonical child)
- employee SS + Medicare → employee_payroll_tax (single canonical var)
- Added ~9 missing programs: housing subsidy, unemployment comp,
  broadband subsidy, energy rebates, state benefits, and more
- State credits heatmap now has its own dedicated grid

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
32 tests across 5 scenarios verifying:
- All metadata variable keys are present and numeric
- Benefits/credits/taxes/health breakdowns sum to aggregates
- Correct variable names (refundable_ctc, medicaid_cost, aca_ptc, etc.)
- getCategorizedPrograms returns complete shapes for all 3 scenarios
- buildCellResults produces correct dicts from mock programData
- Low-income scenario triggers expected programs (SNAP, Medicaid, EITC)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The "Other Credits" residual row was comparing federal credit
breakdowns against householdRefundableCredits, which includes both
federal and state credits. This caused state_refundable_credits
to leak into the federal credits tab as "Other Credits".

Fix: subtract state_refundable_credits from the aggregate before
computing the residual, so Other Credits is truly zero when federal
credits are fully accounted for.

Also adds audit-values tests that print exact dollar amounts for
5 scenarios across all categories.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… tests

- Restyle headline banner (compact, flat backgrounds), pill tabs, move
  health toggle below table
- Add heatmap title and hover labels showing breakdown name and incomes
- Break out per-state credit variables (e.g. CalEITC, NY CTC) instead of
  opaque "Other State Credits" bucket using metadata-driven discovery
- Use household_refundable_state_tax_credits (household-level) for reliable
  2D heatmap grids; compute Federal Credits = Total - State
- Default child age to 5 when adding a new child
- Cross-validate JS API extraction against policyengine-us Python fixtures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Per-state credits are now fully broken out, so the addOtherRow
fallback for the state tab is unnecessary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only strip the state_refundable_credits aggregate key when per-state
credit entries are present. Fixes empty table for heatmap cell clicks
and states without discovered per-state credits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Request per-state credit variables in heatmap API calls, include their
arrays in programData, and use label-keyed entries in buildCellResults.
Heatmap cell clicks now show actual credit names (CalEITC, NY CTC, etc.)
instead of an empty table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use #0D9488 (medium teal) instead of #285E61 (near-black) at the
bonus extreme, and start teal at 0.65 instead of 0.7 so green appears
earlier. Penalty side stays dark grey.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Negative values use dark/medium grey (matching normal mode) while
positive values use pink/rose (valentine theme).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused .cell-selection-banner and .data-table--transposed CSS
- Extract shared heatmapProps object to avoid duplicating 11 props
- Replace 165-line Python-only gitignore boilerplate with minimal entries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@PavelMakarchuk PavelMakarchuk merged commit 3b131b5 into main Feb 13, 2026
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.

2 participants