-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
All the changes I made including departures and trip-planner from other branches. Updated HomePage.tsx and TransitBar.tsx
- Loading branch information
1 parent
6a64bc3
commit 8793793
Showing
14 changed files
with
834 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
import React, { useState } from 'react'; | ||
import { | ||
ComboBox, | ||
Item, | ||
Button, | ||
Flex, | ||
View, | ||
Heading, | ||
Text, | ||
Divider, | ||
useAsyncList, | ||
} from '@adobe/react-spectrum'; | ||
import moment from 'moment'; | ||
|
||
interface Stop { | ||
id: string; | ||
name: string; | ||
latitude: number; | ||
longitude: number; | ||
} | ||
|
||
interface Departure { | ||
routeShortName: string; | ||
headsign: string; | ||
departure: string; | ||
} | ||
|
||
const useStopSuggestions = () => { | ||
return useAsyncList<Stop>({ | ||
async load({ filterText, signal }) { | ||
if (!filterText) return { items: [] }; | ||
const res: Response = await fetch(`http://motis.metroll.live/api/v1/geocode?text=${filterText}`, { signal }); | ||
const data = await res.json(); | ||
return { items: data.slice(0, 5) }; | ||
}, | ||
}); | ||
}; | ||
|
||
// Function to fetch stations near the user's location | ||
const fetchNearbyStations = async (latitude: number, longitude: number) => { | ||
try { | ||
// Example API call - update with actual endpoint if necessary | ||
const res = await fetch(`http://motis.metroll.live/api/v1/stations?lat=${latitude}&lng=${longitude}`); | ||
const data = await res.json(); | ||
|
||
console.log('Nearby stations:', data); | ||
return data; // Return station data | ||
} catch (error) { | ||
console.error('Error fetching nearby stations:', error); | ||
return []; | ||
} | ||
}; | ||
|
||
// Function to fetch departures for a given stop | ||
const fetchDepartures = async (stopId: string) => { | ||
const res = await fetch( | ||
`http://motis.metroll.live/api/v1/stoptimes?stopId=${stopId}&time=${new Date().toISOString()}&arriveBy=false&n=10` | ||
); | ||
const data = await res.json(); | ||
return data.stopTimes || []; | ||
}; | ||
|
||
const Departures: React.FC = () => { | ||
const [selectedStop, setSelectedStop] = useState<Stop | null>(null); | ||
const [departures, setDepartures] = useState<Departure[]>([]); | ||
const [error, setError] = useState<string | null>(null); | ||
const [locationError, setLocationError] = useState<string | null>(null); | ||
const stopSuggestions = useStopSuggestions(); | ||
|
||
const handleGetLocation = async () => { | ||
if (navigator.geolocation) { | ||
navigator.geolocation.getCurrentPosition( | ||
async (position) => { | ||
const { latitude, longitude } = position.coords; | ||
try { | ||
// Fetch nearest stations based on the user's location | ||
const nearbyStations = await fetchNearbyStations(latitude, longitude); | ||
console.log('Nearby Stations:', nearbyStations); | ||
setLocationError(null); // Reset location error | ||
// You can select the nearest station or update your UI here | ||
setSelectedStop(nearbyStations[0] || null); // Example: Select the first station | ||
} catch { | ||
setLocationError('Failed to fetch nearby stations.'); | ||
} | ||
}, | ||
(err) => { | ||
setLocationError('Geolocation error: ' + err.message); | ||
} | ||
); | ||
} else { | ||
setLocationError('Geolocation is not supported by this browser.'); | ||
} | ||
}; | ||
|
||
const handleGetDepartures = async () => { | ||
if (!selectedStop) { | ||
setError('Please select a stop.'); | ||
return; | ||
} | ||
|
||
try { | ||
setError(null); | ||
const departures = await fetchDepartures(selectedStop.id); | ||
console.log('Fetched Departures:', departures); | ||
setDepartures(departures); | ||
} catch { | ||
setError('Failed to load departures.'); | ||
} | ||
}; | ||
|
||
const formatTime = (time: string) => moment.utc(time).local().format('DD/MM/YYYY HH:mm:ss'); | ||
|
||
return ( | ||
<Flex direction="column" alignItems="center" gap="size-200"> | ||
<View backgroundColor="gray-100" padding="size-300" borderRadius="medium" width="size-6000"> | ||
<Heading level={3}>Stop Departures</Heading> | ||
<Divider marginBottom="size-200" /> | ||
|
||
<Button variant="cta" onPress={handleGetLocation} marginTop="size-200"> | ||
Get Nearest Stops | ||
</Button> | ||
|
||
{locationError && <Text UNSAFE_style={{ color: 'red' }}><strong>Error:</strong> {locationError}</Text>} | ||
|
||
<ComboBox | ||
label="Stop" | ||
items={stopSuggestions.items} | ||
inputValue={stopSuggestions.filterText} | ||
onInputChange={stopSuggestions.setFilterText} | ||
onSelectionChange={(key) => setSelectedStop(stopSuggestions.items.find(item => item.id === key) || null)} | ||
loadingState={stopSuggestions.loadingState} | ||
placeholder="Select a stop" | ||
width="100%" | ||
> | ||
{(item) => <Item key={item.id}>{item.name}</Item>} | ||
</ComboBox> | ||
|
||
<Button variant="cta" onPress={handleGetDepartures} marginTop="size-200"> | ||
Get Departures | ||
</Button> | ||
</View> | ||
|
||
<View marginTop="size-300" backgroundColor="gray-100" padding="size-300" borderRadius="medium" width="size-6000"> | ||
{error && <Text UNSAFE_style={{ color: 'red' }}><strong>Error:</strong> {error}</Text>} | ||
{!error && departures.length === 0 && <Text>Enter a stop to receive information.</Text>} | ||
{departures.map((departure, idx) => { | ||
console.log(`Departure ${idx + 1}:`, departure); | ||
return ( | ||
<View key={idx} marginBottom="size-200" padding="size-200" backgroundColor="gray-200" borderRadius="medium"> | ||
<Text> | ||
<strong>Route:</strong> {departure.routeShortName} <br /> | ||
<strong>Headsign:</strong> {departure.headsign} <br /> | ||
<strong>Departure:</strong> {formatTime(departure.departure)} | ||
</Text> | ||
<Divider size="S" marginTop="size-150" /> | ||
</View> | ||
); | ||
})} | ||
</View> | ||
</Flex> | ||
); | ||
}; | ||
|
||
export default Departures; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React from 'react'; | ||
|
||
const Routes: React.FC = () => { | ||
return ( | ||
<div> | ||
<h1>Routes</h1> | ||
<p>This is the routes page content.</p> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Routes; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,23 @@ | ||
import React from 'react'; | ||
import {Flex, Heading, MenuTrigger, ActionButton, Menu, Item} from '@adobe/react-spectrum'; | ||
|
||
// Nishil | ||
// Implements the top navigation bar | ||
const TopNavBar: React.FC = () => { | ||
return ( | ||
|
||
<Flex margin="auto" justifyContent="space-between" alignItems="center" width="95%" height="100%"> | ||
<Heading level={1}>Metroll</Heading> | ||
<MenuTrigger> | ||
<ActionButton>☰</ActionButton> | ||
<Menu /*onAction={(key) => alert(key)}*/> | ||
<Item href="/login" key="login" >Login/Sign In</Item> | ||
<Item href="/" key="">Home</Item> | ||
<Item href="/about" key="about">About</Item> | ||
</Menu> | ||
</MenuTrigger> | ||
</Flex> | ||
); | ||
} | ||
|
||
export default TopNavBar; | ||
import React from 'react'; | ||
import {Flex, Heading, MenuTrigger, ActionButton, Menu, Item} from '@adobe/react-spectrum'; | ||
|
||
// Nishil | ||
// Implements the top navigation bar | ||
const TopNavBar: React.FC = () => { | ||
return ( | ||
|
||
<Flex margin="auto" justifyContent="space-between" alignItems="center" width="95%" height="100%"> | ||
<Heading level={1}>Metroll</Heading> | ||
<MenuTrigger> | ||
<ActionButton>☰</ActionButton> | ||
<Menu /*onAction={(key) => alert(key)}*/> | ||
<Item href="/login" key="login" >Login/Sign In</Item> | ||
<Item href="/" key="">Home</Item> | ||
<Item href="/about" key="about">About</Item> | ||
</Menu> | ||
</MenuTrigger> | ||
</Flex> | ||
); | ||
} | ||
|
||
export default TopNavBar; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,30 @@ | ||
import React from 'react'; | ||
import {Flex, Item, ActionGroup} from '@adobe/react-spectrum'; | ||
|
||
// Nishil | ||
// Implements the three transit use case buttons | ||
const TransitBar: React.FC = () => { | ||
return ( | ||
<Flex margin="auto" alignItems="center" justifyContent="center" height="100%"> | ||
<ActionGroup selectionMode="single" width="fit-content" defaultSelectedKeys={['planner']}> | ||
<Item key="departures">Departures</Item> | ||
<Item key="planner">Trip Planner</Item> | ||
<Item key="routes">Routes</Item> | ||
</ActionGroup> | ||
</Flex> | ||
); | ||
} | ||
|
||
export default TransitBar; | ||
import React from 'react'; | ||
import { Flex, ActionGroup, Item } from '@adobe/react-spectrum'; | ||
|
||
interface TransitBarProps { | ||
onSelect: (selectedView: string) => void; // Define the expected prop type | ||
} | ||
|
||
const TransitBar: React.FC<TransitBarProps> = ({ onSelect }) => { | ||
return ( | ||
<Flex margin="auto" alignItems="center" justifyContent="center" height="100%"> | ||
<ActionGroup | ||
selectionMode="single" | ||
width="fit-content" | ||
defaultSelectedKeys={['planner']} | ||
onSelectionChange={(selected) => { | ||
const key = Array.from(selected)[0] as string; // Correctly extract and cast the selected key | ||
if (key) { | ||
onSelect(key); // Pass the selected key to onSelect | ||
} | ||
}} | ||
> | ||
<Item key="departures">Departures</Item> | ||
<Item key="planner">Trip Planner</Item> | ||
<Item key="routes">Routes</Item> | ||
</ActionGroup> | ||
</Flex> | ||
); | ||
} | ||
|
||
export default TransitBar; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
.autocomplete-container { | ||
position: relative; | ||
} | ||
|
||
.suggestions { | ||
border: 1px solid #ccc; /* Optional: Add border for better visibility */ | ||
background-color: white; /* Background color for the dropdown */ | ||
z-index: 1000; /* Make sure it's on top of other elements */ | ||
max-height: 200px; /* Optional: Limit the height */ | ||
overflow-y: auto; /* Optional: Add scroll if there are many items */ | ||
} | ||
|
||
.suggestion-item { | ||
padding: 8px; /* Padding for each suggestion item */ | ||
cursor: pointer; /* Change cursor to pointer on hover */ | ||
color: black; /* Set text color to black */ | ||
} | ||
|
||
.suggestion-item:hover { | ||
background-color: #f0f0f0; /* Change background on hover */ | ||
} | ||
|
||
.map-container { | ||
height: 100%; | ||
display: flex; | ||
flex-direction: column; | ||
} | ||
|
||
.full-map { | ||
height: 400px; /* or another height as needed */ | ||
width: 100%; | ||
} |
Oops, something went wrong.