Skip to content

Add household calculator tab#24

Merged
PavelMakarchuk merged 18 commits into
mainfrom
household-calculator
May 18, 2026
Merged

Add household calculator tab#24
PavelMakarchuk merged 18 commits into
mainfrom
household-calculator

Conversation

@PavelMakarchuk

Copy link
Copy Markdown
Collaborator

Summary

  • Adds a Household calculator tab alongside the existing map view.
  • Users enter state, filing status, ages, earnings (incl. spouse if joint), optional other income, and per-child ages; results show federal EITC, federal CTC, state EITC, state CTC, and total.
  • Calculations go live to api.policyengine.org/us/calculate — no precomputed data needed.

Files

  • frontend/src/api/policyengine.ts — household JSON builder + API client
  • frontend/src/components/HouseholdCalculator.tsx — form + results card
  • frontend/src/App.tsx — tab toggle between Map and Calculator

Test plan

  • npm run dev, switch to Household calculator tab
  • CA, head of household, age 40, $30k earnings, 1 child age 5 → ~$3,265 fed EITC, $2,200 fed CTC, ~$89 CA EITC, ~$630 CA CTC
  • Switch filing status to Married joint → spouse age/earnings fields appear
  • Add/remove children works
  • Year selector in the map tab carries over to the calculator
  • npm run build passes

🤖 Generated with Claude Code

PavelMakarchuk and others added 18 commits May 18, 2026 09:27
Add a household calculator view alongside the existing map. Users
enter state, filing status, ages, earnings, optional other income,
and per-child ages, then see federal EITC, federal CTC, state EITC,
state CTC, and the total. Calculations go live to the PolicyEngine
US API.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the explicit filing-status pill group with an "Add spouse"
toggle. Filing status is now derived: spouse -> JOINT, no spouse +
children -> HEAD_OF_HOUSEHOLD, otherwise SINGLE. Remove the optional
other-income field. Add the PolicyEngine favicon at public/favicon.svg
to match the path already referenced in layout.tsx metadata.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The ctc variable in PolicyEngine US is the gross credit before
tax-liability and refundability limits, which overstated the credit
for low-earnings households (e.g. $4,400 shown for a household with
$0 earnings, where the actual received amount is $0). Request and
read ctc_value instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The API returns result.tax_units.tax_unit.<var>, not
result.household.tax_units.tax_unit.<var>. The extra .household
lookup meant every variable resolved to undefined and the calculator
displayed 0 for all credits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the "Add spouse" button with an "Are you married?" checkbox
placed directly below State. When checked, spouse age renders next
to primary age and spouse earnings next to primary earnings in a
two-column row.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Children render as cards in a 3-per-row grid, wrapping to a new row
beyond three. Each card stacks the age input and a small Remove
button.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Show a Plotly line chart with federal/state EITC and CTC curves
plotted against earnings (~17 sample points from $0 to $200k). The
user's submitted earnings is marked with a dashed vertical line.

While the API sweep is in flight, the results panel shows a teal
spinner and the submit button shows an inline mini-spinner. Adds
react-plotly.js + plotly.js-dist-min as deps. Plotly is loaded via
next/dynamic with ssr:false to avoid window-not-defined on render.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Use the multi-series palette from @policyengine/design-system
(#319795, #285E61, #0EA5E9, #026AA2), Inter throughout at the
prescribed sizes (14px axis, 12px ticks), gray.200 (#E2E8F0) gridlines,
black text on white, sentence-case title, and add the PolicyEngine
teal logo as a bottom-right watermark.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the 17-call parallel sweep with a single vectorized API
call using the household.axes parameter, matching policyengine-app's
EarningsVariation approach. Now plots 401 sample points from $0 to
max(200k, 2*current_earnings) in one round-trip — both faster (one
HTTP call) and visibly smoother. Switch the line shape from spline
to linear since the dense sampling makes the curves smooth on their
own and avoids spline overshoot at EITC plateau corners.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror BaselineOnlyChart from policyengine-app: drop the in-chart
title (now rendered as an H3 above the plot), shrink the top margin,
position the legend at y=1.15 in the freed space, use per-line
hovertemplates with "If you earn X, your <credit> is Y" copy, replace
the dashed vertical "Your earnings" marker with a small dot on each
line at the current earnings (interpolated), and use rgba(0,0,0,0)
plot background per plotLayoutFont. Eliminates the title/legend
overlap visible in the previous version.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Draw a dashed gray vertical line at the user's current earnings, with
a small label anchored inside the plot area at y=0.97 (below the
legend at 1.15) so it doesn't overlap legend or title. The dots on
each line at the current earnings are kept too — they show the credit
amount per series at the user's earnings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add an effect that resets the calculation result, sweep data, and
error whenever any form input changes. Removes the stale-looking
state where the user has tweaked a field but the panel still shows
the previous calculation, until they click Calculate again.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Total Investment / Poverty Reduction / Child Poverty Reduction
metrics are aggregate state-level stats relevant only to the map
view. Render the banner only when appView is "map".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Place a Tax year dropdown (2024, 2025, 2026) to the right of the
State dropdown in a 2-column row. Year is now local to the
calculator and initialized from the App-level year prop so the
two views can be set independently.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add matching legendgroup on each line+dot pair so clicking a legend
entry hides both the line and the "you are here" marker dot
together.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pin the x-axis range to [0, max(earnings)] so the chart's left edge
sits exactly at $0 with no padding. The y-axis already had
rangemode: "tozero".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI runs bun install --frozen-lockfile; previous plotly install via
npm updated package.json without touching bun.lock, which would have
failed the install step on CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@PavelMakarchuk PavelMakarchuk marked this pull request as ready for review May 18, 2026 18:21
@PavelMakarchuk PavelMakarchuk merged commit 64415bb into main May 18, 2026
3 checks passed
@PavelMakarchuk PavelMakarchuk deleted the household-calculator branch May 18, 2026 18:22
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