Skip to content

Commit

Permalink
All Changes
Browse files Browse the repository at this point in the history
All the changes I made including departures and trip-planner from other branches.

Updated HomePage.tsx and TransitBar.tsx
  • Loading branch information
yoelkidane authored Nov 15, 2024
1 parent 6a64bc3 commit 8793793
Show file tree
Hide file tree
Showing 14 changed files with 834 additions and 131 deletions.
164 changes: 164 additions & 0 deletions src/components/Departures.tsx
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;
12 changes: 12 additions & 0 deletions src/components/Routes.tsx
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;
46 changes: 23 additions & 23 deletions src/components/TopNavBar.tsx
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;
48 changes: 30 additions & 18 deletions src/components/TransitBar.tsx
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;
32 changes: 32 additions & 0 deletions src/components/TripPlanner.css
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%;
}
Loading

0 comments on commit 8793793

Please sign in to comment.