Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<title>Shubble</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Karla:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Karla:ital,wght@0,200..800;1,200..800&family=KoHo:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;1,200;1,300;1,400;1,500;1,600;1,700&display=swap" rel="stylesheet">
</head>
<body>
<div id="root"></div>
Expand Down
75 changes: 35 additions & 40 deletions client/src/App.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
:root {
--text-color: #141301;
--header-color: #a1c3ff;
--header-color: #578FCA;
}

.App {
Expand All @@ -14,12 +14,21 @@
width: 100%;
}

.title,
.title:link,
.title:visited{
font-family: "KoHo", sans-serif;
font-weight: 700;
color: var(--text-color);
text-decoration: none;
}

nav.small ul {
margin: 0;
padding: 0;
box-sizing: border-box;
display: flex;
gap: 10px;
gap: 50px;
flex-direction: row;
width: 100%;
list-style: none;
Expand All @@ -29,13 +38,15 @@ nav.small ul {
nav.big ul {
margin: 0;
padding: 0;
padding-top:10px;
box-sizing: border-box;
display: flex;
gap: 30px;
flex-direction: row;
width: 100%;
list-style: none;
font-size: 0.8em;
font-size: 0.6em;
font-family: "Karla", sans-serif;
}

li {
Expand All @@ -54,15 +65,14 @@ header {
box-sizing: border-box;
max-height: 100px;
background-color: var(--header-color);
padding: 20px;
padding: 10px;
margin: 0;
font-size: 2em;
font-weight: bold;
z-index: 1000;
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 10px;
gap: 30px;
justify-content: center;
}

@media (max-width: 1024px) {
Expand All @@ -77,6 +87,7 @@ header {

footer {
border-radius: 20px 20px 0 0;
background-color: #e1e1e1;
}
}

Expand All @@ -92,6 +103,7 @@ header {

footer {
border-radius: 0;
/* background-color: #f0f0f0; */
}
}

Expand All @@ -118,14 +130,21 @@ footer {
padding: 20px;
box-sizing: border-box;
width: 100%;
background-color: #ddd;
/* background-color: ; */
justify-content: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

.big-footer {
display: flex;
flex-direction: row;
justify-content: space-between;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: "Karla", sans-serif;
background-color: #ffffff;
}

.git-copy {
Expand All @@ -137,41 +156,17 @@ footer {
padding: 0 20px;
}

.banner {
Copy link
Collaborator

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

display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
background-color: #184b7f;
color: #ffffff;
padding: 1px;
box-sizing: border-box;
text-align: center;
font-weight: bold;
font-size: 18px;
margin: 0;
}


.banner a {
color: #ffffff;
text-decoration: underline;
}

.banner p {
margin: 4px 0;
.line {
height: 1px;
background-color: #d9d9d9;
width: 1200px;
}

.banner * {
margin: 5px;
}

/*
/*shubble text link styling*/
.site-title,
.site-title:link,
.site-title:visited {
color: var(--text-color);
text-decoration: none; /* remove underline */
}

*/
3 changes: 2 additions & 1 deletion client/src/components/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default function Navigation({ GIT_REV }: { GIT_REV: string }) {
return (
<>
<header>
<Link to='/' className='site-title'>SHUBBLE</Link>
<Link to='/' className='title'>SHUBBLE</Link>
<nav className='big'>
<ul>
<li>
Expand Down Expand Up @@ -58,6 +58,7 @@ export default function Navigation({ GIT_REV }: { GIT_REV: string }) {
</ul>
</nav>
<div className='big'>
<div class='line'></div>
<div className='big-footer'>
<div className='git-copy'>
<a href='https://github.com/wtg/shubble' target='_blank'>
Expand Down
25 changes: 25 additions & 0 deletions client/src/components/RouteToggle.jsx
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();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use selectedDay to enable day selection

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>
);
}
76 changes: 37 additions & 39 deletions client/src/components/Schedule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -14,17 +15,19 @@ type ScheduleProps = {
setSelectedRoute: (route: string | null) => void;
};

export default function Schedule({ selectedRoute, setSelectedRoute }: ScheduleProps) {
export default function Schedule() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're gonna want to include the selectedRoute and setSelectedRoute here. They are needed for the feature that flips the schedule to a specific route when a user clicks on a stop on the map.

// 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");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we got rid of selectedStop? This might be from a merge.

const [selectedRoute, setSelectedRoute] = useState(routeNames[0]);

// Define safe values to avoid repeated null checks
const safeSelectedRoute = selectedRoute || routeNames[0];
Expand All @@ -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(" ");

Expand All @@ -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);
Expand All @@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The 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();

Expand All @@ -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>
)
}
Expand Down
4 changes: 2 additions & 2 deletions client/src/styles/LiveLocation.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
gap: 40px;
width: 90%;
justify-content: center;
padding-top: 20px;
padding-bottom: 20px;
padding: 20px;
box-sizing:border-box;
}

.schedule-table {
Expand Down
4 changes: 2 additions & 2 deletions client/src/styles/MapKitMap.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.map {
width: 800px;
height: 500px;
width: 760px;
height: 450px;
touch-action: manipulation;
-webkit-overflow-scrolling: touch;
background-color: #f0f0f0;
Expand Down
Loading