import React, { useState } from 'react'; import HomePage from './components/HomePage'; import ImpactDashboard from './components/ImpactDashboard'; import TopicNavigation from './components/TopicNavigation'; import DecisionCard from './components/shared/DecisionCard'; import SplitScreenView from './components/SplitScreenView'; import NonprofitCard from './components/NonprofitCard'; import { metadata } from './data/dashboardData'; import { Home, Grid, Building2, Heart, Church, Search, X, Calendar, Filter, MapPin, Edit2, Lightbulb } from 'lucide-react'; export default function App() { const [viewMode, setViewMode] = useState('home'); // 'home', 'impact', 'browse', 'split-screen' const [exploreMode, setExploreMode] = useState('decisions'); // 'decisions', 'organizations', or 'causes' const [sectorView, setSectorView] = useState('all'); // 'all', 'public', 'nonprofits', 'churches' const [selectedPersona, setSelectedPersona] = useState(null); const [selectedTopic, setSelectedTopic] = useState(null); const [selectedDecision, setSelectedDecision] = useState(null); const [selectedTopics, setSelectedTopics] = useState([]); const [selectedPatterns, setSelectedPatterns] = useState([]); const [selectedResources, setSelectedResources] = useState([]); const [startDate, setStartDate] = useState(null); const [endDate, setEndDate] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [quickDateFilter, setQuickDateFilter] = useState('all'); // 'all', '7days', '30days', '90days' const [quickTopicFilter, setQuickTopicFilter] = useState('all'); // 'all', 'health', 'education', 'infrastructure' const [jurisdictionType, setJurisdictionType] = useState('city'); // 'nation', 'state', 'county', 'city', 'school-district' const [jurisdictionName, setJurisdictionName] = useState('Tuscaloosa'); const [jurisdictionState, setJurisdictionState] = useState('AL'); const [showLocationModal, setShowLocationModal] = useState(false); const [tempJurisdictionType, setTempJurisdictionType] = useState('city'); const [tempJurisdictionName, setTempJurisdictionName] = useState(''); const [tempJurisdictionState, setTempJurisdictionState] = useState(''); const handlePersonaSelect = (persona, topic) => { setSelectedPersona(persona); setSelectedTopic(topic); setViewMode('impact'); }; const handleTopicSelect = (topicId) => { setSelectedTopics([topicId]); setViewMode('browse'); }; const handleTopicToggle = (topicId) => { setSelectedTopics(prev => prev.includes(topicId) ? prev.filter(t => t !== topicId) : [...prev, topicId] ); }; const handlePatternToggle = (patternId) => { setSelectedPatterns(prev => prev.includes(patternId) ? prev.filter(p => p !== patternId) : [...prev, patternId] ); }; const handleResourceToggle = (resourceId) => { setSelectedResources(prev => prev.includes(resourceId) ? prev.filter(r => r !== resourceId) : [...prev, resourceId] ); }; const handleClearFilters = () => { setSelectedTopics([]); setSelectedPatterns([]); setSelectedResources([]); setStartDate(null); setEndDate(null); setSearchQuery(''); setQuickDateFilter('all'); setQuickTopicFilter('all'); }; const handleQuickDateFilter = (filter) => { setQuickDateFilter(filter); const today = new Date(); switch(filter) { case '7days': const sevenDaysAgo = new Date(today); sevenDaysAgo.setDate(today.getDate() - 7); setStartDate(sevenDaysAgo.toISOString().split('T')[0]); setEndDate(today.toISOString().split('T')[0]); break; case '30days': const thirtyDaysAgo = new Date(today); thirtyDaysAgo.setDate(today.getDate() - 30); setStartDate(thirtyDaysAgo.toISOString().split('T')[0]); setEndDate(today.toISOString().split('T')[0]); break; case '90days': const ninetyDaysAgo = new Date(today); ninetyDaysAgo.setDate(today.getDate() - 90); setStartDate(ninetyDaysAgo.toISOString().split('T')[0]); setEndDate(today.toISOString().split('T')[0]); break; case 'all': default: setStartDate(null); setEndDate(null); break; } }; const handleQuickTopicFilter = (filter) => { setQuickTopicFilter(filter); if (filter === 'all') { setSelectedTopics([]); } else { setSelectedTopics([filter]); } }; const handleBackToHome = () => { setViewMode('home'); setSelectedPersona(null); setSelectedTopic(null); setSelectedDecision(null); }; const handleDecisionClick = (decision) => { setSelectedDecision(decision); setViewMode('split-screen'); }; const handleSectorSelect = (sector) => { setViewMode('browse'); // Set explore mode and sector based on selection if (sector === 'public') { setExploreMode('decisions'); setSectorView('public'); } else if (sector === 'nonprofits' || sector === 'churches') { setExploreMode('organizations'); setSectorView(sector); } else if (sector === 'all') { setExploreMode('organizations'); setSectorView('all'); } }; // Example decision data - would come from Python export const exampleDecisions = [ { decision_summary: "Approval of $850,000 athletic turf replacement project", outcome: "Approved", primary_rationale: "Athletic facilities are essential for student engagement and community pride. The current turf is beyond its useful life and poses safety concerns.", supporters: [ { name: "Board Member Johnson", role: "Board Member" }, { name: "Athletic Director Smith", role: "Staff" } ], opponents: [ { name: "Parent Coalition for Health", role: "Public" } ], vote_result: "6-1", meeting_date: "2026-03-15", tradeoffs_discussed: ["Athletic facilities vs. health screening programs"], evidence_cited: [{ source: "Athletic Department Report" }], policy_domain: "facilities", ntee_code: "N20" // Recreation, Sports, and Athletics }, { decision_summary: "Tabled decision on dental screening partnership with West Alabama Dental Clinic", outcome: "Tabled for further study", primary_rationale: "Risk management concerns require additional legal review and liability analysis before proceeding with external health partnerships.", supporters: [ { name: "Patricia Johnson, Risk Manager", role: "Staff" } ], opponents: [ { name: "Dr. Sarah Martinez", role: "Public" }, { name: "Parent Teacher Association", role: "Public" }, { name: "Board Member Williams", role: "Board Member" } ], vote_result: "5-2 to table", meeting_date: "2026-01-18", tradeoffs_discussed: ["Preventive care vs. perceived liability risk"], evidence_cited: [{ source: "Risk Management Memo" }], policy_domain: "health", ntee_code: "E32", // School-Based Health Care community_gap: { description: "100% of surveyed parents want dental screenings for students", nonprofit_filling_gap: true } }, { decision_summary: "Reduction of nursing staff from 5 FTE to 3 FTE", outcome: "Approved", primary_rationale: "Budget constraints necessitate cost reductions. Nursing positions will be restructured to focus on emergency response rather than preventive services.", supporters: [ { name: "Superintendent Brown", role: "Staff" }, { name: "Board Chair Thompson", role: "Board Member" } ], opponents: [ { name: "School Nurses Association", role: "Public" }, { name: "Board Member Lee", role: "Board Member" } ], vote_result: "4-3", meeting_date: "2026-02-20", tradeoffs_discussed: ["Cost savings vs. preventive health services"], evidence_cited: [{ source: "FY2026 Budget Proposal" }], policy_domain: "budget", ntee_code: "E40", // Health - General and Rehabilitative community_gap: { description: "Students lost access to preventive health services", nonprofit_filling_gap: true } } ]; // Example nonprofit data - would come from IRS/GuideStar API const exampleNonprofits = [ { name: "West Alabama Dental Initiative", ein: "63-1234567", ntee_code: "E32", ntee_description: "School-Based Health Care", mission: "Providing free dental screenings and preventive care to underserved students in West Alabama", services: [ "Mobile dental unit visits to schools", "Free toothbrush and fluoride kits", "Dental education workshops for parents" ], annual_budget: 125000, students_served: 2400, contact: { website: "https://wadaldentalinitiative.org", email: "info@wadaldentalinitiative.org", phone: "(205) 555-0123" }, volunteer_opportunities: true, accepting_board_members: true }, { name: "Tuscaloosa Family Health Network", ein: "63-7654321", ntee_code: "E40", ntee_description: "Health - General and Rehabilitative", mission: "Connecting low-income families with preventive health services and wellness programs", services: [ "Health screenings at community centers", "Nutrition education programs", "Mental health counseling referrals" ], annual_budget: 280000, families_served: 850, contact: { website: "https://tuscfamilyhealth.org", email: "contact@tuscfamilyhealth.org", phone: "(205) 555-0456" }, volunteer_opportunities: true, accepting_board_members: false }, { name: "After School Champions", ein: "63-9876543", ntee_code: "O50", ntee_description: "Youth Development Programs", mission: "Providing safe, enriching after-school programs that support academic success and healthy development", services: [ "Homework help and tutoring", "Healthy snacks and meals", "Physical activity and sports", "Health and wellness workshops" ], annual_budget: 340000, youth_served: 450, contact: { website: "https://afterschoolchamps.org", email: "info@afterschoolchamps.org", phone: "(205) 555-0789" }, volunteer_opportunities: true, accepting_board_members: true }, { name: "First Baptist Church Tuscaloosa - Health Ministry", ein: "63-2345678", ntee_code: "X20", ntee_description: "Christian", mission: "Faith-based health outreach serving Tuscaloosa families through free dental kits, health screenings, and nutrition education", services: [ "Free dental hygiene kits distribution", "Health screenings after Sunday service", "Nutrition education classes", "Mobile health unit partnership" ], annual_budget: 45000, families_served: 450, contact: { website: "https://fbctuscaloosa.org/health", email: "health@fbctuscaloosa.org", phone: "(205) 555-0200" }, volunteer_opportunities: true, accepting_board_members: false }, { name: "Tuscaloosa County Interfaith Dental Initiative", ein: "63-3456789", ntee_code: "X20", ntee_description: "Christian", mission: "Multi-faith collaboration providing free dental care to low-income students across Tuscaloosa County schools", services: [ "Mobile dental unit serving Title I schools", "Free toothbrush and fluoride programs", "Parent education workshops", "Dental emergency fund for families" ], annual_budget: 180000, students_served: 1600, contact: { website: "https://tuscaloosainterfaithdental.org", email: "contact@tuscaloosainterfaithdental.org", phone: "(205) 555-0300" }, volunteer_opportunities: true, accepting_board_members: true }, { name: "Catholic Social Services - Dental Outreach", ein: "63-4567890", ntee_code: "X20", ntee_description: "Christian", mission: "Diocese of Birmingham outreach providing dental care and health services to underserved communities", services: [ "Quarterly dental clinics at parish hall", "School dental screening partnerships", "Dental supply distribution", "Financial assistance for dental emergencies" ], annual_budget: 95000, families_served: 320, contact: { website: "https://cssalabama.org/dental", email: "dental@cssalabama.org", phone: "(205) 555-0400" }, volunteer_opportunities: true, accepting_board_members: false } ]; // Filter decisions based on search, topics, patterns, resources, and date range const filteredDecisions = exampleDecisions.filter(decision => { const matchesSearch = searchQuery === '' || decision.decision_summary.toLowerCase().includes(searchQuery.toLowerCase()) || decision.primary_rationale.toLowerCase().includes(searchQuery.toLowerCase()); // Map policy_domain to topic IDs const topicMap = { 'health': 'public-health', 'facilities': 'infrastructure', 'budget': 'education' // Example mapping }; const decisionTopic = topicMap[decision.policy_domain] || decision.policy_domain; const matchesTopic = selectedTopics.length === 0 || selectedTopics.includes(decisionTopic); // Date filtering const decisionDate = new Date(decision.meeting_date); const matchesStartDate = !startDate || decisionDate >= new Date(startDate); const matchesEndDate = !endDate || decisionDate <= new Date(endDate); // TODO: Add pattern matching based on decision.patterns field // TODO: Add resource matching based on decision.available_resources field return matchesSearch && matchesTopic && matchesStartDate && matchesEndDate; }); // Filter nonprofits and churches based on search and topic const filteredNonprofits = exampleNonprofits.filter(org => { const matchesSearch = searchQuery === '' || org.name.toLowerCase().includes(searchQuery.toLowerCase()) || org.mission.toLowerCase().includes(searchQuery.toLowerCase()) || org.services.some(service => service.toLowerCase().includes(searchQuery.toLowerCase())) || org.ntee_description.toLowerCase().includes(searchQuery.toLowerCase()); // Map NTEE codes to topic IDs const nteeTopicMap = { 'E': 'public-health', // Health 'F': 'public-health', // Mental Health 'K': 'public-health', // Food/Nutrition 'O': 'education', // Youth Development 'P': 'education', // Human Services 'X': 'public-health' // Religious (often health ministries) }; const orgTopic = nteeTopicMap[org.ntee_code?.[0]] || 'public-health'; const matchesTopic = selectedTopics.length === 0 || selectedTopics.includes(orgTopic); return matchesSearch && matchesTopic; }); return (
{metadata.description}
No government decisions match your filters
No nonprofits match your search
No churches match your search
Discover the underlying factors driving policy decisions in your community. Understand the connections between social determinants, community needs, and government actions.
Coming soon: Interactive cause analysis and trend mapping
Choose the level and location to see relevant decisions and organizations.