// ===== APP: header, nav, drawer, routing, mood, dark mode, AI news ===== const SCREENS = { Home: { title: 'NRSA', comp: HomeScreen }, Traffic: { title: 'Live Traffic', subtitle: 'Metro Manila · Real-time', comp: TrafficScreen }, Courses: { title: 'Education', subtitle: 'Drive smarter, safer', comp: CoursesScreen }, Laws: { title: 'Traffic Laws', subtitle: 'Know the rules', comp: LawsScreen }, Emergency: { title: 'Emergency SOS', subtitle: 'Help is one tap away', comp: EmergencyScreen }, Weather: { title: 'Weather & Roads', subtitle: 'Drive to the conditions', comp: WeatherScreen }, Forum: { title: 'Community', subtitle: 'Drivers helping drivers', comp: ForumScreen }, Coach: { title: 'AI Driving Coach', subtitle: 'Powered by Claude', comp: CoachScreen }, Score: { title: 'Safety Score', subtitle: 'Your driving report card', comp: ScoreScreen }, Commute: { title: 'Commute Tracker', subtitle: 'Plan a safer route', comp: CommuteScreen }, Buddy: { title: 'SOS Buddy', subtitle: 'Share trips with loved ones', comp: BuddyScreen }, Checklist: { title: 'Pre-Trip Checklist', subtitle: 'Inspect before you drive', comp: ChecklistScreen }, Logger: { title: 'Evidence Logger', subtitle: 'Document incidents', comp: LoggerScreen }, PoliceTips: { title: 'Know Your Rights', subtitle: 'Philippines · Enforcers', comp: PoliceTipsScreen }, Offices: { title: 'Traffic Offices', subtitle: 'PH directory', comp: OfficesScreen }, PHOrdinances: { title: 'PH Ordinances', subtitle: 'City-by-city rules', comp: PHOrdinancesScreen }, Alerts: { title: 'Notifications', subtitle: 'Your latest alerts', comp: AlertsScreen }, Profile: { title: 'My Profile', subtitle: 'Account & settings', comp: ProfileScreen }, PWD: { title: 'PWD Assistance', subtitle: 'Accessibility & priority support', comp: PWDScreen }, Bicycle: { title: 'Cyclist Hub', subtitle: 'Ride safe · lanes · rights', comp: BicycleScreen }, Ebike: { title: 'E-Bike Center', subtitle: 'Classes · rules · charging', comp: EbikeScreen }, RoadHazard: { title: 'Road Hazard Report', subtitle: 'Ibalik ang sidewalk sa mga tao', comp: RoadHazardScreen }, CrashReport: { title: 'Crash Report', subtitle: 'Real-time intake · 24 fields', comp: CrashReportScreen }, ResponderRegister: { title: 'Crash Responder', subtitle: 'Application & verification', comp: ResponderRegisterScreen }, AdminConsole: { title: 'Admin Console', subtitle: 'NRSA system administration', comp: AdminConsoleScreen }, Programs: { title: 'Programs & Campaigns', subtitle: 'NRSA · road safety initiatives', comp: ProgramsScreen }, Donate: { title: 'Donate', subtitle: 'Support road safety', comp: DonateScreen } }; const TABS = [ { id: 'Home', label: 'Home', icon: 'home' }, { id: 'Traffic', label: 'Traffic', icon: 'traffic' }, { id: 'Courses', label: 'Learn', icon: 'learn' }, { id: '__more', label: 'More', icon: 'grid' }, { id: 'Emergency', label: 'SOS', icon: 'sos' }]; const DRAWER_ITEMS = [ { id: 'Laws', icon: '⚖️', color: '#7b2d8b' }, { id: 'Weather', icon: '🌦️', color: '#00c48c' }, { id: 'Forum', icon: '💬', color: '#ffa502' }, { id: 'Coach', icon: '🤖', color: '#2556a8' }, { id: 'Score', icon: '🏆', color: '#f5a623' }, { id: 'Commute', icon: '🛣️', color: '#ff6b2b' }, { id: 'Buddy', icon: '👥', color: '#00c48c' }, { id: 'Checklist', icon: '✅', color: '#1a3a6e' }, { id: 'Logger', icon: '📍', color: '#ff4757' }, { id: 'PoliceTips', icon: '🪪', color: '#2556a8' }, { id: 'Offices', icon: '🏛️', color: '#7b2d8b' }, { id: 'PHOrdinances', icon: '🏙️', color: '#ff6b2b' }, { id: 'Alerts', icon: '🔔', color: '#ffa502' }, { id: 'Programs', icon: '📢', color: '#2556a8' }, { id: 'Donate', icon: '❤️', color: '#ff6b2b' }, { id: 'CrashReport', icon: '🚨', color: '#ff4757' }, { id: 'PWD', icon: '♿', color: '#2556a8' }, { id: 'Bicycle', icon: '🚲', color: '#00c48c' }, { id: 'Ebike', icon: '🛵', color: '#7b2d8b' }, { id: 'RoadHazard', icon: '🚧', color: '#ff6b2b' }, { id: 'Profile', icon: '🙋', color: '#00c48c' }]; const DRAWER_LABELS = { Laws: 'Traffic Laws', Weather: 'Weather', Forum: 'Community', Coach: 'AI Coach', Score: 'Safety Score', Commute: 'Commute', Buddy: 'SOS Buddy', Checklist: 'Pre-Trip', Logger: 'Evidence Log', PoliceTips: 'Your Rights', Offices: 'Offices', PHOrdinances: 'PH Ordinances', Alerts: 'Alerts', Programs: 'Programs', Donate: 'Donate', CrashReport: 'Crash Report', PWD: 'PWD Assistance', Bicycle: 'Bicycles', Ebike: 'E-Bikes', RoadHazard: 'Road Hazard', Profile: 'Profile', AdminConsole: 'Admin Console' }; function App() { const [user, setUser] = useState(() => { try { return JSON.parse(localStorage.getItem('nrsa_auth')) || null; } catch (e) { return null; } }); const [consent, setConsent] = useState(() => { const c = getConsent(); return c && c.version === CONSENT_VERSION ? c : null; }); const [dark, setDark] = useState(() => localStorage.getItem('nrsa_dark') === '1'); const [moodId, setMoodId] = useState(() => localStorage.getItem('nrsa_mood') || 'focused'); const [screen, setScreen] = useState('Home'); const [drawer, setDrawer] = useState(false); const [moodSheet, setMoodSheet] = useState(false); const [news, setNews] = useState(news_static); const [newsLoading, setNewsLoading] = useState(false); const [newsKey, setNewsKey] = useState(0); const t = getTheme(dark); const mood = MOODS.find((m) => m.id === moodId) || MOODS[0]; useEffect(() => {localStorage.setItem('nrsa_dark', dark ? '1' : '0');}, [dark]); useEffect(() => {localStorage.setItem('nrsa_mood', moodId);}, [moodId]); const handleAuth = (u) => { const full = { role: 'driver', ...u }; localStorage.setItem('nrsa_auth', JSON.stringify(full)); setUser(full); setScreen(full.role === 'admin' ? 'AdminConsole' : 'Home'); // Live mode: sync the consent captured at the gate (it needs a session). if (NRSAApi.isLive() && consent && !consent.synced) { NRSAApi.recordConsent({ privacy: !!consent.privacy, terms: !!consent.terms, marketing: !!consent.marketing, version: consent.version }) .then(() => { const c = { ...consent, synced: true }; localStorage.setItem(CONSENT_KEY, JSON.stringify(c)); setConsent(c); }) .catch(() => { /* will retry next login */ }); } }; const updateUser = (patch) => setUser(prev => { const next = { ...prev, ...patch }; localStorage.setItem('nrsa_auth', JSON.stringify(next)); if (NRSAApi.isLive()) NRSAApi.updateProfile(patch).catch(() => {}); return next; }); const logout = () => { if (NRSAApi.isLive()) NRSAApi.logout().catch(() => {}); localStorage.removeItem('nrsa_auth'); setUser(null); setDrawer(false); }; const acceptConsent = (c) => { localStorage.setItem(CONSENT_KEY, JSON.stringify(c)); setConsent(c); }; const withdrawConsent = () => { localStorage.removeItem(CONSENT_KEY); localStorage.removeItem('nrsa_auth'); setConsent(null); setUser(null); setDrawer(false); }; // Gate 1: no data-privacy consent yet → consent notice (RA 10173) if (!consent) { return (
{meta.subtitle}
}Sets your mood glow and tailors safety nudges.