/* Home dashboard */ function SectionLabel({ children, action }) { return (
{children} {action}
); } function HomeScreen({ onNav, onBack, child, childList, onSwitchChild }) { const [busOpen, setBusOpen] = React.useState(true); const [emOpen, setEmOpen] = React.useState(true); const [emExp, setEmExp] = React.useState(false); const [childSheet, setChildSheet] = React.useState(false); const [roster, setRoster] = React.useState({}); React.useEffect(() => { const read = () => { try { setRoster(JSON.parse(localStorage.getItem('jl_roster') || '{}')); } catch(e){} }; read(); const onStore = (e) => { if (e.key === 'jl_roster') read(); }; window.addEventListener('storage', onStore); const iv = setInterval(read, 1500); return () => { window.removeEventListener('storage', onStore); clearInterval(iv); }; }, []); const boarding = roster[child.id]; const [att, setAtt] = React.useState(null); React.useEffect(() => { const read = () => { try { const all = JSON.parse(localStorage.getItem('jl_attendance') || '{}'); setAtt(all[child.id] || null); } catch(e){} }; read(); const onStore = (e) => { if (e.key === 'jl_attendance') read(); }; window.addEventListener('storage', onStore); const iv = setInterval(read, 1500); return () => { window.removeEventListener('storage', onStore); clearInterval(iv); }; }, [child.id]); const [hw, setHw] = React.useState(null); React.useEffect(() => { const read = () => { try { const all = JSON.parse(localStorage.getItem('jl_homework') || '{}'); setHw(all[child.id] || null); } catch(e){} }; read(); const onStore = (e) => { if (e.key === 'jl_homework') read(); }; window.addEventListener('storage', onStore); const iv = setInterval(read, 1500); return () => { window.removeEventListener('storage', onStore); clearInterval(iv); }; }, [child.id]); const [bus, setBus] = React.useState(null); React.useEffect(() => { const read = () => { try { setBus(JSON.parse(localStorage.getItem('jl_buspos') || 'null')); } catch(e){} }; read(); const onStore = (e) => { if (e.key === 'jl_buspos') read(); }; window.addEventListener('storage', onStore); const iv = setInterval(read, 1500); return () => { window.removeEventListener('storage', onStore); clearInterval(iv); }; }, []); const [busAlert, setBusAlert] = React.useState(null); React.useEffect(() => { const read = () => { try { const a = JSON.parse(localStorage.getItem('jl_alerts') || '[]'); setBusAlert(a.find(x => (x.kind==='delay'||x.kind==='incident') && x.status!=='resolved' && (!child.bus || x.bus===child.bus)) || null); } catch(e){} }; read(); const onStore = (e) => { if (e.key === 'jl_alerts') read(); }; window.addEventListener('storage', onStore); const iv = setInterval(read, 1500); return () => { window.removeEventListener('storage', onStore); clearInterval(iv); }; }, [child.bus]); return (
onNav('notifications')} onBack={onBack} /> {childSheet && (
setChildSheet(false)} style={{ position:'absolute', inset:0, zIndex:70, background:'rgba(10,20,40,.4)', display:'flex', alignItems:'flex-end' }}>
e.stopPropagation()} style={{ width:'100%', background:'#fff', borderRadius:'22px 22px 0 0', padding:'10px 18px 30px' }}>
Your Children
Switch to see each child’s info
{childList.map(c => { const on = c.id === child.id; return ( ); })}
)}
{busAlert && (
Bus {busAlert.bus} {busAlert.kind==='incident'?'incident reported':'is running late'}
{busAlert.kind==='incident'?'The school is responding — we’ll update you shortly.':(child.first + '’s ride may arrive later than usual.')}
)} {/* emergency alert */} {emOpen && (
EMERGENCY ALERT · KATY MIDDLE
Early dismissal today at 1:00 PM
{emExp && (
Due to a forecasted storm, all students will be dismissed at 1:00 PM. Buses will run on the early schedule. Please confirm your pickup plan.
)}
)} {/* child selector */} {/* bus status hero */} {att && att.status && att.status!=='present' && (
{child.first} marked {att.status} in {att.period}
{att.cls} · {att.at} · by teacher
)} {/* bus status hero */} {busOpen && (
BUS STATUS
{child.bus==='Walker' ? 'Walker' : (bus ? 'On the way' : 'Not on route yet')}
{child.bus==='Walker' ? 'Walks home' : 'Bus '+child.bus}
ETA
{child.bus==='Walker' ? '—' : (bus ? bus.eta : 5)} min
{bus ? 'Next: ' + bus.nextStop + ' · live' : 'Last updated 3:19 PM'}
{boarding && (
{boarding.status==='boarded' ? child.first + ' boarded at ' + boarding.stop + ' · ' + boarding.time : child.first + ' marked absent by the driver'}
)}
)} {/* quick actions */} {jlT('quick_actions')}
{[ { id:'pickup', label:'Pickup', icon:'car-front', tint:'var(--gold-100)', ic:'var(--gold-600)' }, { id:'grades', label:'Grades', icon:'graduation-cap', tint:'var(--blue-100)', ic:'var(--blue-500)' }, { id:'wallet', label:'Lunch', icon:'utensils', tint:'var(--success-100)', ic:'var(--success-500)' }, { id:'tutor', label:'AI Tutor', icon:'bot', tint:'var(--info-100)', ic:'var(--info-500)' }, ].map(q => ( ))}
{/* where's my child */} {/* explore */} {jlT('explore')}
onNav('safety')} /> onNav('attendance')} /> onNav('marketplace')} /> onNav('calendar')} /> onNav('forms')} /> onNav('health')} /> onNav('docs')} /> onNav('waitlist')} /> onNav('wristband')} /> onNav('watch')} /> onNav('engagement')} />
{/* today's schedule */} {hw && (() => { const next = (hw.items||[]).find(h=>!h.done); return ( Homework
=hw.total?'var(--success-100)':'var(--blue-100)', display:'flex', alignItems:'center', justifyContent:'center', flex:'0 0 auto' }}>=hw.total?'circle-check-big':'clipboard-list'} size={19} color={hw.done>=hw.total?'var(--success-500)':'var(--blue-500)'} />
{hw.done} of {hw.total} done{next?' · '+next.title:''}
{hw.done>=hw.total?child.first+' is all caught up':'Updated from '+child.first+'’s app'}
=hw.total?'var(--success-100)':'var(--blue-100)'} fg={hw.done>=hw.total?'var(--success-600)':'var(--blue-600)'}>{Math.round((hw.done/hw.total)*100)}%
); })()} {/* today's schedule */} {jlT('todays_schedule')}
{/* recent alerts */} {jlT('view_all')}}>{jlT('recent_alerts')}
High} onClick={()=>onNav('activities')} /> onNav('messages')} />
); } function ScheduleRow({ icon, tint, ic, title, sub, right, onClick }) { return ( ); } const cardWrap = { background:'#fff', border:'1px solid var(--gray-200)', borderRadius:14, boxShadow:'var(--shadow-sm)', overflow:'hidden' }; function Divider(){ return
; } Object.assign(window, { HomeScreen, SectionLabel, ScheduleRow, Divider, cardWrap });