Compare commits
13 Commits
main
...
gtfs.delfi
Author | SHA1 | Date |
---|---|---|
dancingCycle | ec1a9a07ed | |
dancingCycle | c03c9b9448 | |
dancingCycle | ea24f8bff1 | |
dancingCycle | 70ab7dd025 | |
dancingCycle | cae6e7dbec | |
dancingCycle | 4b7b45d801 | |
dancingCycle | f5965706c1 | |
dancingCycle | a957846a13 | |
dancingCycle | dfc9b471f7 | |
dancingCycle | 381fe53fae | |
dancingCycle | 0e2b0aa2bb | |
dancingCycle | 4098acc541 | |
dancingCycle | 80a472bfa0 |
|
@ -1,44 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Table from 'react-bootstrap/Table';
|
||||
import Entry from './agency-table-entry';
|
||||
import Head from './agency-table-head';
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function AgencyTable ({ aryData }) {
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const handleAryData = () => {
|
||||
if (aryData.length > 0) {
|
||||
//iterate over array
|
||||
return aryData.map((item, index) => {
|
||||
//console.log('aryData index: ' + index);
|
||||
return (
|
||||
<Entry
|
||||
agencyId={item.agency_id}
|
||||
agencyName={item.agency_name}
|
||||
agencyUrl={item.agency_url}
|
||||
agencyTimezone={item.agency_timezone}
|
||||
agencyLang={item.agency_lang}
|
||||
agencyPhone={item.agency_phone}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead>
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{handleAryData()}</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
AgencyTable.propTypes = {
|
||||
aryData: PropTypes.array
|
||||
};
|
||||
export default AgencyTable;
|
|
@ -3,22 +3,22 @@ import PropTypes from 'prop-types';
|
|||
import FileSelect from '../components/file-select';
|
||||
import TablePage from '../components/table-page.js';
|
||||
const FileSelection = ({ options }) => {
|
||||
const defaultGtfsFile = 'Select GTFS file';
|
||||
const [gtfsFile, setGtfsFile] = useState(defaultGtfsFile);
|
||||
const handleChangeGtfsFile = (event) => {
|
||||
setGtfsFile((gtfsFile) => event.target.value);
|
||||
const defaultFile = 'Select file';
|
||||
const [fileName, setFileName] = useState(defaultFile);
|
||||
const handleChangeFile = (event) => {
|
||||
setFileName((fileName) => event.target.value);
|
||||
};
|
||||
if (options.length > 0) {
|
||||
return (
|
||||
<div>
|
||||
<FileSelect
|
||||
name="file"
|
||||
onChange={handleChangeGtfsFile}
|
||||
onChange={handleChangeFile}
|
||||
options={options}
|
||||
defaultValue={defaultGtfsFile}
|
||||
title={defaultGtfsFile}
|
||||
defaultValue={defaultFile}
|
||||
title={defaultFile}
|
||||
/>
|
||||
<TablePage name={gtfsFile} />
|
||||
<TablePage name={fileName} />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Table from 'react-bootstrap/Table';
|
||||
import Entry from './frequencies-table-entry';
|
||||
import Head from './frequencies-table-head';
|
||||
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function FrequenciesTable ({ aryData }) {
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const handleAryData = () => {
|
||||
if (aryData.length > 0) {
|
||||
//iterate over array
|
||||
return aryData.map((item, index) => {
|
||||
//console.log('aryData index: ' + index);
|
||||
return (
|
||||
<Entry
|
||||
tripId={item.trip_id}
|
||||
startTime={item.start_time}
|
||||
endTime={item.end_time}
|
||||
headwaySecs={item.headway_secs}
|
||||
exactTimes={item.exact_times}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead>
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{handleAryData()}</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
FrequenciesTable.propTypes = {
|
||||
aryData: PropTypes.array
|
||||
};
|
||||
export default FrequenciesTable;
|
|
@ -20,7 +20,7 @@ const GtfsFile = ({ name }) => {
|
|||
/*set state*/
|
||||
setCount(count.data[0]['count']);
|
||||
} catch (err) {
|
||||
console.log('err.message: ' + err.message);
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -4,38 +4,14 @@ import GtfsFile from './gtfs-file';
|
|||
import Container from 'react-bootstrap/Container';
|
||||
import Row from 'react-bootstrap/Row';
|
||||
import config from '../config';
|
||||
const GtfsFiles = () => {
|
||||
/*store and initialise data in function component state*/
|
||||
const [tables, setTables] = useState([]);
|
||||
/*fetch data in a JavaScript function*/
|
||||
const getTables = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const tables = await axios.get(`${config.API}table-names`);
|
||||
|
||||
/*set state*/
|
||||
setTables(tables.data);
|
||||
} catch (err) {
|
||||
console.log('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state migh result in an infinite loop*/
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
getTables();
|
||||
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, []);
|
||||
if (tables) {
|
||||
import PropTypes from 'prop-types';
|
||||
const GtfsFiles = ({data}) => {
|
||||
if (data.length>0) {
|
||||
return (
|
||||
<>
|
||||
<Container>
|
||||
<Row>
|
||||
{tables.map((item, index) => {
|
||||
{data.map((item, index) => {
|
||||
return <GtfsFile key={index} name={item['table_name']} />;
|
||||
})}
|
||||
</Row>
|
||||
|
@ -49,5 +25,7 @@ const GtfsFiles = () => {
|
|||
return <p>List of GTFS files loading...</p>;
|
||||
}
|
||||
};
|
||||
|
||||
GtfsFiles.propTypes = {
|
||||
data: PropTypes.array
|
||||
};
|
||||
export default GtfsFiles;
|
||||
|
|
|
@ -10,13 +10,8 @@ function NavigationBar () {
|
|||
<Navbar.Toggle aria-controls="basic-navbar-nav" />
|
||||
<Navbar.Collapse id="basic-navbar-nav">
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/agency">
|
||||
<Nav.Link>Agency</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/frequencies">
|
||||
<Nav.Link>Frequencies</Nav.Link>
|
||||
<LinkContainer to="/files">
|
||||
<Nav.Link>Files</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
|
@ -24,31 +19,11 @@ function NavigationBar () {
|
|||
<Nav.Link>Overview</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/routes">
|
||||
<Nav.Link>Routes</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/service">
|
||||
<Nav.Link>Service</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/shapes">
|
||||
<Nav.Link>Shapes</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/stops">
|
||||
<Nav.Link>Stops</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/trips">
|
||||
<Nav.Link>Trips</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/contact">
|
||||
<Nav.Link>Contact</Nav.Link>
|
||||
|
|
|
@ -22,7 +22,7 @@ function OverviewTable ({ overview }) {
|
|||
);
|
||||
});
|
||||
} else {
|
||||
console.log('overview NOT available');
|
||||
console.error('overview NOT available');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Table from 'react-bootstrap/Table';
|
||||
import Entry from './routes-table-entry';
|
||||
import Head from './routes-table-head';
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function RoutesTable ({ aryData }) {
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const handleAryData = () => {
|
||||
if (aryData.length > 0) {
|
||||
//iterate over array
|
||||
return aryData.map((item, index) => {
|
||||
//console.log('aryData index: ' + index);
|
||||
return (
|
||||
<Entry
|
||||
routeId={item.route_id}
|
||||
agencyId={item.agency_id}
|
||||
routeShortName={item.route_short_name}
|
||||
routeLongName={item.route_long_name}
|
||||
routeType={item.route_type}
|
||||
routeColor={item.route_color}
|
||||
routeTextColor={item.route_text_color}
|
||||
routeDesc={item.route_desc}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead>
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{handleAryData()}</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
RoutesTable.propTypes = {
|
||||
aryData: PropTypes.array
|
||||
};
|
||||
export default RoutesTable;
|
|
@ -5,13 +5,12 @@ import Entry from './service-table-entry';
|
|||
import Head from './service-table-head';
|
||||
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*accept a single property object argument*/
|
||||
function ServiceTable (props) {
|
||||
function ServiceTable ({service,render}) {
|
||||
/*map over msgs array and return Standortmeldungen*/
|
||||
const getService = () => {
|
||||
//iterate over object
|
||||
if (props.service) {
|
||||
return Object.entries(props.service).map((trips, key) => {
|
||||
if (service) {
|
||||
return Object.entries(service).map((trips, key) => {
|
||||
/*the strict equals operator does not converts operants of differnet type*/
|
||||
//console.log('key: ' + key);
|
||||
let objTrips = trips[1];
|
||||
|
@ -24,11 +23,12 @@ function ServiceTable (props) {
|
|||
return <Entry date={date.toDateString()} count={count} key={key} />;
|
||||
});
|
||||
} else {
|
||||
console.log('service NOT available');
|
||||
console.error('service NOT available');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
if (props.render) {
|
||||
if (render) {
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Table from 'react-bootstrap/Table';
|
||||
import Entry from './shapes-table-entry';
|
||||
import Head from './shapes-table-head';
|
||||
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function ShapesTable ({ aryData }) {
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const handleAryData = () => {
|
||||
if (aryData.length > 0) {
|
||||
//iterate over array
|
||||
return aryData.map((item, index) => {
|
||||
//console.log('aryData index: ' + index);
|
||||
return (
|
||||
<Entry
|
||||
shapeId={item.shape_id}
|
||||
shapePtLat={item.shape_pt_lat}
|
||||
shapePtLon={item.shape_pt_lon}
|
||||
shapePtSequence={item.shape_pt_sequence}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead>
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{handleAryData()}</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
ShapesTable.propTypes = {
|
||||
aryData: PropTypes.array
|
||||
};
|
||||
export default ShapesTable;
|
|
@ -1,50 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Table from 'react-bootstrap/Table';
|
||||
import Entry from './stops-table-entry';
|
||||
import Head from './stops-table-head';
|
||||
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function StopsTable ({ aryData }) {
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const handleAryData = () => {
|
||||
if (aryData.length > 0) {
|
||||
//iterate over array
|
||||
return aryData.map((item, index) => {
|
||||
//console.log('aryData index: ' + index);
|
||||
return (
|
||||
<Entry
|
||||
stopId={item.stop_id}
|
||||
stopCode={item.stop_code}
|
||||
stopName={item.stop_name}
|
||||
stopDesc={item.stop_desc}
|
||||
stopLat={item.stop_lat}
|
||||
stopLon={item.stop_lon}
|
||||
locationType={item.location_type}
|
||||
parentStation={item.parent_station}
|
||||
wheelchairBoarding={item.wheelchair_boarding}
|
||||
platformCode={item.platform_code}
|
||||
zoneId={item.zone_id}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead>
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{handleAryData()}</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
StopsTable.propTypes = {
|
||||
aryData: PropTypes.array
|
||||
};
|
||||
export default StopsTable;
|
|
@ -0,0 +1,206 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import AgencyEntry from './agency-table-entry';
|
||||
import CalendarEntry from './calendar-table-entry';
|
||||
import CalendarDatesEntry from './calendar-dates-table-entry';
|
||||
import FrequenciesEntry from './frequencies-table-entry';
|
||||
import LevelsEntry from './levels-table-entry';
|
||||
import RoutesEntry from './routes-table-entry';
|
||||
import ShapesEntry from './shapes-table-entry';
|
||||
import StopsEntry from './stops-table-entry';
|
||||
import StopTimesEntry from './stop-times-table-entry';
|
||||
import TransfersEntry from './transfers-table-entry';
|
||||
import TripsEntry from './trips-table-entry';
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function TableEntrySwitch ({ aryData, name }) {
|
||||
/*TODO add table entry for pathways*/
|
||||
if (aryData.length > 0) {
|
||||
//iterate over array
|
||||
return aryData.map((item, index) => {
|
||||
switch (name) {
|
||||
case 'agency':
|
||||
return (
|
||||
<AgencyEntry
|
||||
agencyId={item.agency_id}
|
||||
agencyName={item.agency_name}
|
||||
agencyUrl={item.agency_url}
|
||||
agencyTimezone={item.agency_timezone}
|
||||
agencyLanguage={item.agency_language}
|
||||
agencyPhone={item.agency_phone}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'calendar':
|
||||
return (
|
||||
<CalendarEntry
|
||||
serviceId={item.service_id}
|
||||
monday={item.monday}
|
||||
tuesday={item.tuesday}
|
||||
wednesday={item.wednesday}
|
||||
thursday={item.thursday}
|
||||
friday={item.friday}
|
||||
saturday={item.saturday}
|
||||
sunday={item.sunday}
|
||||
startDate={item.start_date}
|
||||
endDate={item.end_date}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'calendar_dates':
|
||||
return (
|
||||
<CalendarDatesEntry
|
||||
serviceId={item.service_id}
|
||||
date={item.date}
|
||||
exceptionType={item.exception_type}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'frequencies':
|
||||
return (
|
||||
<FrequenciesEntry
|
||||
tripId={item.trip_id}
|
||||
startTime={item.start_time}
|
||||
endTime={item.end_time}
|
||||
headwaySecs={item.headway_secs}
|
||||
exactTimes={item.exact_times}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'levels':
|
||||
return (
|
||||
<LevelsEntry
|
||||
levelId={item.level_id}
|
||||
levelIndex={item.level_index}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'routes':
|
||||
return (
|
||||
<RoutesEntry
|
||||
routeId={item.route_id}
|
||||
agencyId={item.agency_id}
|
||||
routeShortName={item.route_short_name}
|
||||
routeLongName={item.route_long_name}
|
||||
routeType={item.route_type}
|
||||
routeColor={item.route_color}
|
||||
routeTextColor={item.route_text_color}
|
||||
routeDesc={item.route_desc}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'shapes':
|
||||
return (
|
||||
<ShapesEntry
|
||||
shapeId={item.shape_id}
|
||||
shapePtLat={item.shape_pt_lat}
|
||||
shapePtLon={item.shape_pt_lon}
|
||||
shapePtSequence={item.shape_pt_sequence}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'stops':
|
||||
return (
|
||||
<StopsEntry
|
||||
stopId={item.stop_id}
|
||||
stopCode={item.stop_code}
|
||||
stopName={item.stop_name}
|
||||
stopDesc={item.stop_desc}
|
||||
stopLat={item.stop_lat}
|
||||
stopLon={item.stop_lon}
|
||||
locationType={item.location_type}
|
||||
parentStation={item.parent_station}
|
||||
wheelchairBoarding={item.wheelchair_boarding}
|
||||
platformCode={item.platform_code}
|
||||
zoneId={item.zone_id}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'stop_times':
|
||||
let arrivalTime = item.arrival_time;
|
||||
/*TODO Why is this condition neccessary?*/
|
||||
if (arrivalTime) {
|
||||
return (
|
||||
<StopTimesEntry
|
||||
tripId={item.trip_id}
|
||||
arrivalTimeHours={item.arrival_time['hours']}
|
||||
arrivalTimeMinutes={item.arrival_time['minutes']}
|
||||
departureTimeHours={item.departure_time['hours']}
|
||||
departureTimeMinutes={item.departure_time['minutes']}
|
||||
stopId={item.stop_id}
|
||||
stopSequence={item.stop_sequence}
|
||||
pickupType={item.pickup_type}
|
||||
dropOffType={item.drop_off_type}
|
||||
stopHeadsign={item.stop_headsign}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<StopTimesEntry
|
||||
tripId={item.trip_id}
|
||||
stopId={item.stop_id}
|
||||
stopSequence={item.stop_sequence}
|
||||
pickupType={item.pickup_type}
|
||||
dropOffType={item.drop_off_type}
|
||||
stopHeadsign={item.stop_headsign}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'transfers':
|
||||
return (
|
||||
<TransfersEntry
|
||||
fromStopId={item.from_stop_id}
|
||||
toStopId={item.to_stop_id}
|
||||
fromRouteId={item.from_route_id}
|
||||
toRouteId={item.to_route_id}
|
||||
fromTripId={item.from_trip_id}
|
||||
toTripId={item.to_trip_id}
|
||||
transferType={item.transfer_type}
|
||||
minTransferTime={item.min_transfer_time}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'trips':
|
||||
return (
|
||||
<TripsEntry
|
||||
routeId={item.route_id}
|
||||
serviceId={item.service_id}
|
||||
tripId={item.trip_id}
|
||||
tripHeadsign={item.trip_headsign}
|
||||
tripShortName={item.trip_short_name}
|
||||
directionId={item.direction_id}
|
||||
blockId={item.block_id}
|
||||
shapeId={item.shape_id}
|
||||
wheelchairAccessible={item.wheelchair_accessible}
|
||||
bikesAllowed={item.bikes_allowed}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
console.error(`${name} unknown`);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}else{
|
||||
console.error('data is empty');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
TableEntrySwitch.propTypes = {
|
||||
aryData: PropTypes.array,
|
||||
name: PropTypes.string
|
||||
};
|
||||
export default TableEntrySwitch;
|
|
@ -0,0 +1,63 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import AgencyHead from './agency-table-head';
|
||||
import CalendarHead from './calendar-table-head';
|
||||
import CalendarDatesHead from './calendar-dates-table-head';
|
||||
import FrequenciesHead from './frequencies-table-head';
|
||||
import LevelsHead from './levels-table-head';
|
||||
import PathwaysHead from './pathways-table-head';
|
||||
import RoutesHead from './routes-table-head';
|
||||
import ShapesHead from './shapes-table-head';
|
||||
import StopsHead from './stops-table-head';
|
||||
import StopTimesHead from './stop-times-table-head';
|
||||
import TransfersHead from './transfers-table-head';
|
||||
import TripsHead from './trips-table-head';
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function TableHeadSwitch ({ name }) {
|
||||
switch (name) {
|
||||
case 'agency':
|
||||
return <AgencyHead />;
|
||||
break;
|
||||
case 'calendar':
|
||||
return <CalendarHead />;
|
||||
break;
|
||||
case 'calendar_dates':
|
||||
return <CalendarDatesHead />;
|
||||
break;
|
||||
case 'frequencies':
|
||||
return <FrequenciesHead />;
|
||||
break;
|
||||
case 'levels':
|
||||
return <LevelsHead />;
|
||||
break;
|
||||
case 'pathways':
|
||||
return <PathwaysHead />;
|
||||
break;
|
||||
case 'routes':
|
||||
return <RoutesHead />;
|
||||
break;
|
||||
case 'shapes':
|
||||
return <ShapesHead />;
|
||||
break;
|
||||
case 'stops':
|
||||
return <StopsHead />;
|
||||
break;
|
||||
case 'stop_times':
|
||||
return <StopTimesHead />;
|
||||
break;
|
||||
case 'transfers':
|
||||
return <TransfersHead />;
|
||||
break;
|
||||
case 'trips':
|
||||
return <TripsHead />;
|
||||
break;
|
||||
default:
|
||||
console.error(`${name} unknown`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
TableHeadSwitch.propTypes = {
|
||||
name: PropTypes.string
|
||||
};
|
||||
export default TableHeadSwitch;
|
|
@ -1,46 +1,16 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import Select from '../components/select';
|
||||
const selectOptions = [10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000];
|
||||
import TablePageSwitch from '../components/table-switch';
|
||||
import Select from './select';
|
||||
import {selectOptions} from '../utils/select-options';
|
||||
import TableSwitch from './table-switch';
|
||||
import Stack from 'react-bootstrap/Stack';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import Input from './input';
|
||||
import PropTypes from 'prop-types';
|
||||
import config from '../config';
|
||||
const TablePage = ({ name }) => {
|
||||
/*store and initialise data in function component state*/
|
||||
const [oset, setOset] = useState(1);
|
||||
const [limit, setLimit] = useState(selectOptions[0]);
|
||||
const [ary, setAry] = useState([]);
|
||||
|
||||
/*fetch ary in a JavaScript function*/
|
||||
const fetch = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
//fetch data only if user selection is available
|
||||
if (name.indexOf(' ') === -1) {
|
||||
const address = `${config.API}${name}-oset-limit?oset=${oset}&limit=${limit}`;
|
||||
const res = await axios.get(address);
|
||||
/*set state*/
|
||||
setAry((ary) => res.data);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
//TODO handle error
|
||||
setAry((ary) => []);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state migh result in an infinite loop*/
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
fetch();
|
||||
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [oset, limit, name]);
|
||||
const [limit, setLimit] = useState(parseInt(selectOptions[0],10));
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const handleClickPrev = () => {
|
||||
setOset((oset) => (oset > 1 ? --oset : oset));
|
||||
};
|
||||
|
@ -48,9 +18,12 @@ const TablePage = ({ name }) => {
|
|||
setOset((oset) => ++oset);
|
||||
};
|
||||
const handleChangeLimit = (event) => {
|
||||
setLimit((limit) => event.target.value);
|
||||
setLimit((limit) => parseInt(event.target.value,10));
|
||||
};
|
||||
if (ary.length > 0 && name.indexOf(' ') === -1) {
|
||||
const handleSearch = (e) => {
|
||||
setSearchField((searchField)=>e.target.value);
|
||||
};
|
||||
if (name!==null && name.indexOf(' ') === -1) {
|
||||
return (
|
||||
<>
|
||||
<Stack direction="horizontal" gap={1} className="m-1">
|
||||
|
@ -62,22 +35,35 @@ const TablePage = ({ name }) => {
|
|||
</Button>
|
||||
<Select
|
||||
defaultValue={selectOptions[0]}
|
||||
id="tabePageLimit"
|
||||
id="tablePageLimit"
|
||||
name="tablePageLimit"
|
||||
onChange={handleChangeLimit}
|
||||
options={selectOptions}
|
||||
/>
|
||||
<Input
|
||||
id="tablePageSearch"
|
||||
name="tablePageSearch"
|
||||
onChange={handleSearch}
|
||||
placeholder="Search table globally"
|
||||
type="search"
|
||||
title="Enter search value"
|
||||
value={searchField}
|
||||
/>
|
||||
</Stack>
|
||||
<TablePageSwitch aryData={ary} name={name} />
|
||||
<TableSwitch
|
||||
name={name}
|
||||
isFetched={false}
|
||||
oset={oset}
|
||||
limit={limit}
|
||||
filter={searchField}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
TablePage.propTypes = {
|
||||
name: PropTypes.string
|
||||
};
|
||||
|
||||
export default TablePage;
|
||||
|
|
|
@ -1,269 +1,80 @@
|
|||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import PropTypes from 'prop-types';
|
||||
import Table from 'react-bootstrap/Table';
|
||||
import AgencyHead from './agency-table-head';
|
||||
import AgencyEntry from './agency-table-entry';
|
||||
import CalendarHead from './calendar-table-head';
|
||||
import CalendarEntry from './calendar-table-entry';
|
||||
import CalendarDatesHead from './calendar-dates-table-head';
|
||||
import CalendarDatesEntry from './calendar-dates-table-entry';
|
||||
import FrequenciesHead from './frequencies-table-head';
|
||||
import FrequenciesEntry from './frequencies-table-entry';
|
||||
import LevelsHead from './levels-table-head';
|
||||
import LevelsEntry from './levels-table-entry';
|
||||
import PathwaysHead from './pathways-table-head';
|
||||
import RoutesHead from './routes-table-head';
|
||||
import RoutesEntry from './routes-table-entry';
|
||||
import ShapesHead from './shapes-table-head';
|
||||
import ShapesEntry from './shapes-table-entry';
|
||||
import StopsHead from './stops-table-head';
|
||||
import StopsEntry from './stops-table-entry';
|
||||
import StopTimesHead from './stop-times-table-head';
|
||||
import StopTimesEntry from './stop-times-table-entry';
|
||||
import TransfersHead from './transfers-table-head';
|
||||
import TransfersEntry from './transfers-table-entry';
|
||||
import TripsHead from './trips-table-head';
|
||||
import TripsEntry from './trips-table-entry';
|
||||
|
||||
import TableHeadSwitch from './table-head-switch';
|
||||
import TableEntrySwitch from './table-entry-switch';
|
||||
import config from '../config';
|
||||
import {filterData} from '../utils/filter-data';
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function TableSwitch ({ aryData, name }) {
|
||||
const handleTableHead = () => {
|
||||
switch (name) {
|
||||
case 'agency':
|
||||
return <AgencyHead />;
|
||||
break;
|
||||
case 'calendar':
|
||||
return <CalendarHead />;
|
||||
break;
|
||||
case 'calendar_dates':
|
||||
return <CalendarDatesHead />;
|
||||
break;
|
||||
case 'frequencies':
|
||||
return <FrequenciesHead />;
|
||||
break;
|
||||
case 'levels':
|
||||
return <LevelsHead />;
|
||||
break;
|
||||
case 'pathways':
|
||||
return <PathwaysHead />;
|
||||
break;
|
||||
case 'routes':
|
||||
return <RoutesHead />;
|
||||
break;
|
||||
case 'shapes':
|
||||
return <ShapesHead />;
|
||||
break;
|
||||
case 'stops':
|
||||
return <StopsHead />;
|
||||
break;
|
||||
case 'stop_times':
|
||||
return <StopTimesHead />;
|
||||
break;
|
||||
case 'transfers':
|
||||
return <TransfersHead />;
|
||||
break;
|
||||
case 'trips':
|
||||
return <TripsHead />;
|
||||
break;
|
||||
default:
|
||||
console.error('file unknown');
|
||||
function TableSwitch ({name, isFetched, oset, limit, filter}) {
|
||||
//console.log('TableSwitch name: '+name);
|
||||
//console.log('TableSwitch isFetched: '+isFetched);
|
||||
//console.log('TableSwitch filter: '+filter);
|
||||
const [ary, setAry] = useState([]);
|
||||
const [aryFiltered, setAryFiltered] = useState([]);
|
||||
const [fetchCompleted, setFetchCompleted] = useState(isFetched);
|
||||
/*fetch ary in a JavaScript function*/
|
||||
const fetch = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
//fetch data only if user selection is unequal default value
|
||||
if (name.length>0 && name.indexOf(' ') === -1) {
|
||||
const address = `${config.API}${name}-oset-limit?oset=${oset}&limit=${limit}`;
|
||||
const res = await axios.get(address);
|
||||
setAry((ary) => res.data);
|
||||
let data=filterData(res.data,name,filter);
|
||||
setAryFiltered((aryFiltered) => data);
|
||||
} else {
|
||||
console.error(`name ${name} not valid`);
|
||||
setAry((ary) => []);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
setAry((ary) => []);
|
||||
}
|
||||
};
|
||||
const handleTableEntry = () => {
|
||||
/*TODO add table entry for pathways*/
|
||||
if (aryData.length > 0) {
|
||||
//iterate over array
|
||||
return aryData.map((item, index) => {
|
||||
switch (name) {
|
||||
case 'agency':
|
||||
return (
|
||||
<AgencyEntry
|
||||
agencyId={item.agency_id}
|
||||
agencyName={item.agency_name}
|
||||
agencyUrl={item.agency_url}
|
||||
agencyTimezone={item.agency_timezone}
|
||||
agencyLanguage={item.agency_language}
|
||||
agencyPhone={item.agency_phone}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'calendar':
|
||||
return (
|
||||
<CalendarEntry
|
||||
serviceId={item.service_id}
|
||||
monday={item.monday}
|
||||
tuesday={item.tuesday}
|
||||
wednesday={item.wednesday}
|
||||
thursday={item.thursday}
|
||||
friday={item.friday}
|
||||
saturday={item.saturday}
|
||||
sunday={item.sunday}
|
||||
startDate={item.start_date}
|
||||
endDate={item.end_date}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'calendar_dates':
|
||||
return (
|
||||
<CalendarDatesEntry
|
||||
serviceId={item.service_id}
|
||||
date={item.date}
|
||||
exceptionType={item.exception_type}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'frequencies':
|
||||
return (
|
||||
<FrequenciesEntry
|
||||
tripId={item.trip_id}
|
||||
startTime={item.start_time}
|
||||
endTime={item.end_time}
|
||||
headwaySecs={item.headway_secs}
|
||||
exactTimes={item.exact_times}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'levels':
|
||||
return (
|
||||
<LevelsEntry
|
||||
levelId={item.level_id}
|
||||
levelIndex={item.level_index}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'routes':
|
||||
return (
|
||||
<RoutesEntry
|
||||
routeId={item.route_id}
|
||||
agencyId={item.agency_id}
|
||||
routeShortName={item.route_short_name}
|
||||
routeLongName={item.route_long_name}
|
||||
routeType={item.route_type}
|
||||
routeColor={item.route_color}
|
||||
routeTextColor={item.route_text_color}
|
||||
routeDesc={item.route_desc}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'shapes':
|
||||
return (
|
||||
<ShapesEntry
|
||||
shapeId={item.shape_id}
|
||||
shapePtLat={item.shape_pt_lat}
|
||||
shapePtLon={item.shape_pt_lon}
|
||||
shapePtSequence={item.shape_pt_sequence}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'stops':
|
||||
return (
|
||||
<StopsEntry
|
||||
stopId={item.stop_id}
|
||||
stopCode={item.stop_code}
|
||||
stopName={item.stop_name}
|
||||
stopDesc={item.stop_desc}
|
||||
stopLat={item.stop_lat}
|
||||
stopLon={item.stop_lon}
|
||||
locationType={item.location_type}
|
||||
parentStation={item.parent_station}
|
||||
wheelchairBoarding={item.wheelchair_boarding}
|
||||
platformCode={item.platform_code}
|
||||
zoneId={item.zone_id}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'stop_times':
|
||||
let arrivalTime = item.arrival_time;
|
||||
/*TODO Why is this condition neccessary?*/
|
||||
if (arrivalTime) {
|
||||
return (
|
||||
<StopTimesEntry
|
||||
tripId={item.trip_id}
|
||||
arrivalTimeHours={item.arrival_time['hours']}
|
||||
arrivalTimeMinutes={item.arrival_time['minutes']}
|
||||
departureTimeHours={item.departure_time['hours']}
|
||||
departureTimeMinutes={item.departure_time['minutes']}
|
||||
stopId={item.stop_id}
|
||||
stopSequence={item.stop_sequence}
|
||||
pickupType={item.pickup_type}
|
||||
dropOffType={item.drop_off_type}
|
||||
stopHeadsign={item.stop_headsign}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<StopTimesEntry
|
||||
tripId={item.trip_id}
|
||||
stopId={item.stop_id}
|
||||
stopSequence={item.stop_sequence}
|
||||
pickupType={item.pickup_type}
|
||||
dropOffType={item.drop_off_type}
|
||||
stopHeadsign={item.stop_headsign}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'transfers':
|
||||
return (
|
||||
<TransfersEntry
|
||||
fromStopId={item.from_stop_id}
|
||||
toStopId={item.to_stop_id}
|
||||
fromRouteId={item.from_route_id}
|
||||
toRouteId={item.to_route_id}
|
||||
fromTripId={item.from_trip_id}
|
||||
toTripId={item.to_trip_id}
|
||||
transferType={item.transfer_type}
|
||||
minTransferTime={item.min_transfer_time}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'trips':
|
||||
return (
|
||||
<TripsEntry
|
||||
routeId={item.route_id}
|
||||
serviceId={item.service_id}
|
||||
tripId={item.trip_id}
|
||||
tripHeadsign={item.trip_headsign}
|
||||
tripShortName={item.trip_short_name}
|
||||
directionId={item.direction_id}
|
||||
blockId={item.block_id}
|
||||
shapeId={item.shape_id}
|
||||
wheelchairAccessible={item.wheelchair_accessible}
|
||||
bikesAllowed={item.bikes_allowed}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
console.error('file unknown');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
/*return a React element*/
|
||||
return (
|
||||
useEffect(()=>{
|
||||
setAryFiltered(aryFiltered=>filterData(ary,name,filter));
|
||||
},[filter]);
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
fetch();
|
||||
setFetchCompleted((fetchCompleted)=>true);
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [name,oset,limit]);
|
||||
if(fetchCompleted && aryFiltered.length > 0){
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead>{handleTableHead()}</thead>
|
||||
<tbody>{handleTableEntry()}</tbody>
|
||||
<Table
|
||||
striped
|
||||
bordered
|
||||
hover
|
||||
size="sm"
|
||||
variant="dark"
|
||||
responsive
|
||||
>
|
||||
<thead>
|
||||
<TableHeadSwitch name={name}/>
|
||||
</thead>
|
||||
<tbody>
|
||||
<TableEntrySwitch aryData={aryFiltered} name={name}/>
|
||||
</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
);
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
TableSwitch.propTypes = {
|
||||
aryData: PropTypes.array,
|
||||
name: PropTypes.string
|
||||
name: PropTypes.string,
|
||||
isFetched: PropTypes.bool,
|
||||
offset: PropTypes.number,
|
||||
limit: PropTypes.number,
|
||||
filter: PropTypes.string
|
||||
};
|
||||
export default TableSwitch;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import FileSelection from '../components/file-selection';
|
||||
import FileSelection from './file-selection';
|
||||
const Tables = ({ data }) => {
|
||||
//console.log('Tables data.length: '+data.length);
|
||||
if (data.length > 0) {
|
||||
return (
|
||||
<>
|
||||
|
@ -9,10 +10,10 @@ const Tables = ({ data }) => {
|
|||
</>
|
||||
);
|
||||
} else {
|
||||
return <p>Files loading...</p>;
|
||||
return <p>Selection loading...</p>;
|
||||
}
|
||||
};
|
||||
export default Tables;
|
||||
Tables.propTypes = {
|
||||
data: PropTypes.array
|
||||
};
|
||||
export default Tables;
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
const ToggleBtn = (props) => {
|
||||
//destructuring
|
||||
const { btnState, btnTrue, btnFalse, descTrue, descFalse, btnOnClick } =
|
||||
props;
|
||||
//render
|
||||
return (
|
||||
<>
|
||||
<button onClick={btnOnClick}>
|
||||
{btnState === false ? btnFalse : btnTrue}
|
||||
</button>
|
||||
{btnState === false ? descFalse : descTrue}
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default ToggleBtn;
|
||||
ToggleBtn.propTypes = {
|
||||
btnState: PropTypes.bool,
|
||||
btnTrue: PropTypes.string,
|
||||
btnFalse: PropTypes.string,
|
||||
descTrue: PropTypes.string,
|
||||
descFalse: PropTypes.string,
|
||||
btnOnClick: PropTypes.func
|
||||
};
|
|
@ -1,49 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Table from 'react-bootstrap/Table';
|
||||
import Entry from './trips-table-entry';
|
||||
import Head from './trips-table-head';
|
||||
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function TripsTable ({ aryData }) {
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const handleAryData = () => {
|
||||
if (aryData.length > 0) {
|
||||
//iterate over array
|
||||
return aryData.map((item, index) => {
|
||||
//console.log('aryData index: ' + index);
|
||||
return (
|
||||
<Entry
|
||||
routeId={item.route_id}
|
||||
serviceId={item.service_id}
|
||||
tripId={item.trip_id}
|
||||
tripHeadsign={item.trip_headsign}
|
||||
tripShortName={item.trip_short_name}
|
||||
directionId={item.direction_id}
|
||||
blockId={item.block_id}
|
||||
shapeId={item.shape_id}
|
||||
wheelchairAccessibel={item.wheechair_accessible}
|
||||
bikesAllowed={item.bikes_allowed}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead>
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{handleAryData()}</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
TripsTable.propTypes = {
|
||||
aryData: PropTypes.array
|
||||
};
|
||||
export default TripsTable;
|
|
@ -1,4 +1,4 @@
|
|||
export default {
|
||||
API: 'https://v1gtfs.vbn.api.swingbe.de/',
|
||||
GTFS_VALIDATOR_REPORT: 'https://www.v1gtfs.vbn.api.swingbe.de/gtfs-validator/report.html',
|
||||
API: 'https://v1gtfs.delfi.api.swingbe.de/',
|
||||
GTFS_VALIDATOR_REPORT: 'https://www.v1gtfs.delfi.api.swingbe.de/gtfs-validator/report.html',
|
||||
};
|
||||
|
|
14
app/main.js
14
app/main.js
|
@ -6,14 +6,9 @@ import 'bootstrap/dist/css/bootstrap.min.css';
|
|||
|
||||
import NavBar from './components/nav-bar';
|
||||
import HomePage from './pages/homepage';
|
||||
import Agency from './pages/agency';
|
||||
import Frequencies from './pages/frequencies';
|
||||
import GtfsRoutes from './pages/routes';
|
||||
import Files from './pages/files';
|
||||
import Overview from './pages/overview';
|
||||
import Service from './pages/service';
|
||||
import Shapes from './pages/shapes';
|
||||
import Stops from './pages/stops';
|
||||
import Trips from './pages/trips';
|
||||
import Contact from './pages/contact';
|
||||
|
||||
const Main = () => {
|
||||
|
@ -26,14 +21,9 @@ const Main = () => {
|
|||
<NavBar />
|
||||
<Routes>
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/agency" element={<Agency />} />
|
||||
<Route path="/frequencies" element={<Frequencies />} />
|
||||
<Route path="/routes" element={<GtfsRoutes />} />
|
||||
<Route path="/files" element={<Files />} />
|
||||
<Route path="/overview" element={<Overview />} />
|
||||
<Route path="/service" element={<Service />} />
|
||||
<Route path="/shapes" element={<Shapes />} />
|
||||
<Route path="/stops" element={<Stops />} />
|
||||
<Route path="/trips" element={<Trips />} />
|
||||
<Route path="/contact" element={<Contact />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import Select from '../components/select';
|
||||
import {selectOptions} from '../utils/select-options';
|
||||
import AgencyTable from '../components/agency-table';
|
||||
import Stack from 'react-bootstrap/Stack';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import Input from '../components/input';
|
||||
import config from '../config';
|
||||
const Agency = () => {
|
||||
/*store and initialise data in function component state*/
|
||||
const [oset, setOset] = useState(1);
|
||||
const [limit, setLimit] = useState(selectOptions[2]);
|
||||
const [ary, setAry] = useState([]);
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const filteredAry = ary.filter((item, index) => {
|
||||
return (
|
||||
(item.agency_id!==null && item.agency_id.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
item.agency_name.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
item.agency_url.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
item.agency_timezone.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
(item.agency_lang!==null && item.agency_lang.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.agency_phone!==null && item.agency_phone.toLowerCase().includes(searchField.toLowerCase()))
|
||||
);
|
||||
});
|
||||
/*fetch ary in a JavaScript function*/
|
||||
const fetch = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const address = `${config.API}agency-oset-limit?oset=${oset}&limit=${limit}`;
|
||||
const res = await axios.get(address);
|
||||
|
||||
/*set state*/
|
||||
setAry(res.data);
|
||||
} catch (err) {
|
||||
console.log('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state migh result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
fetch();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [oset, limit]);
|
||||
const handleClickPrev = () => {
|
||||
setOset((oset) => (oset > 1 ? --oset : oset));
|
||||
};
|
||||
const handleClickNext = () => {
|
||||
setOset((oset) => ++oset);
|
||||
};
|
||||
const handleChangeLimit = (event) => {
|
||||
setLimit((limit) => event.target.value);
|
||||
};
|
||||
const handleSearch = (e) => {
|
||||
setSearchField(e.target.value);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Stack direction="horizontal" gap={1} className="m-1">
|
||||
<Button variant="secondary" onClick={handleClickPrev} autoFocus>
|
||||
prev
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClickNext}>
|
||||
next
|
||||
</Button>
|
||||
<Select
|
||||
defaultValue={selectOptions[2]}
|
||||
id="agencyLimit"
|
||||
name="agencyLimit"
|
||||
onChange={handleChangeLimit}
|
||||
options={selectOptions}
|
||||
/>
|
||||
<Input
|
||||
id="agencySearch"
|
||||
name="agencySearch"
|
||||
onChange={handleSearch}
|
||||
placeholder="Search table globally"
|
||||
title="Enter search value"
|
||||
type="search"
|
||||
value={searchField}
|
||||
/>
|
||||
</Stack>
|
||||
<AgencyTable aryData={filteredAry} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default Agency;
|
|
@ -0,0 +1,43 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import Tables from '../components/tables.js';
|
||||
import config from '../config';
|
||||
const Files = () => {
|
||||
/*store and initialise data in function component state*/
|
||||
const [tables, setTables] = useState([]);
|
||||
/*fetch data in a JavaScript function*/
|
||||
const getTables = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const tables = await axios.get(`${config.API}table-names`);
|
||||
|
||||
/*set state*/
|
||||
setTables(tables.data);
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state migh result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
getTables();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, []);
|
||||
if(tables.length>0){
|
||||
return (
|
||||
<>
|
||||
<Tables data={tables} />
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return (
|
||||
<>
|
||||
<p>Files loading...</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
export default Files;
|
|
@ -1,89 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import Select from '../components/select';
|
||||
import {selectOptions} from '../utils/select-options';
|
||||
import FrequenciesTable from '../components/frequencies-table';
|
||||
import Stack from 'react-bootstrap/Stack';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import Input from '../components/input';
|
||||
import config from '../config';
|
||||
const Frequencies = () => {
|
||||
/*store and initialise data in function component state*/
|
||||
const [oset, setOset] = useState(1);
|
||||
const [limit, setLimit] = useState(selectOptions[2]);
|
||||
const [ary, setAry] = useState([]);
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const filteredAry = ary.filter((item, index) => {
|
||||
return (
|
||||
item.trip_id.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
item.start_time.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
item.end_time.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
item.headway_secs.toString().includes(searchField) ||
|
||||
(item.exact_times!==null && item.exact_times.toString().includes(searchField))
|
||||
);
|
||||
});
|
||||
/*fetch ary in a JavaScript function*/
|
||||
const fetch = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const address = `${config.API}frequencies-oset-limit?oset=${oset}&limit=${limit}`;
|
||||
const res = await axios.get(address);
|
||||
|
||||
/*set state*/
|
||||
setAry(res.data);
|
||||
} catch (err) {
|
||||
console.log('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state migh result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
fetch();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [oset, limit]);
|
||||
const handleClickPrev = () => {
|
||||
setOset((oset) => (oset > 1 ? --oset : oset));
|
||||
};
|
||||
const handleClickNext = () => {
|
||||
setOset((oset) => ++oset);
|
||||
};
|
||||
const handleChangeLimit = (event) => {
|
||||
setLimit((limit) => event.target.value);
|
||||
};
|
||||
const handleSearch = (e) => {
|
||||
setSearchField(e.target.value);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Stack direction="horizontal" gap={1} className="m-1">
|
||||
<Button variant="secondary" onClick={handleClickPrev} autoFocus>
|
||||
prev
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClickNext}>
|
||||
next
|
||||
</Button>
|
||||
<Select
|
||||
defaultValue={selectOptions[2]}
|
||||
id="frequenciesLimit"
|
||||
name="frequenciesLimit"
|
||||
onChange={handleChangeLimit}
|
||||
options={selectOptions}
|
||||
/>
|
||||
<Input
|
||||
id="frequenciesSearch"
|
||||
name="frequenciesSearch"
|
||||
onChange={handleSearch}
|
||||
placeholder="Search table globally"
|
||||
type="search"
|
||||
title="Enter search value"
|
||||
value={searchField}
|
||||
/>
|
||||
</Stack>
|
||||
<FrequenciesTable aryData={filteredAry} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default Frequencies;
|
|
@ -12,7 +12,6 @@ const Homepage = () => {
|
|||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const tables = await axios.get(`${config.API}table-names`);
|
||||
|
||||
/*set state*/
|
||||
setTables(tables.data);
|
||||
} catch (err) {
|
||||
|
@ -30,12 +29,20 @@ const Homepage = () => {
|
|||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<GtfsValidatorReport />
|
||||
<GtfsFiles />
|
||||
<Tables data={tables} />
|
||||
</>
|
||||
);
|
||||
if(tables.length>0){
|
||||
return (
|
||||
<>
|
||||
<GtfsValidatorReport />
|
||||
<GtfsFiles data={tables}/>
|
||||
<Tables data={tables} />
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return (
|
||||
<>
|
||||
<GtfsValidatorReport />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
export default Homepage;
|
||||
|
|
|
@ -60,7 +60,6 @@ const Overview = () => {
|
|||
/*get agencies*/
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const res = await axios.get(`${config.API}agency-all`);
|
||||
|
||||
let aryOv = res.data;
|
||||
for (var i = 0; i < aryOv.length; i++) {
|
||||
let agencyId = aryOv[i].agency_id;
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import Select from '../components/select';
|
||||
import {selectOptions} from '../utils/select-options';
|
||||
import RoutesTable from '../components/routes-table';
|
||||
import Stack from 'react-bootstrap/Stack';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import Input from '../components/input';
|
||||
import config from '../config';
|
||||
const Routes = () => {
|
||||
/*store and initialise data in function component state*/
|
||||
const [oset, setOset] = useState(1);
|
||||
const [limit, setLimit] = useState(selectOptions[2]);
|
||||
const [ary, setAry] = useState([]);
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const filteredAry = ary.filter((item, index) => {
|
||||
return (
|
||||
item.route_id.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
(item.agency_id!==null && item.agency_id.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.route_short_name!==null && item.route_short_name.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.route_long_name!==null && item.route_long_name.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
item.route_type.toString().includes(searchField.toLowerCase()) ||
|
||||
(item.route_color!==null && item.route_color.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.route_text_color!==null && item.route_text_color.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.route_desc!==null &&item.route_desc.toLowerCase().includes(searchField.toLowerCase()))
|
||||
);
|
||||
});
|
||||
/*fetch ary in a JavaScript function*/
|
||||
const fetch = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const address = `${config.API}routes-oset-limit?oset=${oset}&limit=${limit}`;
|
||||
const res = await axios.get(address);
|
||||
|
||||
/*set state*/
|
||||
setAry(res.data);
|
||||
} catch (err) {
|
||||
console.log('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state migh result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
fetch();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [oset, limit]);
|
||||
const handleClickPrev = () => {
|
||||
setOset((oset) => (oset > 1 ? --oset : oset));
|
||||
};
|
||||
const handleClickNext = () => {
|
||||
setOset((oset) => ++oset);
|
||||
};
|
||||
const handleChangeLimit = (event) => {
|
||||
setLimit((limit) => event.target.value);
|
||||
};
|
||||
const handleSearch = (e) => {
|
||||
setSearchField(e.target.value);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Stack direction="horizontal" gap={1} className="m-1">
|
||||
<Button variant="secondary" onClick={handleClickPrev} autoFocus>
|
||||
prev
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClickNext}>
|
||||
next
|
||||
</Button>
|
||||
<Select
|
||||
defaultValue={selectOptions[2]}
|
||||
id="shapesLimit"
|
||||
name="shapesLimit"
|
||||
onChange={handleChangeLimit}
|
||||
options={selectOptions}
|
||||
/>
|
||||
<Input
|
||||
id="shapesSearch"
|
||||
name="shapesSearch"
|
||||
onChange={handleSearch}
|
||||
placeholder="Search table globally"
|
||||
type="search"
|
||||
title="Enter search value"
|
||||
value={searchField}
|
||||
/>
|
||||
</Stack>
|
||||
<RoutesTable aryData={filteredAry} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default Routes;
|
|
@ -34,7 +34,7 @@ const Service = () => {
|
|||
const aryDate = aryTime.map((time) => new Date(time).toDateString());
|
||||
setTime(aryDate);
|
||||
} catch (err) {
|
||||
console.log('err.message: ' + err.message);
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import Select from '../components/select';
|
||||
import {selectOptions} from '../utils/select-options';
|
||||
import ShapesTable from '../components/shapes-table';
|
||||
import Stack from 'react-bootstrap/Stack';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import Input from '../components/input';
|
||||
import config from '../config';
|
||||
const Shapes = () => {
|
||||
/*store and initialise data in function component state*/
|
||||
const [oset, setOset] = useState(1);
|
||||
const [limit, setLimit] = useState(selectOptions[2]);
|
||||
const [ary, setAry] = useState([]);
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const filteredAry = ary.filter((item, index) => {
|
||||
return (
|
||||
item.shape_id.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
item.shape_pt_lat.toString().includes(searchField) ||
|
||||
item.shape_pt_lon.toString().includes(searchField) ||
|
||||
item.shape_pt_sequence.toString().includes(searchField)
|
||||
);
|
||||
});
|
||||
/*fetch ary in a JavaScript function*/
|
||||
const fetch = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const address = `${config.API}shapes-oset-limit?oset=${oset}&limit=${limit}`;
|
||||
const res = await axios.get(address);
|
||||
|
||||
/*set state*/
|
||||
setAry(res.data);
|
||||
} catch (err) {
|
||||
console.log('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state migh result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
fetch();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [oset, limit]);
|
||||
const handleClickPrev = () => {
|
||||
setOset((oset) => (oset > 1 ? --oset : oset));
|
||||
};
|
||||
const handleClickNext = () => {
|
||||
setOset((oset) => ++oset);
|
||||
};
|
||||
const handleChangeLimit = (event) => {
|
||||
setLimit((limit) => event.target.value);
|
||||
};
|
||||
const handleSearch = (e) => {
|
||||
setSearchField(e.target.value);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Stack direction="horizontal" gap={1} className="m-1">
|
||||
<Button variant="secondary" onClick={handleClickPrev} autoFocus>
|
||||
prev
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClickNext}>
|
||||
next
|
||||
</Button>
|
||||
<Select
|
||||
defaultValue={selectOptions[2]}
|
||||
id="shapesLimit"
|
||||
name="shapesLimit"
|
||||
onChange={handleChangeLimit}
|
||||
options={selectOptions}
|
||||
/>
|
||||
<Input
|
||||
id="shapesSearch"
|
||||
name="shapesSearch"
|
||||
onChange={handleSearch}
|
||||
placeholder="Search table globally"
|
||||
type="search"
|
||||
title="Enter search value"
|
||||
value={searchField}
|
||||
/>
|
||||
</Stack>
|
||||
<ShapesTable aryData={filteredAry} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default Shapes;
|
|
@ -1,95 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import Select from '../components/select';
|
||||
import {selectOptions} from '../utils/select-options';
|
||||
import StopsTable from '../components/stops-table';
|
||||
import Stack from 'react-bootstrap/Stack';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import Input from '../components/input';
|
||||
import config from '../config';
|
||||
const Stops = () => {
|
||||
/*store and initialise data in function component state*/
|
||||
const [oset, setOset] = useState(1);
|
||||
const [limit, setLimit] = useState(selectOptions[2]);
|
||||
const [ary, setAry] = useState([]);
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const filteredAry = ary.filter((item, index) => {
|
||||
return (
|
||||
item.stop_id.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
(item.stop_code!==null && item.stop_code.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.stop_name!==null && item.stop_name.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.stop_desc!==null && item.stop_descr.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.stop_lat!==null && item.stop_lat.toString().includes(searchField)) ||
|
||||
(item.stop_lon!==null && item.stop_lon.toString().includes(searchField)) ||
|
||||
(item.location_type!==null && item.location_type.toString().includes(searchField)) ||
|
||||
(item.parent_station!==null && item.parent_station.toString().includes(searchField)) ||
|
||||
(item.wheelchair_boarding!==null && item.wheelchair_boarding.toString().includes(searchField)) ||
|
||||
(item.platform_code!==null && item.platform_code.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.zone_id!==null && item.zone_id.toLowerCase().includes(searchField.toLowerCase()))
|
||||
);
|
||||
});
|
||||
/*fetch ary in a JavaScript function*/
|
||||
const fetch = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const address = `${config.API}stops-oset-limit?oset=${oset}&limit=${limit}`;
|
||||
const res = await axios.get(address);
|
||||
|
||||
/*set state*/
|
||||
setAry(res.data);
|
||||
} catch (err) {
|
||||
console.log('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state migh result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
fetch();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [oset, limit]);
|
||||
const handleClickPrev = () => {
|
||||
setOset((oset) => (oset > 1 ? --oset : oset));
|
||||
};
|
||||
const handleClickNext = () => {
|
||||
setOset((oset) => ++oset);
|
||||
};
|
||||
const handleChangeLimit = (event) => {
|
||||
setLimit((limit) => event.target.value);
|
||||
};
|
||||
const handleSearch = (e) => {
|
||||
setSearchField(e.target.value);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Stack direction="horizontal" gap={1} className="m-1">
|
||||
<Button variant="secondary" onClick={handleClickPrev} autoFocus>
|
||||
prev
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClickNext}>
|
||||
next
|
||||
</Button>
|
||||
<Select
|
||||
defaultValue={selectOptions[2]}
|
||||
id="stopsLimit"
|
||||
name="stopsLimit"
|
||||
onChange={handleChangeLimit}
|
||||
options={selectOptions}
|
||||
/>
|
||||
<Input
|
||||
id="stopsSearch"
|
||||
name="stopsSearch"
|
||||
onChange={handleSearch}
|
||||
placeholder="Search table globally"
|
||||
type="search"
|
||||
title="Enter search value"
|
||||
value={searchField}
|
||||
/>
|
||||
</Stack>
|
||||
<StopsTable aryData={filteredAry} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default Stops;
|
|
@ -1,94 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import Select from '../components/select';
|
||||
import {selectOptions} from '../utils/select-options';
|
||||
import TripsTable from '../components/trips-table';
|
||||
import Stack from 'react-bootstrap/Stack';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import Input from '../components/input';
|
||||
import config from '../config';
|
||||
const Trips = () => {
|
||||
/*store and initialise data in function component state*/
|
||||
const [oset, setOset] = useState(1);
|
||||
const [limit, setLimit] = useState(selectOptions[2]);
|
||||
const [ary, setAry] = useState([]);
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const filteredAry = ary.filter((item, index) => {
|
||||
return (
|
||||
item.route_id.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
item.service_id.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
item.trip_id.toLowerCase().includes(searchField.toLowerCase()) ||
|
||||
(item.trip_headsign!==null && item.trip_headsign.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.trip_short_name!==null && item.trip_short_name.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.direction_id!==null && item.direction_id.toString().includes(searchField)) ||
|
||||
(item.block_id!==null && item.block_id.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.shape_id!==null && item.shape_id.toLowerCase().includes(searchField.toLowerCase())) ||
|
||||
(item.wheelchair_accessible!==null && item.wheelchair_accessible.toString().includes(searchField)) ||
|
||||
(item.bikes_allowed!==null && item.bikes_allowed.toString().includes(searchField))
|
||||
);
|
||||
});
|
||||
/*fetch ary in a JavaScript function*/
|
||||
const fetch = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const address = `${config.API}trips-oset-limit?oset=${oset}&limit=${limit}`;
|
||||
const res = await axios.get(address);
|
||||
|
||||
/*set state*/
|
||||
setAry(res.data);
|
||||
} catch (err) {
|
||||
console.log('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state migh result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
fetch();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [oset, limit]);
|
||||
const handleClickPrev = () => {
|
||||
setOset((oset) => (oset > 1 ? --oset : oset));
|
||||
};
|
||||
const handleClickNext = () => {
|
||||
setOset((oset) => ++oset);
|
||||
};
|
||||
const handleChangeLimit = (event) => {
|
||||
setLimit((limit) => event.target.value);
|
||||
};
|
||||
const handleSearch = (e) => {
|
||||
setSearchField(e.target.value);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Stack direction="horizontal" gap={1} className="m-1">
|
||||
<Button variant="secondary" onClick={handleClickPrev} autoFocus>
|
||||
prev
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClickNext}>
|
||||
next
|
||||
</Button>
|
||||
<Select
|
||||
defaultValue={selectOptions[2]}
|
||||
id="tripsLimit"
|
||||
name="tripsLimit"
|
||||
onChange={handleChangeLimit}
|
||||
options={selectOptions}
|
||||
/>
|
||||
<Input
|
||||
id="tripsSearch"
|
||||
name="tripsSearch"
|
||||
onChange={handleSearch}
|
||||
placeholder="Search table globally"
|
||||
type="search"
|
||||
title="Enter search value"
|
||||
value={searchField}
|
||||
/>
|
||||
</Stack>
|
||||
<TripsTable aryData={filteredAry} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default Trips;
|
|
@ -0,0 +1,96 @@
|
|||
function filterData(data, name,filter){
|
||||
if(data.length>0){
|
||||
//console.log('filterData() data.length: '+data.length);
|
||||
//console.log('filterData() name: '+name);
|
||||
//console.log('filterData() filter:'+filter);
|
||||
switch(name){
|
||||
case 'agency':
|
||||
return data.filter((item, index) => {
|
||||
return (
|
||||
(item.agency_id!==null && item.agency_id.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
item.agency_name.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
item.agency_url.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
item.agency_timezone.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
(item.agency_lang!==null && item.agency_lang.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.agency_phone!==null && item.agency_phone.toLowerCase().includes(filter.toLowerCase()))
|
||||
);
|
||||
});
|
||||
break;
|
||||
case 'frequencies':
|
||||
return data.filter((item, index) => {
|
||||
return (
|
||||
item.trip_id.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
item.start_time.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
item.end_time.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
item.headway_secs.toString().includes(filter) ||
|
||||
(item.exact_times!==null && item.exact_times.toString().includes(filter))
|
||||
);
|
||||
});
|
||||
break;
|
||||
case 'routes':
|
||||
return data.filter((item, index) => {
|
||||
return (
|
||||
item.route_id.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
(item.agency_id!==null && item.agency_id.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.route_short_name!==null && item.route_short_name.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.route_long_name!==null && item.route_long_name.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
item.route_type.toString().includes(filter.toLowerCase()) ||
|
||||
(item.route_color!==null && item.route_color.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.route_text_color!==null && item.route_text_color.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.route_desc!==null &&item.route_desc.toLowerCase().includes(filter.toLowerCase()))
|
||||
);
|
||||
});
|
||||
break;
|
||||
case 'shapes':
|
||||
return data.filter((item, index) => {
|
||||
return (
|
||||
item.shape_id.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
item.shape_pt_lat.toString().includes(filter) ||
|
||||
item.shape_pt_lon.toString().includes(filter) ||
|
||||
item.shape_pt_sequence.toString().includes(filter)
|
||||
);
|
||||
});
|
||||
break;
|
||||
case 'stops':
|
||||
return data.filter((item, index) => {
|
||||
return (
|
||||
item.stop_id.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
(item.stop_code!==null && item.stop_code.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.stop_name!==null && item.stop_name.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.stop_desc!==null && item.stop_descr.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.stop_lat!==null && item.stop_lat.toString().includes(filter)) ||
|
||||
(item.stop_lon!==null && item.stop_lon.toString().includes(filter)) ||
|
||||
(item.location_type!==null && item.location_type.toString().includes(filter)) ||
|
||||
(item.parent_station!==null && item.parent_station.toString().includes(filter)) ||
|
||||
(item.wheelchair_boarding!==null && item.wheelchair_boarding.toString().includes(filter)) ||
|
||||
(item.platform_code!==null && item.platform_code.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.zone_id!==null && item.zone_id.toLowerCase().includes(filter.toLowerCase()))
|
||||
);
|
||||
});
|
||||
break;
|
||||
case 'trips':
|
||||
return data.filter((item, index) => {
|
||||
return (
|
||||
item.route_id.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
item.service_id.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
item.trip_id.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
(item.trip_headsign!==null && item.trip_headsign.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.trip_short_name!==null && item.trip_short_name.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.direction_id!==null && item.direction_id.toString().includes(filter)) ||
|
||||
(item.block_id!==null && item.block_id.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.shape_id!==null && item.shape_id.toLowerCase().includes(filter.toLowerCase())) ||
|
||||
(item.wheelchair_accessible!==null && item.wheelchair_accessible.toString().includes(filter)) ||
|
||||
(item.bikes_allowed!==null && item.bikes_allowed.toString().includes(filter))
|
||||
);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
return data;
|
||||
}
|
||||
}else{
|
||||
return data;
|
||||
}
|
||||
};
|
||||
module.exports = {
|
||||
filterData
|
||||
};
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "gtfs-display",
|
||||
"version": "0.1.0",
|
||||
"version": "0.3.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gtfs-display",
|
||||
"version": "0.1.0",
|
||||
"version": "0.3.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"axios": "0.27.2",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"private": true,
|
||||
"name": "gtfs-display",
|
||||
"description": "display data from GTFS files",
|
||||
"version": "0.1.1",
|
||||
"version": "0.3.0",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
"public",
|
||||
|
|
Loading…
Reference in New Issue