-
Notifications
You must be signed in to change notification settings - Fork 7
[UI] Live location redesign #190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2dfb9cb
21eff7f
88607cb
9e90219
de8ef6a
00a7572
6cbfee9
deb175b
cfe8006
a7616fc
b5fff41
641e068
a82fa79
dbb3fe3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
danasiongsin marked this conversation as resolved.
Show resolved
Hide resolved
|
danasiongsin marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import '../styles/RouteToggle.css'; | ||
| import rawAggregatedSchedule from '../data/aggregated_schedule.json'; | ||
|
|
||
| export default function RouteToggle({selectedRoute, setSelectedRoute}) { | ||
| const today = new Date(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should use |
||
| const keys = Object.keys(rawAggregatedSchedule[today.getDay()]) | ||
|
|
||
| // const [active, setActive] = useState("north"); | ||
| return( | ||
| <div class="toggle-div"> | ||
| <button | ||
| className={selectedRoute ===keys[0] ? "north-on" : "north-off"} | ||
| onClick={() => setSelectedRoute(keys[0])} | ||
| > | ||
| North | ||
| </button> | ||
| <button | ||
| className={selectedRoute === keys[1] ? "west-on" : "west-off"} | ||
| onClick={() => setSelectedRoute(keys[1])} | ||
| > | ||
| West | ||
| </button> | ||
| </div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,8 +2,9 @@ import { useState, useEffect } from 'react'; | |
| import '../styles/Schedule.css'; | ||
| import rawRouteData from '../data/routes.json'; | ||
| import rawAggregatedSchedule from '../data/aggregated_schedule.json'; | ||
| import RouteToggle from './RouteToggle'; | ||
| import type { AggregatedDaySchedule, AggregatedScheduleType } from '../ts/types/schedule'; | ||
| import type { ShuttleRouteData, ShuttleStopData } from '../ts/types/route'; | ||
| import type { ShuttleRouteData } from '../ts/types/route'; | ||
|
|
||
| const aggregatedSchedule: AggregatedScheduleType = rawAggregatedSchedule as unknown as AggregatedScheduleType; | ||
|
|
||
|
|
@@ -14,17 +15,19 @@ type ScheduleProps = { | |
| setSelectedRoute: (route: string | null) => void; | ||
| }; | ||
|
|
||
| export default function Schedule({ selectedRoute, setSelectedRoute }: ScheduleProps) { | ||
| export default function Schedule() { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're gonna want to include the |
||
| // Validate props once at the top | ||
| if (typeof setSelectedRoute !== 'function') { | ||
| throw new Error('setSelectedRoute must be a function'); | ||
| } | ||
| // if (typeof setSelectedRoute !== 'function') { | ||
| // throw new Error('setSelectedRoute must be a function'); | ||
| // } | ||
|
|
||
| const now = new Date(); | ||
| const [selectedDay, setSelectedDay] = useState(now.getDay()); | ||
| const [selectedDay] = useState(now.getDay()); | ||
| const [routeNames, setRouteNames] = useState(Object.keys(aggregatedSchedule[selectedDay])); | ||
| const [stopNames, setStopNames] = useState<string[]>([]); | ||
| const [schedule, setSchedule] = useState<AggregatedDaySchedule>(aggregatedSchedule[selectedDay]); | ||
| const [selectedStop, setSelectedStop] = useState("all"); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we got rid of |
||
| const [selectedRoute, setSelectedRoute] = useState(routeNames[0]); | ||
|
|
||
| // Define safe values to avoid repeated null checks | ||
| const safeSelectedRoute = selectedRoute || routeNames[0]; | ||
|
|
@@ -40,17 +43,6 @@ export default function Schedule({ selectedRoute, setSelectedRoute }: SchedulePr | |
| } | ||
| }, [selectedDay, selectedRoute, setSelectedRoute]); | ||
|
|
||
| // Update stopNames when selectedRoute changes | ||
| useEffect(() => { | ||
| if (!safeSelectedRoute || !(safeSelectedRoute in routeData)) return; | ||
| setStopNames(routeData[safeSelectedRoute as keyof typeof routeData].STOPS); | ||
| }, [selectedRoute]); | ||
|
|
||
| // Handle day change from dropdown | ||
| const handleDayChange = (e: React.ChangeEvent<HTMLSelectElement>) => { | ||
| setSelectedDay(parseInt(e.target.value)); | ||
| } | ||
|
|
||
| const timeToDate = (timeStr: string): Date => { | ||
| const [time, modifier] = timeStr.trim().split(" "); | ||
|
|
||
|
|
@@ -69,6 +61,23 @@ export default function Schedule({ selectedRoute, setSelectedRoute }: SchedulePr | |
| return dateObj; | ||
| } | ||
|
|
||
| // Update stopNames when selectedRoute changes | ||
| useEffect(() => { | ||
| if (!safeSelectedRoute || !(safeSelectedRoute in routeData)) return; | ||
| setStopNames(routeData[safeSelectedRoute as keyof typeof routeData].STOPS); | ||
| }, [selectedRoute]); | ||
|
|
||
| useEffect(() => { | ||
| setSchedule(aggregatedSchedule[selectedDay]); | ||
| setRouteNames(Object.keys(aggregatedSchedule[selectedDay])); | ||
| }, [selectedDay]); | ||
| useEffect(() => { | ||
| if (!(selectedStop in rawRouteData[selectedRoute])) { | ||
| setSelectedStop("all"); | ||
| } | ||
| setStopNames(routeData[selectedRoute].STOPS); | ||
| }, [selectedRoute]); | ||
|
|
||
| // Function to offset schedule time by given minutes | ||
| const offsetTime = (time: string, offset: number) => { | ||
| const date = timeToDate(time); | ||
|
|
@@ -81,7 +90,7 @@ export default function Schedule({ selectedRoute, setSelectedRoute }: SchedulePr | |
| const scheduleDiv = document.querySelector('.schedule-scroll'); | ||
| if (!scheduleDiv) return; | ||
|
|
||
| if (selectedDay !== now.getDay()) return; // only scroll if viewing today's schedule | ||
| // if (selectedDay !== now.getDay()) return; // only scroll if viewing today's schedule | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Delete if unneeded. |
||
| const currentTimeRow = Array.from(scheduleDiv.querySelectorAll('td.outdented')).find(td => { | ||
| const timeStr = td.textContent?.trim(); | ||
|
|
||
|
|
@@ -94,33 +103,22 @@ export default function Schedule({ selectedRoute, setSelectedRoute }: SchedulePr | |
| if (currentTimeRow) { | ||
| currentTimeRow.scrollIntoView({ behavior: "auto" }); | ||
| } | ||
| }, [selectedRoute, selectedDay, schedule]); | ||
|
|
||
| }, [selectedRoute, selectedDay, selectedStop]); | ||
|
|
||
| const daysOfTheWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; | ||
|
|
||
| return ( | ||
| <div className="p-4"> | ||
| <h2>Schedule</h2> | ||
| <div> | ||
| <label htmlFor='weekday-dropdown'>Weekday:</label> | ||
| <select id='weekday-dropdown' className="schedule-dropdown-style" value={selectedDay} onChange={handleDayChange}> | ||
| { | ||
| daysOfTheWeek.map((day, index) => | ||
| <option key={index} value={index}> | ||
| {day} | ||
| </option> | ||
| ) | ||
| } | ||
| </select> | ||
| </div> | ||
| <h2>Today's schedule</h2> | ||
| <RouteToggle selectedRoute={selectedRoute} setSelectedRoute={setSelectedRoute} /> | ||
|
|
||
| <div> | ||
| <label htmlFor='loop-dropdown'>Loop:</label> | ||
| <select id='loop-dropdown' className="schedule-dropdown-style" value={safeSelectedRoute} onChange={(e) => setSelectedRoute(e.target.value)}> | ||
| <label htmlFor='stop-dropdown'>Filter stops: </label> | ||
| <select id='stop-dropdown' className="schedule-dropdown-style" value={selectedStop} onChange={(e) => setSelectedStop(e.target.value)}> | ||
| <option value="all">All Stops</option> | ||
| { | ||
| routeNames.map((route, index) => | ||
| <option key={index} value={route}> | ||
| {route} | ||
| stopNames.map((stop, index) => | ||
| <option key={index} value={stop}> | ||
| {rawRouteData[safeSelectedRoute][stop]?.NAME} | ||
| </option> | ||
| ) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we lost the staging domain banner styling here