/* Parent → "Where's my child now?" — a live timeline pulling every tracking signal. */ function TimelineScreen({ onNav, onBack }) { const child = jlChild(); const [bus, setBus] = React.useState(null); const [roster, setRoster] = React.useState(null); const [pickup, setPickup] = React.useState(null); const [att, setAtt] = React.useState(null); React.useEffect(() => { const read = () => { try { setBus(JSON.parse(localStorage.getItem('jl_buspos') || 'null')); setRoster((JSON.parse(localStorage.getItem('jl_roster') || '{}'))[child.id] || null); setPickup(JSON.parse(localStorage.getItem('jl_pickup') || 'null')); setAtt((JSON.parse(localStorage.getItem('jl_attendance') || '{}'))[child.id] || null); } catch(e){} }; read(); const iv = setInterval(read, 1500); window.addEventListener('storage', read); return () => { clearInterval(iv); window.removeEventListener('storage', read); }; }, [child.id]); // derive current status + step states const boarded = roster && roster.status === 'boarded'; const atSchool = att && (att.status === 'present' || att.status === 'tardy') || boarded; const pickedUp = pickup && pickup.done; const cur = pickedUp ? 'Picked up' : atSchool ? 'At school' : boarded ? 'On the bus' : 'Getting ready'; const steps = [ { key:'home', icon:'home', title:'Left for school', sub: roster ? (boarded ? child.first + ' boarded ' + child.bus + (roster.stop?' at '+roster.stop:'') : 'Waiting at the stop') : 'Morning routine', done: !!boarded || atSchool || pickedUp, live:!boarded && !atSchool && !pickedUp }, { key:'bus', icon:'bus-front', title:'On the bus', sub: bus ? ('Next: ' + bus.nextStop + ' · ETA ' + bus.eta + ' min') : (boarded ? 'On board '+child.bus : 'Not on route yet'), done: atSchool || pickedUp, live: boarded && !atSchool && !pickedUp }, { key:'school', icon:'school', title:'Arrived at school', sub: att ? (att.status==='tardy' ? 'Marked tardy · ' + (att.at||'') : 'Marked present' + (att.at?' · '+att.at:'')) : 'Homeroom check-in', done: pickedUp, live: atSchool && !pickedUp }, { key:'day', icon:'book-open', title:'In class', sub:'Following the daily schedule', done: pickedUp, live: atSchool && !pickedUp }, { key:'out', icon:'car-front', title:'Dismissal', sub: pickedUp ? (child.first + ' was picked up' + (pickup.at?' at '+pickup.at:'')) : 'Not dismissed yet', done: pickedUp, live: pickedUp }, ]; return (
{/* current status hero */}
RIGHT NOW
{cur}
Live
{/* timeline */} Today's Journey
{steps.map((s,i) => { const color = s.done ? 'var(--success-500)' : s.live ? 'var(--blue-500)' : 'var(--gray-300)'; return (
{/* rail */}
{i}
{/* content */}
{s.title}
{s.sub}
{s.live && Now}
); })}
{/* jump links */} Details
onNav('transport')} /> onNav('attendance')} /> onNav('pickup')} />
); } Object.assign(window, { TimelineScreen });