Deploy to Git Pages / build-and-deploy (push) Failing after 19s
React + Vite static site demonstrating the CRDC School Arrest Rate API. Features 6 interactive charts comparing observed arrest data against Bayesian model estimates across U.S. school districts, with Civilytics visual identity. - State selector and district search with 'interesting' suggestions (top arrests) - Animated histogram loading grid showing posterior draw progress - Charts: time series, rate by group, district vs national, model comparison quadrants, density proxy, exceedance probability - Static JSON fixture for national rates (no API changes needed) - Dockerfile + docker-compose.yml for self-hosted deployment - GitHub Actions workflow and _config.yml for Git Pages
138 lines
5.7 KiB
React
138 lines
5.7 KiB
React
import { useState } from 'react'
|
||
|
||
// All 50 states + DC, matching the API's ALLOWED_STATES
|
||
const STATES = [
|
||
'AL','AK','AZ','AR','CA','CO','CT','DE','DC','FL','GA','HI',
|
||
'ID','IL','IN','IA','KS','KY','LA','ME','MD','MA','MI','MN','MS','MO','MT',
|
||
'NE','NV','NH','NJ','NM','NY','NC','ND','OH','OK','OR','PA','RI','SC','SD',
|
||
'TN','TX','UT','VT','VA','WA','WV','WI','WY'
|
||
]
|
||
|
||
const STATE_NAMES = {
|
||
AL: 'Alabama', AK: 'Alaska', AZ: 'Arizona', AR: 'Arkansas', CA: 'California',
|
||
CO: 'Colorado', CT: 'Connecticut', DE: 'Delaware', DC: 'District of Columbia', FL: 'Florida',
|
||
GA: 'Georgia', HI: 'Hawaii', ID: 'Idaho', IL: 'Illinois', IN: 'Indiana', IA: 'Iowa',
|
||
KS: 'Kansas', KY: 'Kentucky', LA: 'Louisiana', ME: 'Maine', MD: 'Maryland', MA: 'Massachusetts',
|
||
MI: 'Michigan', MN: 'Minnesota', MS: 'Mississippi', MO: 'Missouri', MT: 'Montana',
|
||
NE: 'Nebraska', NV: 'Nevada', NH: 'New Hampshire', NJ: 'New Jersey', NM: 'New Mexico',
|
||
NY: 'New York', NC: 'North Carolina', ND: 'North Dakota', OH: 'Ohio', OK: 'Oklahoma',
|
||
OR: 'Oregon', PA: 'Pennsylvania', RI: 'Rhode Island', SC: 'South Carolina', SD: 'South Dakota',
|
||
TN: 'Tennessee', TX: 'Texas', UT: 'Utah', VT: 'Vermont', VA: 'Virginia',
|
||
WA: 'Washington', WV: 'West Virginia', WI: 'Wisconsin', WY: 'Wyoming'
|
||
}
|
||
|
||
/**
|
||
* Landing screen — prompts user to select a state.
|
||
* Matches the Civilytics visual style with eyebrow label, stat callout, and clean card layout.
|
||
*/
|
||
export default function StateSelector({ onNext }) {
|
||
const [query, setQuery] = useState('')
|
||
|
||
// Filter states by code or name as user types
|
||
const filtered = STATES.filter(
|
||
(code) =>
|
||
code.toLowerCase().includes(query.toLowerCase()) ||
|
||
STATE_NAMES[code].toLowerCase().includes(query.toLowerCase())
|
||
)
|
||
|
||
return (
|
||
<div style={{ padding: 'var(--space-5) 0 var(--space-7)' }}>
|
||
{/* Eyebrow */}
|
||
<span className="eyebrow">US Department of Education Civil Rights Data Collection</span>
|
||
|
||
{/* Hero */}
|
||
<h1 style={{ marginTop: 'var(--space-2)', marginBottom: 'var(--space-3)' }}>
|
||
Explore school-based arrest rates by district
|
||
</h1>
|
||
|
||
<p style={{ fontSize: '1.1rem', lineHeight: 1.7, maxWidth: '48rem' }}>
|
||
The Civil Rights Data Collection (CRDC) is the only source of data on school-related
|
||
arrests for all U.S. public schools and districts. Enter a state to see estimates for
|
||
any district — with Bayesian model comparisons that reveal how confident we can be in
|
||
each rate, even when arrests are rare events.
|
||
</p>
|
||
|
||
{/* Stat callout — key context */}
|
||
<div className="stat-callout" style={{ marginTop: 'var(--space-4)' }}>
|
||
<div>
|
||
<span className="stat-num">34,846</span>
|
||
<span className="stat-label">students arrested in 2021–22</span>
|
||
</div>
|
||
<div>
|
||
<span className="stat-num">0.72</span>
|
||
<span className="stat-label accent">arrests per 1,000 students (national rate)</span>
|
||
</div>
|
||
<div>
|
||
<span className="stat-num">11.6%</span>
|
||
<span className="stat-label">of districts reported >0 arrests</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Search input */}
|
||
<div style={{ marginTop: 'var(--space-5)' }}>
|
||
<label htmlFor="state-search" style={{ display: 'block', marginBottom: 'var(--space-2)', fontWeight: 600 }}>
|
||
Select a state to begin:
|
||
</label>
|
||
<input
|
||
id="state-search"
|
||
type="text"
|
||
placeholder="Type a state name or code (e.g., Texas, TX)…"
|
||
value={query}
|
||
onChange={(e) => setQuery(e.target.value)}
|
||
style={{
|
||
width: '100%', padding: 'var(--space-2)', fontSize: '1rem',
|
||
border: '1px solid var(--cv-rule)', borderRadius: 'var(--radius-md)',
|
||
fontFamily: 'var(--font-sans)'
|
||
}}
|
||
autoFocus
|
||
/>
|
||
|
||
{/* Filtered grid of states */}
|
||
{filtered.length > 0 && (
|
||
<div style={{
|
||
display: 'grid',
|
||
gridTemplateColumns: 'repeat(auto-fill, minmax(120px, 1fr))',
|
||
gap: 'var(--space-1)',
|
||
marginTop: 'var(--space-3)'
|
||
}}>
|
||
{filtered.map((code) => (
|
||
<button
|
||
key={code}
|
||
className="cv-card"
|
||
style={{ textAlign: 'center', padding: 'var(--space-2)' }}
|
||
onClick={() => onNext(code)}
|
||
>
|
||
<span style={{ fontSize: '1.25rem', fontWeight: 700, color: 'var(--cv-navy-600)' }}>
|
||
{code}
|
||
</span>
|
||
<span className="stat-label" style={{ marginTop: '0.25rem' }}>
|
||
{STATE_NAMES[code]}
|
||
</span>
|
||
</button>
|
||
))}
|
||
</div>
|
||
)}
|
||
|
||
{filtered.length === 0 && (
|
||
<p style={{ color: 'var(--cv-ink-3)', marginTop: 'var(--space-2)' }}>
|
||
No states match "{query}". Try a full state name or two-letter code.
|
||
</p>
|
||
)}
|
||
</div>
|
||
|
||
{/* Context footer */}
|
||
<div style={{ marginTop: 'var(--space-5)', paddingBottom: 'var(--space-3)', borderBottom: '1px solid var(--cv-rule)' }}>
|
||
<span className="eyebrow">How it works</span>
|
||
<p style={{ fontSize: '0.9rem', color: 'var(--cv-ink-2)', marginTop: 'var(--space-1)' }}>
|
||
After selecting a state, you'll search for a school district and see arrest estimates from 10 Bayesian models —
|
||
including one-year vs. three-year specifications and baseline vs. referral-rate covariate models.
|
||
The app fetches data directly from the{' '}
|
||
<a href="https://crdc-api.civilytics.org/api/v1/" target="_blank" rel="noopener noreferrer">
|
||
CRDC Arrest Rate API
|
||
</a>. No account or key required.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|