--- name: policyengine-app description: PolicyEngine React web application - the user interface at policyengine.org --- # PolicyEngine App The PolicyEngine App is the React-based web application that users interact with at policyengine.org. ## For Users 👥 ### What is the App? The app at policyengine.org provides: - Interactive household calculator - Policy reform creator - Population impact analysis - Blog and research hub **Access:** https://policyengine.org ### App Features **Calculator:** - Enter household details - See tax and benefit calculations - Visualize marginal tax rates - Compare scenarios **Policy designer:** - Browse all parameters - Create custom reforms - Share via URL - Download charts **Research hub:** - Read policy analysis - Explore modeled programs - Access documentation ## For Analysts 📊 ### Understanding App URLs Reform URLs encode all policy changes in the query string, allowing sharing and reproducibility. **Example URL:** ``` policyengine.org/us/policy? focus=policyOutput.policyBreakdown& reform=67696& region=enhanced_us& timePeriod=2025& baseline=2 ``` **Parameters:** - `focus` - Which section to display - `reform` - Reform ID from database - `region` - Geographic scope (enhanced_us, CA, congressional districts) - `timePeriod` - Year of analysis - `baseline` - Baseline policy ID ### Embedding PolicyEngine **iFrame integration:** ```html ``` **Parameter:** - `embedded=true` - Removes navigation, optimizes for embedding ### URL Structure **Household calculator:** ``` /us/household?household=12345 /uk/household?household=67890 ``` **Policy page:** ``` /us/policy?reform=12345 /uk/policy?reform=67890 ``` **Research/blog:** ``` /us/research/article-slug /uk/research/article-slug ``` ## For Contributors 💻 ### Repository **Location:** PolicyEngine/policyengine-app **Clone:** ```bash git clone https://github.com/PolicyEngine/policyengine-app cd policyengine-app ``` ### Current Architecture **To see current structure:** ```bash tree src/ -L 2 # Key directories: ls src/ # - pages/ - Page components # - applets/ - Reusable UI modules # - api/ - API integration # - controls/ - Form controls # - layout/ - Layout components # - posts/ - Blog posts # - routing/ - Routing configuration # - hooks/ - Custom React hooks # - data/ - Static data ``` ### Technology Stack **Current dependencies:** ```bash # See package.json for versions cat package.json # Key dependencies: # - React 18 # - React Router v6 # - Plotly.js # - Ant Design # - axios ``` ### React Patterns (Critical) **✅ Functional components only (no classes):** ```javascript // CORRECT import { useState, useEffect } from "react"; export default function TaxCalculator({ income }) { const [tax, setTax] = useState(0); useEffect(() => { calculateTax(income).then(setTax); }, [income]); return
Tax: ${tax}
; } ``` **❌ Class components forbidden:** ```javascript // WRONG - Don't use class components class TaxCalculator extends Component { // ... } ``` **To find component examples:** ```bash # Reference components ls src/pages/ ls src/applets/ # See a complete page cat src/pages/HouseholdPage.jsx ``` ### State Management **No global state (Redux, Context) - lift state up:** ```javascript // Parent manages state function PolicyPage() { const [reform, setReform] = useState({}); const [impact, setImpact] = useState(null); return ( <> ); } ``` **To see state patterns:** ```bash # Find useState usage grep -r "useState" src/pages/ | head -20 ``` ### API Integration **To see current API patterns:** ```bash cat src/api/call.js # Base API caller cat src/api/variables.js # Variable metadata cat src/api/parameters.js # Parameter metadata ``` **Standard pattern:** ```javascript import { api call } from "api/call"; // Fetch data const result = await call( `/us/calculate`, { household: householdData }, "POST" ); ``` ### Routing **To see current routing:** ```bash cat src/routing/routes.js # Routes defined with React Router v6 # See examples: grep -r "useNavigate" src/ grep -r "useSearchParams" src/ ``` **URL parameters:** ```javascript import { useSearchParams } from "react-router-dom"; const [searchParams, setSearchParams] = useSearchParams(); // Read const reformId = searchParams.get("reform"); // Update setSearchParams({ ...Object.fromEntries(searchParams), reform: newId }); ``` ### Custom Hooks **To see PolicyEngine-specific hooks:** ```bash ls src/hooks/ # - useCountryId.js - Current country # - useDisplayCategory.js # - etc. ``` **Usage:** ```javascript import { useCountryId } from "hooks/useCountryId"; function Component() { const [countryId, setCountryId] = useCountryId(); // countryId = "us", "uk", or "ca" } ``` ### Charts and Visualization **Plotly integration:** ```bash # See chart components ls src/pages/policy/output/ # Reference implementation cat src/pages/policy/output/EconomyOutput.jsx ``` **Standard Plotly pattern:** ```javascript import Plot from "react-plotly.js"; const layout = { font: { family: "Roboto Serif" }, plot_bgcolor: "white", // PolicyEngine branding }; ; ``` ### Blog Posts **To see blog post structure:** ```bash ls src/posts/articles/ # Read a recent post cat src/posts/articles/harris-eitc.md ``` **Blog posts:** - Written in Markdown - Stored in `src/posts/articles/` - Include metadata (title, date, authors) - Follow policyengine-writing-skill style **Adding a post:** ```bash # Create new file # src/posts/articles/my-analysis.md # Add to index (if needed) # See existing posts for format ``` ### Styling **Current styling approach:** ```bash # See style configuration ls src/style/ # Colors cat src/style/colors.js # Ant Design theme cat src/style/theme.js ``` **PolicyEngine colors:** - Teal: `#39C6C0` (primary accent) - Blue: `#2C6496` (charts, links) - Dark gray: `#616161` (text) ### Testing **To see current tests:** ```bash ls src/__tests__/ # Run tests make test # Test pattern cat src/__tests__/example.test.js ``` **Testing libraries:** - Jest (test runner) - React Testing Library (component testing) - User-centric testing (not implementation details) ### Development Server **Start locally:** ```bash make debug # Opens http://localhost:3000 ``` **Environment:** ```bash # Environment variables cat .env.example # Config ls src/config/ ``` ### Building and Deployment **Build:** ```bash make build # Creates optimized production build ``` **Deployment:** ```bash # See deployment config cat netlify.toml # or appropriate hosting config ``` ## Component Patterns ### Standard Component Structure **To see well-structured components:** ```bash # Example page cat src/pages/HouseholdPage.jsx # Example applet cat src/applets/PolicySearch.jsx ``` **Pattern:** ```javascript import { useState, useEffect } from "react"; import { useSearchParams } from "react-router-dom"; import { useCountryId } from "hooks/useCountryId"; export default function MyComponent({ prop1, prop2 }) { // 1. Hooks first const [state, setState] = useState(initialValue); const [countryId] = useCountryId(); const [searchParams] = useSearchParams(); // 2. Effects useEffect(() => { // Side effects }, [dependencies]); // 3. Event handlers const handleClick = () => { setState(newValue); }; // 4. Render return (
{/* JSX */}
); } ``` ### Component Size Limit **Keep components under 150 lines after formatting.** **If component is too large:** 1. Extract sub-components 2. Move logic to custom hooks 3. Split into multiple files **To find large components:** ```bash # Find files >150 lines find src/ -name "*.jsx" -exec wc -l {} \; | sort -rn | head -20 ``` ### File Naming **Components:** PascalCase.jsx - `HouseholdPage.jsx` - `PolicySearch.jsx` - `ImpactChart.jsx` **Utilities:** camelCase.js - `formatCurrency.js` - `apiUtils.js` - `chartHelpers.js` **Hooks:** camelCase.js with 'use' prefix - `useCountryId.js` - `usePolicy.js` ## Common Development Tasks ### Task 1: Add New Page 1. **See page structure:** ```bash cat src/pages/HouseholdPage.jsx ``` 2. **Create new page:** ```javascript // src/pages/MyNewPage.jsx export default function MyNewPage() { return
Content
; } ``` 3. **Add route:** ```bash # See routing cat src/routing/routes.js # Add your route following the pattern ``` ### Task 2: Add New Chart 1. **See chart examples:** ```bash ls src/pages/policy/output/ cat src/pages/policy/output/DistributionalImpact.jsx ``` 2. **Create chart component:** ```javascript import Plot from "react-plotly.js"; export default function MyChart({ data }) { return ( ); } ``` ### Task 3: Add Blog Post 1. **See post structure:** ```bash cat src/posts/articles/harris-eitc.md ``` 2. **Create post:** ```bash # Create markdown file # src/posts/articles/my-analysis.md # Follow policyengine-writing-skill for style ``` 3. **Images:** ```bash # Store in public/images/posts/ # Reference in markdown ``` ## API Integration Patterns ### Fetching Data **To see API call patterns:** ```bash cat src/api/call.js ``` **Standard pattern:** ```javascript import { call } from "api/call"; const fetchData = async () => { const result = await call( `/us/calculate`, { household: data }, "POST" ); return result; }; ``` ### Loading States **Pattern:** ```javascript const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [data, setData] = useState(null); useEffect(() => { setLoading(true); fetchData() .then(setData) .catch(setError) .finally(() => setLoading(false)); }, [dependencies]); if (loading) return ; if (error) return ; return ; ``` ## Performance Patterns ### Code Splitting **To see code splitting:** ```bash grep -r "React.lazy" src/ ``` **Pattern:** ```javascript import { lazy, Suspense } from "react"; const HeavyComponent = lazy(() => import("./HeavyComponent")); function Page() { return ( }> ); } ``` ### Memoization **Use React.memo for expensive components:** ```javascript import { memo } from "react"; const ExpensiveChart = memo(function ExpensiveChart({ data }) { // Only re-renders if data changes return ; }); ``` ## Accessibility **Requirements:** - Semantic HTML elements - ARIA labels for complex widgets - Keyboard navigation - Color contrast (WCAG AA) **To see accessibility patterns:** ```bash grep -r "aria-" src/ grep -r "role=" src/ ``` ## Country-Specific Features ### Country Switching **To see country switching:** ```bash cat src/hooks/useCountryId.js ``` **Usage:** ```javascript import { useCountryId } from "hooks/useCountryId"; function Component() { const [countryId] = useCountryId(); // "us", "uk", or "ca" // Load country-specific data const data = countryId === "us" ? usData : ukData; } ``` ### Country-Specific Content **Conditional rendering:** ```javascript {countryId === "us" && } {countryId === "uk" && } ``` **To find country-specific code:** ```bash grep -r "countryId ===" src/ ``` ## Development Workflow ### Local Development **Start dev server:** ```bash make debug # App runs on http://localhost:3000 # Connects to production API by default ``` **Connect to local API:** ```bash # See environment configuration cat src/config/environment.js # Or set environment variable REACT_APP_API_URL=http://localhost:5000 make debug ``` ### Testing **Run tests:** ```bash make test ``` **Watch mode:** ```bash npm test -- --watch ``` **Coverage:** ```bash npm test -- --coverage ``` ### Linting and Formatting **Format code (critical before committing):** ```bash make format # Or manually npm run lint -- --fix npx prettier --write . ``` **Check linting (CI check):** ```bash npm run lint -- --max-warnings=0 ``` ## Current Implementation Reference ### Component Structure **To see current page structure:** ```bash ls src/pages/ # - HouseholdPage.jsx # - PolicyPage.jsx # - HomePage.jsx # - etc. ``` **To see a complete page:** ```bash cat src/pages/PolicyPage.jsx ``` ### API Call Patterns **To see current API integration:** ```bash cat src/api/call.js # Base caller cat src/api/variables.js # Variable metadata fetching cat src/api/parameters.js # Parameter metadata fetching ``` ### Routing Configuration **To see current routes:** ```bash cat src/routing/routes.js ``` ### Form Controls **To see PolicyEngine-specific form controls:** ```bash ls src/controls/ # - InputField.jsx # - SearchParamControl.jsx # - etc. ``` ### Chart Components **To see chart implementations:** ```bash ls src/pages/policy/output/ # - BudgetaryImpact.jsx # - DistributionalImpact.jsx # - PovertyImpact.jsx # - etc. ``` **Reference chart:** ```bash cat src/pages/policy/output/DistributionalImpact.jsx ``` ## Multi-Repository Integration ### How App Relates to Other Repos ``` policyengine-core (engine) ↓ policyengine-us, policyengine-uk (country models) ↓ policyengine-api (backend) ↓ policyengine-app (you are here) ``` **Understanding the stack:** - See `policyengine-core-skill` for engine concepts - See `policyengine-us-skill` for what variables/parameters mean - See `policyengine-api-skill` for API endpoints the app calls ### Blog Posts Reference Country Models **Blog posts often reference variables:** ```bash # Posts reference variables like "income_tax", "ctc" # See policyengine-us-skill for variable definitions cat src/posts/articles/harris-eitc.md ``` ## Common Development Tasks ### Task 1: Add New Parameter to UI 1. **Understand parameter:** ```bash # See parameter in country model cd ../policyengine-us cat policyengine_us/parameters/gov/irs/credits/ctc/amount/base_amount.yaml ``` 2. **Find similar parameter in app:** ```bash cd ../policyengine-app grep -r "ctc.*amount" src/pages/policy/ ``` 3. **Add UI control following pattern** ### Task 2: Add New Chart 1. **See existing charts:** ```bash cat src/pages/policy/output/DistributionalImpact.jsx ``` 2. **Create new chart component** 3. **Add to policy output page** ### Task 3: Fix Bug in Calculator 1. **Find relevant component:** ```bash # Search for the feature grep -r "keyword" src/pages/ ``` 2. **Read component code** 3. **Make fix following React patterns** 4. **Test with dev server:** ```bash make debug ``` ## Build and Deployment **Production build:** ```bash make build # Creates optimized bundle in build/ ``` **Deployment:** ```bash # See deployment configuration cat netlify.toml # or appropriate config ``` **Environment variables:** ```bash # React env vars must have REACT_APP_ prefix REACT_APP_API_URL=https://api.policyengine.org # Or use config file pattern (recommended) cat src/config/environment.js ``` ## Style Guide **Follow policyengine-standards-skill for:** - ESLint configuration - Prettier formatting - Component size limits - File organization **Follow policyengine-writing-skill for:** - Blog post content - Documentation - UI copy ## Resources **Repository:** https://github.com/PolicyEngine/policyengine-app **Live app:** https://policyengine.org **Staging:** https://staging.policyengine.org (if applicable) **Related skills:** - **policyengine-api-skill** - Understanding the backend - **policyengine-us-skill** - Understanding variables/parameters - **policyengine-writing-skill** - Blog post style - **policyengine-standards-skill** - Code quality