chore: lint
This commit is contained in:
parent
f3be1cd91d
commit
787f525e0f
8
.babelrc
8
.babelrc
|
@ -2,5 +2,13 @@
|
|||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"@babel/plugin-transform-runtime",
|
||||
{
|
||||
"regenerator": true
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"parser": "@babel/eslint-parser",
|
||||
"extends": ["airbnb"],
|
||||
"rules": {
|
||||
"no-tabs": 0,
|
||||
"no-mixed-spaces-and-tabs": 0
|
||||
|
||||
}
|
||||
}
|
|
@ -1,61 +1,50 @@
|
|||
//generate a HTML5 file including all webpack bundles in the body using script tags
|
||||
// generate a HTML5 file including all webpack bundles in the body using script tags
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
//path is used to resolve properly across the OS
|
||||
// path is used to resolve properly across the OS
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
//bundle *.js from this entry point
|
||||
entry: path.resolve(__dirname, '../src/index.jsx'),
|
||||
//create output file to be linked to index.html
|
||||
output: {
|
||||
filename: '[name].bundle.js',
|
||||
path: path.resolve(__dirname, '../dist'),
|
||||
clean: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
// bundle *.js from this entry point
|
||||
entry: path.resolve(__dirname, '../src/index.jsx'),
|
||||
// create output file to be linked to index.html
|
||||
output: {
|
||||
filename: '[name].bundle.js',
|
||||
path: path.resolve(__dirname, '../dist'),
|
||||
clean: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
//test all *.js using babel-loader
|
||||
//test all *.jsx (e.g. React.js) using babel-loader
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
include: path.resolve(__dirname, '../src'),
|
||||
use: ['babel-loader'],
|
||||
},
|
||||
{
|
||||
//test all *.css using style-loader and css-loader
|
||||
test: /\.css$/i,
|
||||
use: ["style-loader", "css-loader"],
|
||||
},
|
||||
{
|
||||
//test all *.svg using svg-loader
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'svg-url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
},
|
||||
// test all *.js using babel-loader
|
||||
// test all *.jsx (e.g. React.js) using babel-loader
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
include: path.resolve(__dirname, '../src'),
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
},
|
||||
],
|
||||
// test all *.css using style-loader and css-loader
|
||||
test: /\.css$/i,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['*', '.js', '.jsx'],
|
||||
},
|
||||
plugins: [
|
||||
// create a plugin instance so that you can use it several times anywhere
|
||||
new HtmlWebpackPlugin({
|
||||
title: 'Production',
|
||||
template: path.resolve(__dirname, "../public/index.html")
|
||||
}),
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['*', '.js', '.jsx'],
|
||||
},
|
||||
plugins: [
|
||||
// create a plugin instance so that you can use it several times anywhere
|
||||
new HtmlWebpackPlugin({
|
||||
title: 'Production',
|
||||
template: path.resolve(__dirname, '../public/index.html'),
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
//path is used to resolve properly across the OS
|
||||
// path is used to resolve properly across the OS
|
||||
const path = require('path');
|
||||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
//merge() calls in the environment-specific configuration to include commons
|
||||
const common = require('./webpack.common');
|
||||
// merge() calls in the environment-specific configuration to include commons
|
||||
module.exports = merge(common, {
|
||||
//set development mode
|
||||
mode: 'development',
|
||||
//enable strong source mapping
|
||||
devtool: 'inline-source-map',
|
||||
devServer: {
|
||||
static: path.resolve(__dirname, '../dist'),
|
||||
//When using the HTML5 History API, the index.html page will likely have to be served in place of any 404 responses. Enable devServer.historyApiFallback by setting it to true.
|
||||
historyApiFallback: true,
|
||||
},
|
||||
// set development mode
|
||||
mode: 'development',
|
||||
// enable strong source mapping
|
||||
devtool: 'inline-source-map',
|
||||
devServer: {
|
||||
static: path.resolve(__dirname, '../dist'),
|
||||
/*
|
||||
When using the HTML5 History API,
|
||||
the index.html page will likely have to be served in place of any 404 responses.
|
||||
Enable devServer.historyApiFallback by setting it to true.
|
||||
*/
|
||||
historyApiFallback: true,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const common = require('./webpack.common');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
//source maps encouraged in production
|
||||
//choose mapping with fairly quick build speed like source-map
|
||||
devtool: 'source-map',
|
||||
mode: 'production',
|
||||
// source maps encouraged in production
|
||||
// choose mapping with fairly quick build speed like source-map
|
||||
devtool: 'source-map',
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load Diff
32
package.json
32
package.json
|
@ -14,29 +14,35 @@
|
|||
"author": "Software Ingenieur Begerad <dialog@SwIngBe.de>",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"engines": {
|
||||
"node": ">=18.19.0"
|
||||
"node": ">=18.17.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "webpack serve --config config/webpack.dev.js",
|
||||
"build": "webpack --config config/webpack.prod.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint --fix ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.22.10",
|
||||
"@babel/preset-env": "7.22.10",
|
||||
"@babel/preset-react": "7.22.5",
|
||||
"@babel/core": "7.23.9",
|
||||
"@babel/eslint-parser": "7.23.10",
|
||||
"@babel/plugin-transform-runtime": "7.23.9",
|
||||
"@babel/preset-env": "7.23.9",
|
||||
"@babel/preset-react": "7.23.3",
|
||||
"@babel/runtime": "7.23.9",
|
||||
"babel-loader": "9.1.3",
|
||||
"css-loader": "6.8.1",
|
||||
"file-loader": "6.2.0",
|
||||
"html-webpack-plugin": "5.5.3",
|
||||
"style-loader": "3.3.2",
|
||||
"svg-url-loader": "8.0.0",
|
||||
"webpack": "5.88.2",
|
||||
"css-loader": "6.10.0",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-airbnb": "19.0.4",
|
||||
"eslint-webpack-plugin": "4.0.1",
|
||||
"style-loader": "3.3.4",
|
||||
"webpack": "5.90.2",
|
||||
"webpack-cli": "5.1.4",
|
||||
"webpack-dev-server": "4.15.1",
|
||||
"webpack-merge": "5.9.0"
|
||||
"webpack-dev-server": "5.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"webpack-merge": "5.10.0",
|
||||
"html-webpack-plugin": "5.6.0",
|
||||
"axios": "1.3.6",
|
||||
"prop-types": "15.8.1",
|
||||
"react": "18.2.0",
|
||||
|
|
|
@ -1,37 +1,35 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
const AgencyTableEntry = ({
|
||||
agencyId,
|
||||
agencyName,
|
||||
tripCalendar
|
||||
}) => {
|
||||
if(tripCalendar!==undefined && Object.keys(tripCalendar).length>0){
|
||||
return (
|
||||
<tr>
|
||||
<td>{agencyId}</td>
|
||||
<td>{agencyName}</td>
|
||||
{
|
||||
Object.values(tripCalendar).map((value,index)=>{
|
||||
return (
|
||||
<th key={index}>{value}</th>
|
||||
);
|
||||
})
|
||||
|
||||
function AgencyTableEntry({
|
||||
agencyId,
|
||||
agencyName,
|
||||
tripCalendar,
|
||||
}) {
|
||||
if (tripCalendar !== undefined && Object.keys(tripCalendar).length > 0) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{agencyId}</td>
|
||||
<td>{agencyName}</td>
|
||||
{
|
||||
Object.values(tripCalendar).map((value, index) => (
|
||||
<th key={index}>{value}</th>
|
||||
))
|
||||
}
|
||||
</tr>
|
||||
);
|
||||
}else{
|
||||
//console.log('AgencyTableEntry waiting for prop');
|
||||
return (
|
||||
<tr>
|
||||
<th>Table Body loading...</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
};
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
// console.log('AgencyTableEntry waiting for prop');
|
||||
return (
|
||||
<tr>
|
||||
<th>Table Body loading...</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
AgencyTableEntry.propTypes = {
|
||||
agencyId: PropTypes.string,
|
||||
agencyName: PropTypes.string,
|
||||
tripCalendar: PropTypes.object
|
||||
agencyId: PropTypes.string,
|
||||
agencyName: PropTypes.string,
|
||||
tripCalendar: PropTypes.object,
|
||||
|
||||
};
|
||||
export default AgencyTableEntry;
|
||||
|
|
|
@ -1,40 +1,37 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function AgencyTableHead({tripCalendar}) {
|
||||
const handleTs=(ts)=>{
|
||||
//console.log(`AgencyTableHead ts: ${ts}`);
|
||||
const date=new Date(parseInt(ts,10));
|
||||
//console.log(`AgencyTableHead date: ${date}`);
|
||||
//return date.toString();
|
||||
//return date.toISOString().split('T')[0]
|
||||
return date.toLocaleDateString();
|
||||
};
|
||||
if(tripCalendar!==undefined && Object.keys(tripCalendar).length>0){
|
||||
//console.log('AgencyTableHead tripCalendar.length: '+Object.keys(tripCalendar).length);
|
||||
return (
|
||||
<tr>
|
||||
<th>agency_id</th>
|
||||
<th>agency_name</th>
|
||||
{
|
||||
Object.keys(tripCalendar).map((key,index)=>{
|
||||
return (
|
||||
<th key={index}>{handleTs(key)}</th>
|
||||
);
|
||||
})
|
||||
export default function AgencyTableHead({ tripCalendar }) {
|
||||
const handleTs = (ts) => {
|
||||
// console.log(`AgencyTableHead ts: ${ts}`);
|
||||
const date = new Date(parseInt(ts, 10));
|
||||
// console.log(`AgencyTableHead date: ${date}`);
|
||||
// return date.toString();
|
||||
// return date.toISOString().split('T')[0]
|
||||
return date.toLocaleDateString();
|
||||
};
|
||||
if (tripCalendar !== undefined && Object.keys(tripCalendar).length > 0) {
|
||||
// console.log('AgencyTableHead tripCalendar.length: '+Object.keys(tripCalendar).length);
|
||||
return (
|
||||
<tr>
|
||||
<th>agency_id</th>
|
||||
<th>agency_name</th>
|
||||
{
|
||||
Object.keys(tripCalendar).map((key, index) => (
|
||||
<th key={index}>{handleTs(key)}</th>
|
||||
))
|
||||
}
|
||||
</tr>
|
||||
);
|
||||
}else{
|
||||
//console.log('AgencyTableHead waiting for prop');
|
||||
return (
|
||||
<tr>
|
||||
<th>Table Head loading...</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
};
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
// console.log('AgencyTableHead waiting for prop');
|
||||
return (
|
||||
<tr>
|
||||
<th>Table Head loading...</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
AgencyTableHead.propTypes = {
|
||||
tripCalendar: PropTypes.object
|
||||
tripCalendar: PropTypes.object,
|
||||
};
|
||||
|
|
|
@ -1,32 +1,53 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function AgencyPerDayTableEntries ({array}) {
|
||||
if ( array !== undefined && array !== null && array.length > 0 ) {
|
||||
//TODO Shall we switch from UTC to local time zone for item.timestamp_pgsql?
|
||||
//iterate over array
|
||||
return array.map((item, index) => {
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
>
|
||||
<td>{item.agency_name} |</td>
|
||||
<td>{item.agency_id} |</td>
|
||||
<td>{item.route_id} |</td>
|
||||
<td>{item.route_short_name} |</td>
|
||||
<td>{item.trip_id} |</td>
|
||||
<td>{item.rt_part} |</td>
|
||||
<td>{item.trip_id === 0 ? 0 : ((item.rt_part / item.trip_id) * 100).toFixed(2)} |</td>
|
||||
<td>{item.timestamp_pgsql} |</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
}else{
|
||||
//data is empty
|
||||
return null;
|
||||
}
|
||||
};
|
||||
export default function AgencyPerDayTableEntries({ array }) {
|
||||
if (array !== undefined && array !== null && array.length > 0) {
|
||||
// TODO Shall we switch from UTC to local time zone for item.timestamp_pgsql?
|
||||
// iterate over array
|
||||
return array.map((item, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
>
|
||||
<td>
|
||||
{item.agency_name}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.agency_id}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.route_id}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.route_short_name}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.trip_id}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.rt_part}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.trip_id === 0 ? 0 : ((item.rt_part / item.trip_id) * 100).toFixed(2)}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.timestamp_pgsql}
|
||||
|
|
||||
</td>
|
||||
</tr>
|
||||
));
|
||||
}
|
||||
// data is empty
|
||||
return null;
|
||||
}
|
||||
|
||||
AgencyPerDayTableEntries.propTypes = {
|
||||
array: PropTypes.array
|
||||
array: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -3,43 +3,47 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import AgencyPerDayTableEntries from './agency-per-day-table-entries';
|
||||
|
||||
/*destructure props object*/
|
||||
export default function AgencyPerDayTable ({array, title, date}){
|
||||
|
||||
if ( array !== undefined && array !== null) {
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<p>Table of {array.length} {title} for {date}:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>agency_name |</th>
|
||||
<th>agency_id |</th>
|
||||
<th>route_id |</th>
|
||||
<th>route_short_name |</th>
|
||||
<th>abs. trip count |</th>
|
||||
<th>RT TU count |</th>
|
||||
<th>RT TU % |</th>
|
||||
<th>latest RT timestamp |</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<AgencyPerDayTableEntries array={array} />
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return (
|
||||
<>
|
||||
<p>loading...</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
/* destructure props object */
|
||||
export default function AgencyPerDayTable({ array, title, date }) {
|
||||
if (array !== undefined && array !== null) {
|
||||
/* return a React element */
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Table of
|
||||
{array.length}
|
||||
{title}
|
||||
{' '}
|
||||
for
|
||||
{date}
|
||||
:
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>agency_name |</th>
|
||||
<th>agency_id |</th>
|
||||
<th>route_id |</th>
|
||||
<th>route_short_name |</th>
|
||||
<th>abs. trip count |</th>
|
||||
<th>RT TU count |</th>
|
||||
<th>RT TU % |</th>
|
||||
<th>latest RT timestamp |</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<AgencyPerDayTableEntries array={array} />
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<p>loading...</p>
|
||||
);
|
||||
}
|
||||
AgencyPerDayTable.propTypes = {
|
||||
array: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
date: PropTypes.string
|
||||
array: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
date: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -2,33 +2,35 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import Dropdown from 'react-bootstrap/Dropdown';
|
||||
|
||||
export default function AgencySelect({ name, onChange, placeholder, rry, title }) {
|
||||
|
||||
if (rry.length > 0) {
|
||||
return (<>
|
||||
<Dropdown>
|
||||
<Dropdown.Toggle id="dropdown-basic">{placeholder}
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu>
|
||||
{rry.map((item) => (
|
||||
<Dropdown.Item
|
||||
eventKey={item.agency_id}
|
||||
key={item.agency_id}>
|
||||
{item.agency_name}
|
||||
</Dropdown.Item>
|
||||
export default function AgencySelect({
|
||||
name, onChange, placeholder, rry, title,
|
||||
}) {
|
||||
if (rry.length > 0) {
|
||||
return (
|
||||
<Dropdown>
|
||||
<Dropdown.Toggle id="dropdown-basic">
|
||||
{placeholder}
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu>
|
||||
{rry.map((item) => (
|
||||
<Dropdown.Item
|
||||
eventKey={item.agency_id}
|
||||
key={item.agency_id}
|
||||
>
|
||||
{item.agency_name}
|
||||
</Dropdown.Item>
|
||||
))}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
</>);
|
||||
} else {
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
};
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
|
||||
AgencySelect.propTypes = {
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
rry: PropTypes.array
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
rry: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -2,38 +2,38 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import Form from 'react-bootstrap/Form';
|
||||
|
||||
export default function AgencySelect({ name, onChange, placeholder, rry, title }) {
|
||||
|
||||
if (rry.length > 0) {
|
||||
return (<>
|
||||
<Form.Select
|
||||
aria-label="select table entries per page"
|
||||
name={name}
|
||||
id={name}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={placeholder}
|
||||
defaultValue={placeholder}
|
||||
title={title}
|
||||
type="text"
|
||||
required
|
||||
export default function AgencySelect({
|
||||
name, onChange, placeholder, rry, title,
|
||||
}) {
|
||||
if (rry.length > 0) {
|
||||
return (
|
||||
<Form.Select
|
||||
aria-label="select table entries per page"
|
||||
name={name}
|
||||
id={name}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={placeholder}
|
||||
defaultValue={placeholder}
|
||||
title={title}
|
||||
type="text"
|
||||
required
|
||||
>
|
||||
{rry.map((item) => (
|
||||
<option key={item.agency_id} value={item.agency_id}>
|
||||
{item.agency_name}
|
||||
</option>
|
||||
))}
|
||||
</Form.Select>
|
||||
</>);
|
||||
} else {
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
};
|
||||
{rry.map((item) => (
|
||||
<option key={item.agency_id} value={item.agency_id}>
|
||||
{item.agency_name}
|
||||
</option>
|
||||
))}
|
||||
</Form.Select>
|
||||
);
|
||||
}
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
|
||||
AgencySelect.propTypes = {
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
rry: PropTypes.array
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
rry: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -2,33 +2,35 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import Dropdown from 'react-bootstrap/Dropdown';
|
||||
|
||||
export default function AgencySelect({ name, onChange, placeholder, rry, title }) {
|
||||
|
||||
if (rry.length > 0) {
|
||||
return (<>
|
||||
<Dropdown>
|
||||
<Dropdown.Toggle id="dropdown-basic">{placeholder}
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu>
|
||||
{rry.map((item) => (
|
||||
<Dropdown.Item
|
||||
eventKey={item.agency_id}
|
||||
key={item.agency_id}>
|
||||
{item.agency_name}
|
||||
</Dropdown.Item>
|
||||
export default function AgencySelect({
|
||||
name, onChange, placeholder, rry, title,
|
||||
}) {
|
||||
if (rry.length > 0) {
|
||||
return (
|
||||
<Dropdown>
|
||||
<Dropdown.Toggle id="dropdown-basic">
|
||||
{placeholder}
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu>
|
||||
{rry.map((item) => (
|
||||
<Dropdown.Item
|
||||
eventKey={item.agency_id}
|
||||
key={item.agency_id}
|
||||
>
|
||||
{item.agency_name}
|
||||
</Dropdown.Item>
|
||||
))}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
</>);
|
||||
} else {
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
};
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
|
||||
AgencySelect.propTypes = {
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
rry: PropTypes.array
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
rry: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -5,35 +5,39 @@ import PropTypes from 'prop-types';
|
|||
* @param rry Array of agency objects containing id and name
|
||||
*/
|
||||
export default function AgencySelect({ name, onChange, rry }) {
|
||||
|
||||
if (rry !== undefined && rry !== null && rry.length > 0) {
|
||||
return <form >
|
||||
<label htmlFor="input-agency">{name}: </label>
|
||||
<select
|
||||
name={name}
|
||||
id={name}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={name}
|
||||
defaultValue={name}
|
||||
title={name}
|
||||
type="text"
|
||||
required
|
||||
>
|
||||
{rry.map((item) => (
|
||||
<option key={item.agency_id} value={item.agency_id}>
|
||||
{item.agency_name}
|
||||
</option>
|
||||
if (rry !== undefined && rry !== null && rry.length > 0) {
|
||||
return (
|
||||
<form>
|
||||
<label htmlFor="input-agency">
|
||||
{name}
|
||||
:
|
||||
{' '}
|
||||
</label>
|
||||
<select
|
||||
name={name}
|
||||
id={name}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={name}
|
||||
defaultValue={name}
|
||||
title={name}
|
||||
type="text"
|
||||
required
|
||||
>
|
||||
{rry.map((item) => (
|
||||
<option key={item.agency_id} value={item.agency_id}>
|
||||
{item.agency_name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</form>;
|
||||
} else {
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
};
|
||||
</select>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
|
||||
AgencySelect.propTypes = {
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
rry: PropTypes.array
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
rry: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
const AgencyTableEntry = ({
|
||||
agencyId,
|
||||
agencyName,
|
||||
agencyUrl,
|
||||
agencyTimezone,
|
||||
agencyLang,
|
||||
agencyPhone
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{agencyId}</td>
|
||||
<td>{agencyName}</td>
|
||||
<td>{agencyUrl}</td>
|
||||
<td>{agencyTimezone}</td>
|
||||
<td>{agencyLang}</td>
|
||||
<td>{agencyPhone}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
function AgencyTableEntry({
|
||||
agencyId,
|
||||
agencyName,
|
||||
agencyUrl,
|
||||
agencyTimezone,
|
||||
agencyLang,
|
||||
agencyPhone,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{agencyId}</td>
|
||||
<td>{agencyName}</td>
|
||||
<td>{agencyUrl}</td>
|
||||
<td>{agencyTimezone}</td>
|
||||
<td>{agencyLang}</td>
|
||||
<td>{agencyPhone}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
AgencyTableEntry.propTypes = {
|
||||
agencyId: PropTypes.string,
|
||||
agencyName: PropTypes.string,
|
||||
agencyUrl: PropTypes.string,
|
||||
agencyTimezone: PropTypes.string,
|
||||
agencyLang: PropTypes.string,
|
||||
agencyPhone: PropTypes.string
|
||||
agencyId: PropTypes.string,
|
||||
agencyName: PropTypes.string,
|
||||
agencyUrl: PropTypes.string,
|
||||
agencyTimezone: PropTypes.string,
|
||||
agencyLang: PropTypes.string,
|
||||
agencyPhone: PropTypes.string,
|
||||
};
|
||||
export default AgencyTableEntry;
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import React from 'react';
|
||||
const AgencyTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>agency_id</th>
|
||||
<th>agency_name</th>
|
||||
<th>agency_url</th>
|
||||
<th>agency_timezone</th>
|
||||
<th>agency_lang</th>
|
||||
<th>agency_phone</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
function AgencyTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>agency_id</th>
|
||||
<th>agency_name</th>
|
||||
<th>agency_url</th>
|
||||
<th>agency_timezone</th>
|
||||
<th>agency_lang</th>
|
||||
<th>agency_phone</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
export default AgencyTableHead;
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*destructure props object*/
|
||||
const CalendarDatesTableEntry = ({ serviceId, date, exceptionType }) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{serviceId}</td>
|
||||
<td>{date}</td>
|
||||
<td>{exceptionType}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function CalendarDatesTableEntry({ serviceId, date, exceptionType }) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{serviceId}</td>
|
||||
<td>{date}</td>
|
||||
<td>{exceptionType}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
CalendarDatesTableEntry.propTypes = {
|
||||
serviceId: PropTypes.string,
|
||||
date: PropTypes.string,
|
||||
exceptionType: PropTypes.number
|
||||
serviceId: PropTypes.string,
|
||||
date: PropTypes.string,
|
||||
exceptionType: PropTypes.number,
|
||||
};
|
||||
|
||||
export default CalendarDatesTableEntry;
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import React from 'react';
|
||||
|
||||
const CalendarDatesTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>service_id</th>
|
||||
<th>date</th>
|
||||
<th>exception_type</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function CalendarDatesTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>service_id</th>
|
||||
<th>date</th>
|
||||
<th>exception_type</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default CalendarDatesTableHead;
|
||||
|
|
|
@ -1,46 +1,46 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*destructure props object*/
|
||||
const CalendarTableEntry = ({
|
||||
serviceId,
|
||||
monday,
|
||||
tuesday,
|
||||
wednesday,
|
||||
thursday,
|
||||
friday,
|
||||
saturday,
|
||||
sunday,
|
||||
startDate,
|
||||
endDate
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{serviceId}</td>
|
||||
<td>{monday ? 'true' : 'false'}</td>
|
||||
<td>{tuesday ? 'true' : 'false'}</td>
|
||||
<td>{wednesday ? 'true' : 'false'}</td>
|
||||
<td>{thursday ? 'true' : 'false'}</td>
|
||||
<td>{friday ? 'true' : 'false'}</td>
|
||||
<td>{saturday ? 'true' : 'false'}</td>
|
||||
<td>{sunday ? 'true' : 'false'}</td>
|
||||
<td>{startDate}</td>
|
||||
<td>{endDate}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function CalendarTableEntry({
|
||||
serviceId,
|
||||
monday,
|
||||
tuesday,
|
||||
wednesday,
|
||||
thursday,
|
||||
friday,
|
||||
saturday,
|
||||
sunday,
|
||||
startDate,
|
||||
endDate,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{serviceId}</td>
|
||||
<td>{monday ? 'true' : 'false'}</td>
|
||||
<td>{tuesday ? 'true' : 'false'}</td>
|
||||
<td>{wednesday ? 'true' : 'false'}</td>
|
||||
<td>{thursday ? 'true' : 'false'}</td>
|
||||
<td>{friday ? 'true' : 'false'}</td>
|
||||
<td>{saturday ? 'true' : 'false'}</td>
|
||||
<td>{sunday ? 'true' : 'false'}</td>
|
||||
<td>{startDate}</td>
|
||||
<td>{endDate}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
CalendarTableEntry.propTypes = {
|
||||
serviceId: PropTypes.string,
|
||||
monday: PropTypes.number,
|
||||
tuesday: PropTypes.number,
|
||||
wednesday: PropTypes.number,
|
||||
thursday: PropTypes.number,
|
||||
friday: PropTypes.number,
|
||||
saturday: PropTypes.number,
|
||||
sunday: PropTypes.number,
|
||||
startDate: PropTypes.string,
|
||||
endDate: PropTypes.string
|
||||
serviceId: PropTypes.string,
|
||||
monday: PropTypes.number,
|
||||
tuesday: PropTypes.number,
|
||||
wednesday: PropTypes.number,
|
||||
thursday: PropTypes.number,
|
||||
friday: PropTypes.number,
|
||||
saturday: PropTypes.number,
|
||||
sunday: PropTypes.number,
|
||||
startDate: PropTypes.string,
|
||||
endDate: PropTypes.string,
|
||||
};
|
||||
|
||||
export default CalendarTableEntry;
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import React from 'react';
|
||||
|
||||
const CalendarTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>service_id</th>
|
||||
<th>monday</th>
|
||||
<th>tuesday</th>
|
||||
<th>wednesday</th>
|
||||
<th>thursday</th>
|
||||
<th>friday</th>
|
||||
<th>saturday</th>
|
||||
<th>sunday</th>
|
||||
<th>start_date</th>
|
||||
<th>end_date</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function CalendarTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>service_id</th>
|
||||
<th>monday</th>
|
||||
<th>tuesday</th>
|
||||
<th>wednesday</th>
|
||||
<th>thursday</th>
|
||||
<th>friday</th>
|
||||
<th>saturday</th>
|
||||
<th>sunday</th>
|
||||
<th>start_date</th>
|
||||
<th>end_date</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default CalendarTableHead;
|
||||
|
|
|
@ -1,79 +1,78 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
} from 'chart.js';
|
||||
import { Bar } from 'react-chartjs-2';
|
||||
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
);
|
||||
/* destructure props*/
|
||||
const ChartBarVertical = ({ route, time, trip }) => {
|
||||
const data = {
|
||||
labels: time,
|
||||
datasets: [
|
||||
{
|
||||
label: `trip count of route ${route}`,
|
||||
data: trip,
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.5)',
|
||||
borderColor: 'rgba(255, 99, 132, 0.2)'
|
||||
}
|
||||
]
|
||||
};
|
||||
const options = {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'top'
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: `trip count of route ${route}`
|
||||
}
|
||||
/* destructure props */
|
||||
function ChartBarVertical({ route, time, trip }) {
|
||||
const data = {
|
||||
labels: time,
|
||||
datasets: [
|
||||
{
|
||||
label: `trip count of route ${route}`,
|
||||
data: trip,
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.5)',
|
||||
borderColor: 'rgba(255, 99, 132, 0.2)',
|
||||
},
|
||||
],
|
||||
};
|
||||
const options = {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'top',
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: `trip count of route ${route}`,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
ticks: {
|
||||
max: 300,
|
||||
min: 0,
|
||||
stepSize: 10,
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
ticks: {
|
||||
max: 300,
|
||||
min: 0,
|
||||
stepSize: 10
|
||||
},
|
||||
scaleLabel: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="ChartBar">
|
||||
<div
|
||||
style={{
|
||||
height: '300px',
|
||||
width: '900px'
|
||||
}}
|
||||
>
|
||||
<Bar data={data} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
scaleLabel: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
return (
|
||||
<div className="ChartBar">
|
||||
<div
|
||||
style={{
|
||||
height: '300px',
|
||||
width: '900px',
|
||||
}}
|
||||
>
|
||||
<Bar data={data} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
ChartBarVertical.propTypes = {
|
||||
time: PropTypes.array,
|
||||
trip: PropTypes.array,
|
||||
route: PropTypes.string
|
||||
time: PropTypes.array,
|
||||
trip: PropTypes.array,
|
||||
route: PropTypes.string,
|
||||
};
|
||||
export default ChartBarVertical;
|
||||
|
|
|
@ -1,82 +1,81 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
PointElement
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
PointElement,
|
||||
} from 'chart.js';
|
||||
import { Line } from 'react-chartjs-2';
|
||||
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
PointElement
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
PointElement,
|
||||
);
|
||||
/* destructure props*/
|
||||
const ChartLine = ({ route, time, trip }) => {
|
||||
const data = {
|
||||
labels: time,
|
||||
datasets: [
|
||||
{
|
||||
label: `trip count of route ${route}`,
|
||||
data: trip,
|
||||
fill: false,
|
||||
backgroundColor: 'rgb(255, 99, 132)',
|
||||
borderColor: 'rgba(255, 99, 132, 0.2)'
|
||||
}
|
||||
]
|
||||
};
|
||||
const options = {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'top'
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: `trip count of route ${route}`
|
||||
}
|
||||
/* destructure props */
|
||||
function ChartLine({ route, time, trip }) {
|
||||
const data = {
|
||||
labels: time,
|
||||
datasets: [
|
||||
{
|
||||
label: `trip count of route ${route}`,
|
||||
data: trip,
|
||||
fill: false,
|
||||
backgroundColor: 'rgb(255, 99, 132)',
|
||||
borderColor: 'rgba(255, 99, 132, 0.2)',
|
||||
},
|
||||
],
|
||||
};
|
||||
const options = {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'top',
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: `trip count of route ${route}`,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
ticks: {
|
||||
max: 300,
|
||||
min: 0,
|
||||
stepSize: 10,
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
ticks: {
|
||||
max: 300,
|
||||
min: 0,
|
||||
stepSize: 10
|
||||
},
|
||||
scaleLabel: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="ChartLine">
|
||||
<div
|
||||
style={{
|
||||
height: '300px',
|
||||
width: '900px'
|
||||
}}
|
||||
>
|
||||
<Line data={data} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
scaleLabel: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
return (
|
||||
<div className="ChartLine">
|
||||
<div
|
||||
style={{
|
||||
height: '300px',
|
||||
width: '900px',
|
||||
}}
|
||||
>
|
||||
<Line data={data} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
ChartLine.propTypes = {
|
||||
time: PropTypes.array,
|
||||
trip: PropTypes.array,
|
||||
route: PropTypes.string
|
||||
time: PropTypes.array,
|
||||
trip: PropTypes.array,
|
||||
route: PropTypes.string,
|
||||
};
|
||||
export default ChartLine;
|
||||
|
|
|
@ -1,36 +1,43 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function FileSelect({ options, name, onChange, title }) {
|
||||
if (options.length > 0) {
|
||||
return <form >
|
||||
<label htmlFor="input-agency">{name}: </label>
|
||||
<select
|
||||
name={name}
|
||||
id={name}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={name}
|
||||
defaultValue={name}
|
||||
title={name}
|
||||
type="text"
|
||||
required
|
||||
>
|
||||
{options.map((item, index) => (
|
||||
<option key={index} value={item}>
|
||||
{item}
|
||||
</option>
|
||||
export default function FileSelect({
|
||||
options, name, onChange, title,
|
||||
}) {
|
||||
if (options.length > 0) {
|
||||
return (
|
||||
<form>
|
||||
<label htmlFor="input-agency">
|
||||
{name}
|
||||
:
|
||||
{' '}
|
||||
</label>
|
||||
<select
|
||||
name={name}
|
||||
id={name}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={name}
|
||||
defaultValue={name}
|
||||
title={name}
|
||||
type="text"
|
||||
required
|
||||
>
|
||||
{options.map((item, index) => (
|
||||
<option key={index} value={item}>
|
||||
{item}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</form>;
|
||||
} else {
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
};
|
||||
</select>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
|
||||
FileSelect.propTypes = {
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
options: PropTypes.array
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
options: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import FileSelect from '../components/file-select';
|
||||
import TablePage from '../components/table-page';
|
||||
import FileSelect from './file-select';
|
||||
import TablePage from './table-page';
|
||||
import gtfs from '../utils/gtfs';
|
||||
|
||||
export default function FileSelection({ options }) {
|
||||
|
||||
/*store and initialize data in function component state*/
|
||||
const [fileName, setFileName] = useState(gtfs.datasetFiles[0]);
|
||||
const handleChangeFile = (event) => {
|
||||
setFileName((fileName) => event.target.value);
|
||||
};
|
||||
if (options.length > 0) {
|
||||
return <>
|
||||
<FileSelect
|
||||
name="file"
|
||||
onChange={handleChangeFile}
|
||||
options={options}
|
||||
title='Select GTFS dataset file'
|
||||
/>
|
||||
<TablePage name={fileName} />
|
||||
</>;
|
||||
} else {
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
};
|
||||
/* store and initialize data in function component state */
|
||||
const [fileName, setFileName] = useState(gtfs.datasetFiles[0]);
|
||||
const handleChangeFile = (event) => {
|
||||
setFileName((fileName) => event.target.value);
|
||||
};
|
||||
if (options.length > 0) {
|
||||
return (
|
||||
<>
|
||||
<FileSelect
|
||||
name="file"
|
||||
onChange={handleChangeFile}
|
||||
options={options}
|
||||
title="Select GTFS dataset file"
|
||||
/>
|
||||
<TablePage name={fileName} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
|
||||
FileSelection.propTypes = {
|
||||
options: PropTypes.array
|
||||
options: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -1,30 +1,34 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*controlled component: input form value controlled by React*/
|
||||
const FormValue = (props) => {
|
||||
/*destructuring*/
|
||||
const { value, valueName, onChange, onSubmit } = props;
|
||||
/* controlled component: input form value controlled by React */
|
||||
function FormValue(props) {
|
||||
/* destructuring */
|
||||
const {
|
||||
value, valueName, onChange, onSubmit,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
/*one onChange handler for each value*/
|
||||
/*input names should match state names*/
|
||||
<>
|
||||
<form onSubmit={onSubmit}>
|
||||
<label>
|
||||
<p>Please enter {valueName}:</p>
|
||||
<input type="text" name="value" value={value} onChange={onChange} />
|
||||
</label>
|
||||
<input type="submit" value="Submit" />
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
return (
|
||||
/* one onChange handler for each value */
|
||||
/* input names should match state names */
|
||||
<form onSubmit={onSubmit}>
|
||||
<label>
|
||||
<p>
|
||||
Please enter
|
||||
{valueName}
|
||||
:
|
||||
</p>
|
||||
<input type="text" name="value" value={value} onChange={onChange} />
|
||||
</label>
|
||||
<input type="submit" value="Submit" />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
export default FormValue;
|
||||
|
||||
FormValue.propTypes = {
|
||||
value: PropTypes.string,
|
||||
valueName: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
onSubmit: PropTypes.func
|
||||
value: PropTypes.string,
|
||||
valueName: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
onSubmit: PropTypes.func,
|
||||
};
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*destructure props object*/
|
||||
const FrequenciesTableEntry = ({
|
||||
tripId,
|
||||
startTime,
|
||||
endTime,
|
||||
headwaySecs,
|
||||
exactTimes
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{tripId}</td>
|
||||
<td>{startTime}</td>
|
||||
<td>{endTime}</td>
|
||||
<td>{headwaySecs}</td>
|
||||
<td>{exactTimes}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function FrequenciesTableEntry({
|
||||
tripId,
|
||||
startTime,
|
||||
endTime,
|
||||
headwaySecs,
|
||||
exactTimes,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{tripId}</td>
|
||||
<td>{startTime}</td>
|
||||
<td>{endTime}</td>
|
||||
<td>{headwaySecs}</td>
|
||||
<td>{exactTimes}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
FrequenciesTableEntry.propTypes = {
|
||||
tripId: PropTypes.string,
|
||||
startTime: PropTypes.string,
|
||||
endTime: PropTypes.string,
|
||||
headwaySecs: PropTypes.number,
|
||||
exactTimes: PropTypes.number
|
||||
tripId: PropTypes.string,
|
||||
startTime: PropTypes.string,
|
||||
endTime: PropTypes.string,
|
||||
headwaySecs: PropTypes.number,
|
||||
exactTimes: PropTypes.number,
|
||||
};
|
||||
|
||||
export default FrequenciesTableEntry;
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import React from 'react';
|
||||
|
||||
const FrequenciesTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>trip_id</th>
|
||||
<th>start_time</th>
|
||||
<th>end_time</th>
|
||||
<th>headway_secs</th>
|
||||
<th>exact_times</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function FrequenciesTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>trip_id</th>
|
||||
<th>start_time</th>
|
||||
<th>end_time</th>
|
||||
<th>headway_secs</th>
|
||||
<th>exact_times</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default FrequenciesTableHead;
|
||||
|
|
|
@ -1,29 +1,41 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function GroupAgencyPerDayTableEntries ({array}) {
|
||||
if ( array !== undefined && array !== null && array.length > 0 ) {
|
||||
//TODO Shall we switch from UTC to local time zone for item.timestamp_pgsql?
|
||||
//iterate over array
|
||||
return array.map((item, index) => {
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
>
|
||||
<td>{item.agency_name} |</td>
|
||||
<td>{item.agency_id} |</td>
|
||||
<td>{item.rt_part} |</td>
|
||||
<td>{item.agency_id === 0 ? 0 : ((item.rt_part / item.agency_id) * 100).toFixed(2)} |</td>
|
||||
<td>{item.timestamp_pgsql} |</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
}else{
|
||||
//data is empty
|
||||
return null;
|
||||
}
|
||||
};
|
||||
export default function GroupAgencyPerDayTableEntries({ array }) {
|
||||
if (array !== undefined && array !== null && array.length > 0) {
|
||||
// TODO Shall we switch from UTC to local time zone for item.timestamp_pgsql?
|
||||
// iterate over array
|
||||
return array.map((item, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
>
|
||||
<td>
|
||||
{item.agency_name}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.agency_id}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.rt_part}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.agency_id === 0 ? 0 : ((item.rt_part / item.agency_id) * 100).toFixed(2)}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.timestamp_pgsql}
|
||||
|
|
||||
</td>
|
||||
</tr>
|
||||
));
|
||||
}
|
||||
// data is empty
|
||||
return null;
|
||||
}
|
||||
|
||||
GroupAgencyPerDayTableEntries.propTypes = {
|
||||
array: PropTypes.array
|
||||
array: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -3,42 +3,46 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import GroupAgencyPerDayTableEntries from './group-agency-per-day-table-entries';
|
||||
|
||||
//TODO For the cnnct feed, why do we get a 93 length agency array instead of 123?
|
||||
// TODO For the cnnct feed, why do we get a 93 length agency array instead of 123?
|
||||
|
||||
/*destructure props object*/
|
||||
export default function GroupAgencyPerDayTable ({array, title, date}){
|
||||
|
||||
if ( array !== undefined && array !== null) {
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<p>Table of {array.length} {title} for {date}:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>agency_name |</th>
|
||||
<th>abs. trip count |</th>
|
||||
<th>RT TU count |</th>
|
||||
<th>RT TU % |</th>
|
||||
<th>latest RT timestamp |</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<GroupAgencyPerDayTableEntries array={array} />
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return (
|
||||
<>
|
||||
<p>loading...</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
/* destructure props object */
|
||||
export default function GroupAgencyPerDayTable({ array, title, date }) {
|
||||
if (array !== undefined && array !== null) {
|
||||
/* return a React element */
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Table of
|
||||
{array.length}
|
||||
{title}
|
||||
{' '}
|
||||
for
|
||||
{date}
|
||||
:
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>agency_name |</th>
|
||||
<th>abs. trip count |</th>
|
||||
<th>RT TU count |</th>
|
||||
<th>RT TU % |</th>
|
||||
<th>latest RT timestamp |</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<GroupAgencyPerDayTableEntries array={array} />
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<p>loading...</p>
|
||||
);
|
||||
}
|
||||
GroupAgencyPerDayTable.propTypes = {
|
||||
array: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
date: PropTypes.string,
|
||||
array: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
date: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -4,42 +4,46 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import config from '../config';
|
||||
|
||||
//destructure props
|
||||
// destructure props
|
||||
export default function GtfsFile({ name }) {
|
||||
/*store count as array in function component state*/
|
||||
/*initialise as empty array*/
|
||||
const [count, setCount] = useState(null);
|
||||
/* store count as array in function component state */
|
||||
/* initialise as empty array */
|
||||
const [count, setCount] = useState(null);
|
||||
|
||||
/*fetch count in a JavaScript function*/
|
||||
const getCount = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const address = `${config.API}table-${name}-count`;
|
||||
const count = await axios.get(address);
|
||||
/* fetch count in a JavaScript function */
|
||||
const getCount = async () => {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const address = `${config.API}table-${name}-count`;
|
||||
const count = await axios.get(address);
|
||||
|
||||
/*set state*/
|
||||
setCount(count.data[0]['count']);
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
/* set state */
|
||||
setCount(count.data[0].count);
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state migh result in an infinite loop*/
|
||||
useEffect(() => {
|
||||
/*effect goes here*/
|
||||
/* 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*/
|
||||
getCount();
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
getCount();
|
||||
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, []);
|
||||
/* 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 <li key={name}>
|
||||
{name}: {count ? count : 'loading...'}
|
||||
</li>;
|
||||
};
|
||||
return (
|
||||
<li key={name}>
|
||||
{name}
|
||||
:
|
||||
{count || 'loading...'}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
GtfsFile.propTypes = {
|
||||
name: PropTypes.string
|
||||
name: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -6,17 +6,21 @@ import GtfsFile from './gtfs-file';
|
|||
import gtfs from '../utils/gtfs';
|
||||
|
||||
export default function GtfsFiles() {
|
||||
//TODO Do we have to call an API for each and every dataset file?
|
||||
return <fieldset>
|
||||
<legend><b>GTFS Schedule</b> feed overview (file: item count)</legend>
|
||||
<ul>
|
||||
{gtfs.datasetFiles.map((item, index) => {
|
||||
return <GtfsFile key={index} name={item} />;
|
||||
})}
|
||||
</ul>
|
||||
</fieldset>;
|
||||
};
|
||||
// TODO Do we have to call an API for each and every dataset file?
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>
|
||||
<b>GTFS Schedule</b>
|
||||
{' '}
|
||||
feed overview (file: item count)
|
||||
</legend>
|
||||
<ul>
|
||||
{gtfs.datasetFiles.map((item, index) => <GtfsFile key={index} name={item} />)}
|
||||
</ul>
|
||||
</fieldset>
|
||||
);
|
||||
}
|
||||
|
||||
GtfsFiles.propTypes = {
|
||||
data: PropTypes.array
|
||||
data: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -1,31 +1,36 @@
|
|||
import React, { useState } from 'react';
|
||||
import Alert from 'react-bootstrap/Alert';
|
||||
import config from '../config';
|
||||
const GtfsValidatorReport = () => {
|
||||
const [show, setShow] = useState(true);
|
||||
if (show) {
|
||||
return (
|
||||
<>
|
||||
<Alert variant={'secondary'} onClose={() => setShow(false)} dismissible>
|
||||
A daily{' '}
|
||||
<Alert.Link href={config.GTFS_VALIDATOR_REPORT}>
|
||||
report
|
||||
</Alert.Link>{' '}
|
||||
about compliance of this GTFS feed with these{' '}
|
||||
<Alert.Link href="https://github.com/MobilityData/GTFS_Schedule_Best-Practices">
|
||||
Best Practices{' '}
|
||||
</Alert.Link>{' '}
|
||||
is generated using the{' '}
|
||||
<Alert.Link href="https://github.com/MobilityData/gtfs-validator">
|
||||
gtfs-validator{' '}
|
||||
</Alert.Link>
|
||||
.
|
||||
</Alert>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
function GtfsValidatorReport() {
|
||||
const [show, setShow] = useState(true);
|
||||
if (show) {
|
||||
return (
|
||||
<Alert variant="secondary" onClose={() => setShow(false)} dismissible>
|
||||
A daily
|
||||
{' '}
|
||||
<Alert.Link href={config.GTFS_VALIDATOR_REPORT}>
|
||||
report
|
||||
</Alert.Link>
|
||||
{' '}
|
||||
about compliance of this GTFS feed with these
|
||||
{' '}
|
||||
<Alert.Link href="https://github.com/MobilityData/GTFS_Schedule_Best-Practices">
|
||||
Best Practices
|
||||
{' '}
|
||||
</Alert.Link>
|
||||
{' '}
|
||||
is generated using the
|
||||
{' '}
|
||||
<Alert.Link href="https://github.com/MobilityData/gtfs-validator">
|
||||
gtfs-validator
|
||||
{' '}
|
||||
</Alert.Link>
|
||||
.
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default GtfsValidatorReport;
|
||||
|
|
|
@ -1,49 +1,60 @@
|
|||
import React from 'react'
|
||||
import React from 'react';
|
||||
|
||||
export default function Header(){
|
||||
return <>
|
||||
<a href='/' rel="noopener noreferrer">
|
||||
<button>
|
||||
Home
|
||||
</button>
|
||||
</a>
|
||||
<a href='/agency' rel="noopener noreferrer">
|
||||
<button>
|
||||
Agency
|
||||
</button>
|
||||
</a>
|
||||
<a href='/files' rel="noopener noreferrer">
|
||||
<button>
|
||||
Files
|
||||
</button>
|
||||
</a>
|
||||
<a href='/realtime' rel="noopener noreferrer">
|
||||
<button>
|
||||
Realtime
|
||||
</button>
|
||||
</a>
|
||||
<a href='/contact' rel="noopener noreferrer">
|
||||
<button>
|
||||
Contact
|
||||
</button>
|
||||
</a>
|
||||
<a href='https://www.swingbe.de/imprint/'
|
||||
target="_blank" rel="noopener noreferrer">
|
||||
<button>
|
||||
Imprint
|
||||
</button>
|
||||
</a>
|
||||
<a href='https://www.swingbe.de/privacy-policy/'
|
||||
target="_blank" rel="noopener noreferrer">
|
||||
<button>
|
||||
Privacy Policy
|
||||
</button>
|
||||
</a>
|
||||
<a href='https://git.wtf-eg.de/dancingCycle/gtfs-display'
|
||||
target="_blank" rel="noopener noreferrer">
|
||||
<button>
|
||||
Source
|
||||
</button>
|
||||
</a>
|
||||
</>;
|
||||
};
|
||||
export default function Header() {
|
||||
return (
|
||||
<>
|
||||
<a href="/" rel="noopener noreferrer">
|
||||
<button>
|
||||
Home
|
||||
</button>
|
||||
</a>
|
||||
<a href="/agency" rel="noopener noreferrer">
|
||||
<button>
|
||||
Agency
|
||||
</button>
|
||||
</a>
|
||||
<a href="/files" rel="noopener noreferrer">
|
||||
<button>
|
||||
Files
|
||||
</button>
|
||||
</a>
|
||||
<a href="/realtime" rel="noopener noreferrer">
|
||||
<button>
|
||||
Realtime
|
||||
</button>
|
||||
</a>
|
||||
<a href="/contact" rel="noopener noreferrer">
|
||||
<button>
|
||||
Contact
|
||||
</button>
|
||||
</a>
|
||||
<a
|
||||
href="https://www.swingbe.de/imprint/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<button>
|
||||
Imprint
|
||||
</button>
|
||||
</a>
|
||||
<a
|
||||
href="https://www.swingbe.de/privacy-policy/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<button>
|
||||
Privacy Policy
|
||||
</button>
|
||||
</a>
|
||||
<a
|
||||
href="https://git.wtf-eg.de/dancingCycle/gtfs-display"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<button>
|
||||
Source
|
||||
</button>
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,30 +1,38 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*controlled component: input form value controlled by React*/
|
||||
export default function Input({id, name, onChange, placeholder, title, type, value}) {
|
||||
return <form >
|
||||
<label htmlFor="input-agency">{name}: </label>
|
||||
<input
|
||||
name={name}
|
||||
id={id}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={placeholder}
|
||||
title={title}
|
||||
type={type}
|
||||
value={value}
|
||||
required
|
||||
/>
|
||||
</form>;
|
||||
};
|
||||
/* controlled component: input form value controlled by React */
|
||||
export default function Input({
|
||||
id, name, onChange, placeholder, title, type, value,
|
||||
}) {
|
||||
return (
|
||||
<form>
|
||||
<label htmlFor="input-agency">
|
||||
{name}
|
||||
:
|
||||
{' '}
|
||||
</label>
|
||||
<input
|
||||
name={name}
|
||||
id={id}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={placeholder}
|
||||
title={title}
|
||||
type={type}
|
||||
value={value}
|
||||
required
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
Input.propTypes = {
|
||||
id: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
onChange: PropTypes.func
|
||||
id: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
const LevelsTableEntry = ({ levelId, levelIndex }) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{levelId}</td>
|
||||
<td>{levelIndex}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
function LevelsTableEntry({ levelId, levelIndex }) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{levelId}</td>
|
||||
<td>{levelIndex}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
LevelsTableEntry.propTypes = {
|
||||
levelId: PropTypes.string,
|
||||
levelIndex: PropTypes.number
|
||||
levelId: PropTypes.string,
|
||||
levelIndex: PropTypes.number,
|
||||
};
|
||||
export default LevelsTableEntry;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react';
|
||||
import React from 'react';
|
||||
|
||||
const LevelsTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>level_id</th>
|
||||
<th>level_index</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function LevelsTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>level_id</th>
|
||||
<th>level_index</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default LevelsTableHead;
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*Accept a single property object argument*/
|
||||
function Loading (props) {
|
||||
if (props.loading) {
|
||||
/*return a React element*/
|
||||
return <p>Loading...</p>;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
/* the simplest way to define a component is to write a JavaScript function */
|
||||
/* Accept a single property object argument */
|
||||
function Loading(props) {
|
||||
if (props.loading) {
|
||||
/* return a React element */
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Loading.propTypes = {
|
||||
loading: PropTypes.bool
|
||||
loading: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default Loading;
|
||||
|
|
|
@ -2,36 +2,36 @@ import React from 'react';
|
|||
import { Navbar, Nav } from 'react-bootstrap';
|
||||
import { LinkContainer } from 'react-router-bootstrap';
|
||||
|
||||
function NavigationBar () {
|
||||
return (
|
||||
<Navbar collapseOnSelect fixed="top" bg="dark" expand="xxl" variant="dark">
|
||||
function NavigationBar() {
|
||||
return (
|
||||
<Navbar collapseOnSelect fixed="top" bg="dark" expand="xxl" variant="dark">
|
||||
//TODO make brand available through configuration
|
||||
<Navbar.Brand href="/">GTFS Display</Navbar.Brand>
|
||||
<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="/files">
|
||||
<Nav.Link>Files</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/realtime">
|
||||
<Nav.Link>Realtime</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/contact">
|
||||
<Nav.Link>Contact</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
</Navbar.Collapse>
|
||||
</Navbar>
|
||||
);
|
||||
<Navbar.Brand href="/">GTFS Display</Navbar.Brand>
|
||||
<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="/files">
|
||||
<Nav.Link>Files</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/realtime">
|
||||
<Nav.Link>Realtime</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/contact">
|
||||
<Nav.Link>Contact</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
</Navbar.Collapse>
|
||||
</Navbar>
|
||||
);
|
||||
}
|
||||
|
||||
export default NavigationBar;
|
||||
|
|
|
@ -2,49 +2,48 @@ import React, { useState, useEffect } from 'react';
|
|||
import axios from 'axios';
|
||||
|
||||
import config from '../config';
|
||||
import Input from '../components/input';
|
||||
import Input from './input';
|
||||
|
||||
export default function OddTrips() {
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
const [data, setData] = useState([]);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const itemsPerPage = 10; // Number of items to display per page
|
||||
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
const [data, setData] = useState([]);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const itemsPerPage = 10; // Number of items to display per page
|
||||
// TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1
|
||||
|| e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date) => e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
//TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1 ||
|
||||
e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date) => e.target.value);
|
||||
}
|
||||
};
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
/* use an empty dependency array to ensure the hook is running only once */
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, [date]);
|
||||
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [date]);
|
||||
|
||||
const fetchData = async () => {
|
||||
if ( date !== dateDefault) {
|
||||
try {
|
||||
const fetchData = async () => {
|
||||
if (date !== dateDefault) {
|
||||
try {
|
||||
const address = `${config.API}trip-updates-odd-routes?day=${date}`;
|
||||
//console.log('address: ' + address);
|
||||
// console.log('address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if ( res.data !== undefined && res.data !== null ) {
|
||||
//console.log('res.data.length: ' + res.data.length);
|
||||
setData((data) => res.data);
|
||||
if (res.data !== undefined && res.data !== null) {
|
||||
// console.log('res.data.length: ' + res.data.length);
|
||||
setData((data) => res.data);
|
||||
} else {
|
||||
console.error('ERROR: trip-updates with odd routes request FAILED');
|
||||
console.error('ERROR: trip-updates with odd routes request FAILED');
|
||||
}
|
||||
} catch (err) {
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const startIndex = (currentPage - 1) * itemsPerPage;
|
||||
const endIndex = startIndex + itemsPerPage;
|
||||
|
@ -64,28 +63,34 @@ export default function OddTrips() {
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<p>
|
||||
abs odd route count: {data.length}, total pages: {Math.ceil(data.length / itemsPerPage)}, current page: {currentPage}
|
||||
</p>
|
||||
<dl>
|
||||
{currentItems.map((item, index) => (
|
||||
<dt key={index}>{item.trip_route_id}</dt>
|
||||
<>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<p>
|
||||
abs odd route count:
|
||||
{' '}
|
||||
{data.length}
|
||||
, total pages:
|
||||
{Math.ceil(data.length / itemsPerPage)}
|
||||
, current page:
|
||||
{currentPage}
|
||||
</p>
|
||||
<dl>
|
||||
{currentItems.map((item, index) => (
|
||||
<dt key={index}>{item.trip_route_id}</dt>
|
||||
))}
|
||||
</dl>
|
||||
<button onClick={handlePreviousPage}>Previous</button>
|
||||
<button onClick={handleNextPage}>Next</button>
|
||||
</dl>
|
||||
<button onClick={handlePreviousPage}>Previous</button>
|
||||
<button onClick={handleNextPage}>Next</button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,49 +2,48 @@ import React, { useState, useEffect } from 'react';
|
|||
import axios from 'axios';
|
||||
|
||||
import config from '../config';
|
||||
import Input from '../components/input';
|
||||
import Input from './input';
|
||||
|
||||
export default function OddTrips() {
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
const [data, setData] = useState([]);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const itemsPerPage = 10; // Number of items to display per page
|
||||
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
const [data, setData] = useState([]);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const itemsPerPage = 10; // Number of items to display per page
|
||||
|
||||
//TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1 ||
|
||||
e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date) => e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [date]);
|
||||
|
||||
const fetchData = async () => {
|
||||
if ( date !== dateDefault) {
|
||||
try {
|
||||
const address = `${config.API}trip-updates-odd-trips?day=${date}`;
|
||||
//console.log('address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if ( res.data !== undefined && res.data !== null ) {
|
||||
//console.log('res.data.length: ' + res.data.length);
|
||||
setData((data) => res.data);
|
||||
} else {
|
||||
console.error('ERROR: trip-updates with odd trips request FAILED');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1
|
||||
|| e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date) => e.target.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
/* use an empty dependency array to ensure the hook is running only once */
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, [date]);
|
||||
|
||||
const fetchData = async () => {
|
||||
if (date !== dateDefault) {
|
||||
try {
|
||||
const address = `${config.API}trip-updates-odd-trips?day=${date}`;
|
||||
// console.log('address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if (res.data !== undefined && res.data !== null) {
|
||||
// console.log('res.data.length: ' + res.data.length);
|
||||
setData((data) => res.data);
|
||||
} else {
|
||||
console.error('ERROR: trip-updates with odd trips request FAILED');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const startIndex = (currentPage - 1) * itemsPerPage;
|
||||
const endIndex = startIndex + itemsPerPage;
|
||||
|
@ -64,23 +63,29 @@ export default function OddTrips() {
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<p>
|
||||
abs odd trip count: {data.length}, total pages: {Math.ceil(data.length / itemsPerPage)}, current page: {currentPage}
|
||||
</p>
|
||||
<>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<p>
|
||||
abs odd trip count:
|
||||
{' '}
|
||||
{data.length}
|
||||
, total pages:
|
||||
{Math.ceil(data.length / itemsPerPage)}
|
||||
, current page:
|
||||
{currentPage}
|
||||
</p>
|
||||
<dl>
|
||||
{currentItems.map((item, index) => (
|
||||
{currentItems.map((item, index) => (
|
||||
<dt key={index}>{item.trip_trip_id}</dt>
|
||||
))}
|
||||
</dl>
|
||||
|
@ -88,4 +93,4 @@ export default function OddTrips() {
|
|||
<button onClick={handleNextPage}>Next</button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,15 +2,14 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function CountNext({ count }) {
|
||||
if (count === '0'
|
||||
if (count === '0'
|
||||
|| count === null
|
||||
|| count === undefined) {
|
||||
return '0';
|
||||
} else {
|
||||
return count;
|
||||
}
|
||||
};
|
||||
return '0';
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
CountNext.propTypes = {
|
||||
count: PropTypes.string
|
||||
count: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -3,24 +3,26 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import Count from './overview-next-table-count';
|
||||
|
||||
/*destructure props object*/
|
||||
export default function OverviewNextTableEntry ({ agencyName, routeCount, stopCount, tripCount }) {
|
||||
const routeCountBadge = <Count count={routeCount} />;
|
||||
const stopCountBadge = <Count count={stopCount} />;
|
||||
const tripCountBadge = <Count count={tripCount} />;
|
||||
return (
|
||||
<tr>
|
||||
<td>{agencyName}</td>
|
||||
<td>{routeCountBadge}</td>
|
||||
<td>{stopCountBadge}</td>
|
||||
<td>{tripCountBadge}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
export default function OverviewNextTableEntry({
|
||||
agencyName, routeCount, stopCount, tripCount,
|
||||
}) {
|
||||
const routeCountBadge = <Count count={routeCount} />;
|
||||
const stopCountBadge = <Count count={stopCount} />;
|
||||
const tripCountBadge = <Count count={tripCount} />;
|
||||
return (
|
||||
<tr>
|
||||
<td>{agencyName}</td>
|
||||
<td>{routeCountBadge}</td>
|
||||
<td>{stopCountBadge}</td>
|
||||
<td>{tripCountBadge}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
OverviewNextTableEntry.propTypes = {
|
||||
agencyName: PropTypes.string,
|
||||
routeCount: PropTypes.string,
|
||||
stopCount: PropTypes.string,
|
||||
tripCount: PropTypes.string
|
||||
agencyName: PropTypes.string,
|
||||
routeCount: PropTypes.string,
|
||||
stopCount: PropTypes.string,
|
||||
tripCount: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function OverviewNextTableHead () {
|
||||
return (
|
||||
<tr>
|
||||
<th>Agency |</th>
|
||||
<th>Route Count |</th>
|
||||
<th>Stop Count |</th>
|
||||
<th>Trip Count |</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
export default function OverviewNextTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>Agency |</th>
|
||||
<th>Route Count |</th>
|
||||
<th>Stop Count |</th>
|
||||
<th>Trip Count |</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,44 +4,46 @@ import PropTypes from 'prop-types';
|
|||
import Entry from './overview-next-table-entry';
|
||||
import Head from './overview-next-table-head';
|
||||
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
export default function OverviewNextTable ({ overview }) {
|
||||
const handleOverview = () => {
|
||||
/* the simplest way to define a component is to write a JavaScript function */
|
||||
/* destructure props object */
|
||||
export default function OverviewNextTable({ overview }) {
|
||||
const handleOverview = () => {
|
||||
if (overview !== null && overview !== undefined && overview.length !== 0) {
|
||||
// iterate over array
|
||||
return overview.map((item, index) => (
|
||||
<Entry
|
||||
agencyName={item.agency_name}
|
||||
routeCount={item.rts_cnt}
|
||||
stopCount={item.stps_cnt}
|
||||
tripCount={item.trps_cnt}
|
||||
key={item.agency_id}
|
||||
/>
|
||||
));
|
||||
}
|
||||
console.error('overview NOT available');
|
||||
return null;
|
||||
};
|
||||
|
||||
if ( overview !== null && overview !== undefined && overview.length !== 0 ) {
|
||||
//iterate over array
|
||||
return overview.map((item, index) => {
|
||||
return (
|
||||
<Entry
|
||||
agencyName={item.agency_name}
|
||||
routeCount={item.rts_cnt}
|
||||
stopCount={item.stps_cnt}
|
||||
tripCount={item.trps_cnt}
|
||||
key={item.agency_id}
|
||||
/>
|
||||
);
|
||||
});
|
||||
} else {
|
||||
console.error('overview NOT available');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*return a React element*/
|
||||
return <fieldset>
|
||||
<legend><b>GTFS Schedule</b> agency overview</legend>
|
||||
{/*size="sm" cuts cell padding in half*/}
|
||||
{/*variant="dark" inverts colors*/}
|
||||
<table>
|
||||
<thead>
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{handleOverview()}</tbody>
|
||||
</table>
|
||||
</fieldset>;
|
||||
};
|
||||
/* return a React element */
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>
|
||||
<b>GTFS Schedule</b>
|
||||
{' '}
|
||||
agency overview
|
||||
</legend>
|
||||
{/* size="sm" cuts cell padding in half */}
|
||||
{/* variant="dark" inverts colors */}
|
||||
<table>
|
||||
<thead>
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{handleOverview()}</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
);
|
||||
}
|
||||
|
||||
OverviewNextTable.propTypes = {
|
||||
overview: PropTypes.array
|
||||
overview: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -2,16 +2,15 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import Badge from '../utils/badge';
|
||||
|
||||
const count = ({ count }) => {
|
||||
if (count === 0) {
|
||||
return <Badge msg={count} modifier={'danger'} />;
|
||||
} else {
|
||||
return count;
|
||||
}
|
||||
};
|
||||
function count({ count }) {
|
||||
if (count === 0) {
|
||||
return <Badge msg={count} modifier="danger" />;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
count.propTypes = {
|
||||
count: PropTypes.number
|
||||
count: PropTypes.number,
|
||||
};
|
||||
|
||||
export default count;
|
||||
|
|
|
@ -2,25 +2,27 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import Count from './overview-table-count.js';
|
||||
|
||||
/*destructure props object*/
|
||||
const OverviewTableEntry = ({ agencyName, routeCount, tripCount, day }) => {
|
||||
const routeCountBadge = <Count count={routeCount} />;
|
||||
const tripCountBadge = <Count count={tripCount} />;
|
||||
return (
|
||||
<tr>
|
||||
<td>{agencyName}</td>
|
||||
<td>{routeCount === null ? 'loading...' : routeCountBadge}</td>
|
||||
<td>{tripCount === null ? 'loading...' : tripCountBadge}</td>
|
||||
<td>{day === null ? 'loading...' : day}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function OverviewTableEntry({
|
||||
agencyName, routeCount, tripCount, day,
|
||||
}) {
|
||||
const routeCountBadge = <Count count={routeCount} />;
|
||||
const tripCountBadge = <Count count={tripCount} />;
|
||||
return (
|
||||
<tr>
|
||||
<td>{agencyName}</td>
|
||||
<td>{routeCount === null ? 'loading...' : routeCountBadge}</td>
|
||||
<td>{tripCount === null ? 'loading...' : tripCountBadge}</td>
|
||||
<td>{day === null ? 'loading...' : day}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
OverviewTableEntry.propTypes = {
|
||||
agencyName: PropTypes.string,
|
||||
routeCount: PropTypes.number,
|
||||
tripCount: PropTypes.number,
|
||||
day: PropTypes.object
|
||||
agencyName: PropTypes.string,
|
||||
routeCount: PropTypes.number,
|
||||
tripCount: PropTypes.number,
|
||||
day: PropTypes.object,
|
||||
};
|
||||
|
||||
export default OverviewTableEntry;
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from 'react';
|
||||
|
||||
const OverviewTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>Agency</th>
|
||||
<th>Route Count</th>
|
||||
<th>Trip Count</th>
|
||||
<th>{new Date().toDateString()}</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function OverviewTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>Agency</th>
|
||||
<th>Route Count</th>
|
||||
<th>Trip Count</th>
|
||||
<th>{new Date().toDateString()}</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default OverviewTableHead;
|
||||
|
|
|
@ -4,46 +4,43 @@ import Table from 'react-bootstrap/Table';
|
|||
import Entry from './overview-table-entry';
|
||||
import Head from './overview-table-head';
|
||||
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function OverviewTable ({ overview }) {
|
||||
const handleOverview = () => {
|
||||
if (overview) {
|
||||
//iterate over array
|
||||
return overview.map((item, index) => {
|
||||
return (
|
||||
<Entry
|
||||
agencyName={item.agency_name}
|
||||
routeCount={item.route_count}
|
||||
tripCount={item.trip_count}
|
||||
day={item.day}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
});
|
||||
} else {
|
||||
console.error('overview NOT available');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
/* the simplest way to define a component is to write a JavaScript function */
|
||||
/* destructure props object */
|
||||
function OverviewTable({ overview }) {
|
||||
const handleOverview = () => {
|
||||
if (overview) {
|
||||
// iterate over array
|
||||
return overview.map((item, index) => (
|
||||
<Entry
|
||||
agencyName={item.agency_name}
|
||||
routeCount={item.route_count}
|
||||
tripCount={item.trip_count}
|
||||
day={item.day}
|
||||
key={index}
|
||||
/>
|
||||
));
|
||||
}
|
||||
console.error('overview NOT available');
|
||||
return null;
|
||||
};
|
||||
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
{/*size="sm" cuts cell padding in half*/}
|
||||
{/*variant="dark" inverts colors*/}
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead>
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{handleOverview()}</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
/* return a React element */
|
||||
return (
|
||||
<>
|
||||
{/* size="sm" cuts cell padding in half */}
|
||||
{/* variant="dark" inverts colors */}
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead>
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{handleOverview()}</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
OverviewTable.propTypes = {
|
||||
overview: PropTypes.array
|
||||
overview: PropTypes.array,
|
||||
};
|
||||
|
||||
export default OverviewTable;
|
||||
|
|
|
@ -1,52 +1,52 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*destructure props object*/
|
||||
const PathwaysTableEntry = ({
|
||||
pathwayId,
|
||||
fromStopId,
|
||||
toStopId,
|
||||
pathwayMode,
|
||||
isBidirectional,
|
||||
length,
|
||||
traversalTime,
|
||||
stairCount,
|
||||
maxSlope,
|
||||
minWidth,
|
||||
signpostedAs,
|
||||
reversedSignpostedAs
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{pathwayId}</td>
|
||||
<td>{fromStopId}</td>
|
||||
<td>{toStopId}</td>
|
||||
<td>{pathwayMode}</td>
|
||||
<td>{isBidirectional}</td>
|
||||
<td>{length}</td>
|
||||
<td>{traversalTime}</td>
|
||||
<td>{stairCount}</td>
|
||||
<td>{maxSlope}</td>
|
||||
<td>{minWidth}</td>
|
||||
<td>{signpostedAs}</td>
|
||||
<td>{reversedSignpostedAs}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function PathwaysTableEntry({
|
||||
pathwayId,
|
||||
fromStopId,
|
||||
toStopId,
|
||||
pathwayMode,
|
||||
isBidirectional,
|
||||
length,
|
||||
traversalTime,
|
||||
stairCount,
|
||||
maxSlope,
|
||||
minWidth,
|
||||
signpostedAs,
|
||||
reversedSignpostedAs,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{pathwayId}</td>
|
||||
<td>{fromStopId}</td>
|
||||
<td>{toStopId}</td>
|
||||
<td>{pathwayMode}</td>
|
||||
<td>{isBidirectional}</td>
|
||||
<td>{length}</td>
|
||||
<td>{traversalTime}</td>
|
||||
<td>{stairCount}</td>
|
||||
<td>{maxSlope}</td>
|
||||
<td>{minWidth}</td>
|
||||
<td>{signpostedAs}</td>
|
||||
<td>{reversedSignpostedAs}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
PathwaysTableEntry.propTypes = {
|
||||
pathwayId: PropTypes.string,
|
||||
fromStopId: PropTypes.string,
|
||||
toStopId: PropTypes.string,
|
||||
pathwayMode: PropTypes.number,
|
||||
isBidirectional: PropTypes.number,
|
||||
length: PropTypes.number,
|
||||
traversalTime: PropTypes.number,
|
||||
stairCount: PropTypes.number,
|
||||
maxSlope: PropTypes.number,
|
||||
minWidth: PropTypes.number,
|
||||
signpostedAs: PropTypes.string,
|
||||
reversedSignpostedAs: PropTypes.string
|
||||
pathwayId: PropTypes.string,
|
||||
fromStopId: PropTypes.string,
|
||||
toStopId: PropTypes.string,
|
||||
pathwayMode: PropTypes.number,
|
||||
isBidirectional: PropTypes.number,
|
||||
length: PropTypes.number,
|
||||
traversalTime: PropTypes.number,
|
||||
stairCount: PropTypes.number,
|
||||
maxSlope: PropTypes.number,
|
||||
minWidth: PropTypes.number,
|
||||
signpostedAs: PropTypes.string,
|
||||
reversedSignpostedAs: PropTypes.string,
|
||||
};
|
||||
|
||||
export default PathwaysTableEntry;
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import React from 'react';
|
||||
|
||||
const PathwaysTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>pathway_id</th>
|
||||
<th>from_stop_id</th>
|
||||
<th>to_stop_id</th>
|
||||
<th>pathway_mode</th>
|
||||
<th>is_bidirectional</th>
|
||||
<th>length</th>
|
||||
<th>traversal_time</th>
|
||||
<th>stair_count</th>
|
||||
<th>max_slope</th>
|
||||
<th>min_width</th>
|
||||
<th>signposted_as</th>
|
||||
<th>reversed_signposted_as</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function PathwaysTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>pathway_id</th>
|
||||
<th>from_stop_id</th>
|
||||
<th>to_stop_id</th>
|
||||
<th>pathway_mode</th>
|
||||
<th>is_bidirectional</th>
|
||||
<th>length</th>
|
||||
<th>traversal_time</th>
|
||||
<th>stair_count</th>
|
||||
<th>max_slope</th>
|
||||
<th>min_width</th>
|
||||
<th>signposted_as</th>
|
||||
<th>reversed_signposted_as</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default PathwaysTableHead;
|
||||
|
|
|
@ -1,28 +1,37 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function PerDayTableEntries ({array}) {
|
||||
if ( array !== undefined && array !== null && array.length > 0 ) {
|
||||
//TODO Shall we switch from UTC to local time zone for item.timestamp_pgsql?
|
||||
//iterate over array
|
||||
return array.map((item, index) => {
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
>
|
||||
<td>{item.count} |</td>
|
||||
<td>{item.rt_part} |</td>
|
||||
<td>{item.count === 0 ? 0 : ((item.rt_part / item.count) * 100).toFixed(2)} |</td>
|
||||
<td>{item.timestamp_pgsql} |</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
}else{
|
||||
//data is empty
|
||||
return null;
|
||||
}
|
||||
};
|
||||
export default function PerDayTableEntries({ array }) {
|
||||
if (array !== undefined && array !== null && array.length > 0) {
|
||||
// TODO Shall we switch from UTC to local time zone for item.timestamp_pgsql?
|
||||
// iterate over array
|
||||
return array.map((item, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
>
|
||||
<td>
|
||||
{item.count}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.rt_part}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.count === 0 ? 0 : ((item.rt_part / item.count) * 100).toFixed(2)}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.timestamp_pgsql}
|
||||
|
|
||||
</td>
|
||||
</tr>
|
||||
));
|
||||
}
|
||||
// data is empty
|
||||
return null;
|
||||
}
|
||||
|
||||
PerDayTableEntries.propTypes = {
|
||||
array: PropTypes.array
|
||||
array: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -3,39 +3,43 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import PerDayTableEntries from './per-day-table-entries';
|
||||
|
||||
/*destructure props object*/
|
||||
export default function PerDayTable ({array, title, date}){
|
||||
|
||||
if ( array !== undefined && array !== null) {
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<p>Table of {array.length} {title} for {date}:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>abs. trip count |</th>
|
||||
<th>RT TU count |</th>
|
||||
<th>RT TU % |</th>
|
||||
<th>latest RT timestamp |</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<PerDayTableEntries array={array} />
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return (
|
||||
<>
|
||||
<p>loading...</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
/* destructure props object */
|
||||
export default function PerDayTable({ array, title, date }) {
|
||||
if (array !== undefined && array !== null) {
|
||||
/* return a React element */
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Table of
|
||||
{array.length}
|
||||
{title}
|
||||
{' '}
|
||||
for
|
||||
{date}
|
||||
:
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>abs. trip count |</th>
|
||||
<th>RT TU count |</th>
|
||||
<th>RT TU % |</th>
|
||||
<th>latest RT timestamp |</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<PerDayTableEntries array={array} />
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<p>loading...</p>
|
||||
);
|
||||
}
|
||||
PerDayTable.propTypes = {
|
||||
array: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
date: PropTypes.string
|
||||
array: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
date: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -2,83 +2,168 @@ import PropTypes from 'prop-types';
|
|||
import React, { useState } from 'react';
|
||||
|
||||
export default function RadioButton({ state, onChange }) {
|
||||
return (
|
||||
<div >
|
||||
return (
|
||||
<div>
|
||||
<form>
|
||||
<fieldset>
|
||||
<legend>Select <b>GTFS Realtime</b> analysis rule</legend>
|
||||
<input
|
||||
<legend>
|
||||
Select
|
||||
<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
analysis rule
|
||||
</legend>
|
||||
<input
|
||||
type="radio"
|
||||
name="state"
|
||||
id='state-odd-routes'
|
||||
id="state-odd-routes"
|
||||
value="odd-routes"
|
||||
onChange={onChange}
|
||||
checked={state === 'odd-routes'} />
|
||||
<label htmlFor="state-odd-routes">
|
||||
Show <b>GTFS Realtime</b> entities <b>TripUpdate</b> with <b>odd routes</b>
|
||||
</label><br />
|
||||
checked={state === 'odd-routes'}
|
||||
/>
|
||||
<label htmlFor="state-odd-routes">
|
||||
Show
|
||||
{' '}
|
||||
<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
entities
|
||||
{' '}
|
||||
<b>TripUpdate</b>
|
||||
{' '}
|
||||
with
|
||||
{' '}
|
||||
<b>odd routes</b>
|
||||
</label>
|
||||
<br />
|
||||
|
||||
<input
|
||||
<input
|
||||
type="radio"
|
||||
name="state"
|
||||
id='state-odd-trips'
|
||||
id="state-odd-trips"
|
||||
value="odd-trips"
|
||||
onChange={onChange}
|
||||
checked={state === 'odd-trips'} />
|
||||
<label htmlFor="state-odd-trips">
|
||||
Show <b>GTFS Realtime</b> entities <b>TripUpdate</b> with <b>odd trips</b>
|
||||
</label><br />
|
||||
checked={state === 'odd-trips'}
|
||||
/>
|
||||
<label htmlFor="state-odd-trips">
|
||||
Show
|
||||
{' '}
|
||||
<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
entities
|
||||
{' '}
|
||||
<b>TripUpdate</b>
|
||||
{' '}
|
||||
with
|
||||
{' '}
|
||||
<b>odd trips</b>
|
||||
</label>
|
||||
<br />
|
||||
|
||||
<input
|
||||
<input
|
||||
type="radio"
|
||||
name="state"
|
||||
id='state-feed'
|
||||
id="state-feed"
|
||||
value="feed"
|
||||
onChange={onChange}
|
||||
checked={state === 'feed'} />
|
||||
<label htmlFor="state-feed">
|
||||
Analyse <b>GTFS Realtime</b> entities <b>TripUpdate</b> on <b>feed</b> level
|
||||
</label><br />
|
||||
checked={state === 'feed'}
|
||||
/>
|
||||
<label htmlFor="state-feed">
|
||||
Analyse
|
||||
{' '}
|
||||
<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
entities
|
||||
{' '}
|
||||
<b>TripUpdate</b>
|
||||
{' '}
|
||||
on
|
||||
{' '}
|
||||
<b>feed</b>
|
||||
{' '}
|
||||
level
|
||||
</label>
|
||||
<br />
|
||||
|
||||
<input
|
||||
<input
|
||||
type="radio"
|
||||
name="state"
|
||||
id='state-agencies'
|
||||
id="state-agencies"
|
||||
value="agencies"
|
||||
onChange={onChange}
|
||||
checked={state === 'agencies'} />
|
||||
<label htmlFor="state-agencies">
|
||||
Analyse <b>GTFS Realtime</b> entities <b>TripUpdate</b> on <b>agencies</b> level
|
||||
</label><br />
|
||||
checked={state === 'agencies'}
|
||||
/>
|
||||
<label htmlFor="state-agencies">
|
||||
Analyse
|
||||
{' '}
|
||||
<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
entities
|
||||
{' '}
|
||||
<b>TripUpdate</b>
|
||||
{' '}
|
||||
on
|
||||
{' '}
|
||||
<b>agencies</b>
|
||||
{' '}
|
||||
level
|
||||
</label>
|
||||
<br />
|
||||
|
||||
<input
|
||||
<input
|
||||
type="radio"
|
||||
name="state"
|
||||
id='state-routes'
|
||||
id="state-routes"
|
||||
value="routes"
|
||||
onChange={onChange}
|
||||
checked={state === 'routes'} />
|
||||
<label htmlFor="state-routes">
|
||||
Analyse <b>GTFS Realtime</b> entities <b>TripUpdate</b> on <b>routes</b> level
|
||||
</label><br />
|
||||
checked={state === 'routes'}
|
||||
/>
|
||||
<label htmlFor="state-routes">
|
||||
Analyse
|
||||
{' '}
|
||||
<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
entities
|
||||
{' '}
|
||||
<b>TripUpdate</b>
|
||||
{' '}
|
||||
on
|
||||
{' '}
|
||||
<b>routes</b>
|
||||
{' '}
|
||||
level
|
||||
</label>
|
||||
<br />
|
||||
|
||||
<input
|
||||
<input
|
||||
type="radio"
|
||||
name="state"
|
||||
id='state-trips'
|
||||
id="state-trips"
|
||||
value="trips"
|
||||
onChange={onChange}
|
||||
checked={state === 'trips'} />
|
||||
<label htmlFor="state-trips">
|
||||
Analyse <b>GTFS Realtime</b> entities <b>TripUpdate</b> on <b>trips</b> level
|
||||
</label><br />
|
||||
checked={state === 'trips'}
|
||||
/>
|
||||
<label htmlFor="state-trips">
|
||||
Analyse
|
||||
{' '}
|
||||
<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
entities
|
||||
{' '}
|
||||
<b>TripUpdate</b>
|
||||
{' '}
|
||||
on
|
||||
{' '}
|
||||
<b>trips</b>
|
||||
{' '}
|
||||
level
|
||||
</label>
|
||||
<br />
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
RadioButton.propTypes = {
|
||||
state: PropTypes.string,
|
||||
onChange: PropTypes.func
|
||||
state: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
|
|
@ -9,67 +9,117 @@ import PerDay from '../pages/per-day';
|
|||
import TripUpdates from '../pages/trip-updates-route-day';
|
||||
|
||||
export default function Realtime({ state }) {
|
||||
if ( state === 'odd-routes' ) {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Show <b>GTFS Realtime TripUpdate</b> entities that do <b>not</b> match any <b>GTFS Schedule routes</b>:
|
||||
</p>
|
||||
<OddRoutes />
|
||||
</>
|
||||
);
|
||||
} else if ( state === 'odd-trips' ) {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Show <b>GTFS Realtime TripUpdate</b> entities that do <b>not</b> match any <b>GTFS Schedule trips</b>:
|
||||
</p>
|
||||
<OddTrips />
|
||||
</>
|
||||
);
|
||||
} else if ( state === 'feed' ) {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Analyse <b>GTFS Realtime</b> entities <b>TripUpdate</b> on <b>feed</b> level:
|
||||
</p>
|
||||
<PerDay />
|
||||
</>
|
||||
);
|
||||
}
|
||||
else if ( state === 'agencies' ) {
|
||||
if (state === 'odd-routes') {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Analyse <b>GTFS Realtime</b> entities <b>TripUpdate</b> on <b>agencies</b> level:
|
||||
</p>
|
||||
<GroupAgencyPerDay />
|
||||
</>
|
||||
<>
|
||||
<p>
|
||||
Show <b>GTFS Realtime TripUpdate</b>
|
||||
{' '}
|
||||
entities that do<b>not</b>
|
||||
{' '}
|
||||
match any<b>GTFS Schedule routes</b>
|
||||
:
|
||||
</p>
|
||||
<OddRoutes />
|
||||
</>
|
||||
);
|
||||
} else if ( state === 'routes' ) {
|
||||
} if (state === 'odd-trips') {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Analyse <b>GTFS Realtime</b> entities <b>TripUpdate</b> on <b>routes</b> level:
|
||||
</p>
|
||||
<AgencyPerDay />
|
||||
</>
|
||||
<>
|
||||
<p>
|
||||
Show <b>GTFS Realtime TripUpdate</b>
|
||||
{' '}
|
||||
entities that do<b>not</b>
|
||||
{' '}
|
||||
match any<b>GTFS Schedule trips</b>
|
||||
:
|
||||
</p>
|
||||
<OddTrips />
|
||||
</>
|
||||
);
|
||||
} else if ( state === 'trips' ) {
|
||||
} if (state === 'feed') {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Analyse <b>GTFS Realtime</b> entities <b>TripUpdate</b> on <b>trips</b> level:
|
||||
</p>
|
||||
<TripUpdates />
|
||||
</>
|
||||
<>
|
||||
<p>
|
||||
Analyse <b>GTFS Realtime</b>
|
||||
{' '}
|
||||
entities<b>TripUpdate</b>
|
||||
{' '}
|
||||
on<b>feed</b>
|
||||
{' '}
|
||||
level:
|
||||
</p>
|
||||
<PerDay />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return <p>Select a <b>GTFS Realtime</b> analysis rule to contine!</p>;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
if (state === 'agencies') {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Analyse
|
||||
{' '}
|
||||
<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
entities
|
||||
<b>TripUpdate</b>
|
||||
{' '}
|
||||
on
|
||||
<b>agencies</b>
|
||||
{' '}
|
||||
level:
|
||||
</p>
|
||||
<GroupAgencyPerDay />
|
||||
</>
|
||||
);
|
||||
} if (state === 'routes') {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Analyse
|
||||
{' '}
|
||||
<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
entities
|
||||
<b>TripUpdate</b>
|
||||
{' '}
|
||||
on
|
||||
<b>routes</b>
|
||||
{' '}
|
||||
level:
|
||||
</p>
|
||||
<AgencyPerDay />
|
||||
</>
|
||||
);
|
||||
} if (state === 'trips') {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Analyse
|
||||
{' '}
|
||||
<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
entities
|
||||
<b>TripUpdate</b>
|
||||
{' '}
|
||||
on
|
||||
<b>trips</b>
|
||||
{' '}
|
||||
level:
|
||||
</p>
|
||||
<TripUpdates />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<p>
|
||||
Select a<b>GTFS Realtime</b>
|
||||
{' '}
|
||||
analysis rule to contine!
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
Realtime.propTypes = {
|
||||
state: PropTypes.string
|
||||
state: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -5,37 +5,39 @@ import PropTypes from 'prop-types';
|
|||
* @param rry Array of route objects containing id and name
|
||||
*/
|
||||
export default function RouteSelect({ name, onChange, rry }) {
|
||||
|
||||
if (rry !== undefined && rry !== null) {
|
||||
return (<>
|
||||
<form >
|
||||
<label htmlFor="input-route">{name}: </label>
|
||||
<select
|
||||
name={name}
|
||||
id={name}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={name}
|
||||
defaultValue={name}
|
||||
title={name}
|
||||
type="text"
|
||||
required
|
||||
>
|
||||
{rry.map((item) => (
|
||||
<option key={item.route_id} value={item.route_id}>
|
||||
{item.route_short_name}
|
||||
</option>
|
||||
if (rry !== undefined && rry !== null) {
|
||||
return (
|
||||
<form>
|
||||
<label htmlFor="input-route">
|
||||
{name}
|
||||
:
|
||||
{' '}
|
||||
</label>
|
||||
<select
|
||||
name={name}
|
||||
id={name}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={name}
|
||||
defaultValue={name}
|
||||
title={name}
|
||||
type="text"
|
||||
required
|
||||
>
|
||||
{rry.map((item) => (
|
||||
<option key={item.route_id} value={item.route_id}>
|
||||
{item.route_short_name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</form>
|
||||
</>);
|
||||
} else {
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
};
|
||||
</select>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
|
||||
RouteSelect.propTypes = {
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
rry: PropTypes.array
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
rry: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*destructure props object*/
|
||||
const RoutesTableEntry = ({
|
||||
routeId,
|
||||
agencyId,
|
||||
routeShortName,
|
||||
routeLongName,
|
||||
routeType,
|
||||
routeColor,
|
||||
routeTextColor,
|
||||
routeDesc
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{routeId}</td>
|
||||
<td>{agencyId}</td>
|
||||
<td>{routeShortName}</td>
|
||||
<td>{routeLongName}</td>
|
||||
<td>{routeType}</td>
|
||||
<td>{routeColor}</td>
|
||||
<td>{routeTextColor}</td>
|
||||
<td>{routeDesc}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function RoutesTableEntry({
|
||||
routeId,
|
||||
agencyId,
|
||||
routeShortName,
|
||||
routeLongName,
|
||||
routeType,
|
||||
routeColor,
|
||||
routeTextColor,
|
||||
routeDesc,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{routeId}</td>
|
||||
<td>{agencyId}</td>
|
||||
<td>{routeShortName}</td>
|
||||
<td>{routeLongName}</td>
|
||||
<td>{routeType}</td>
|
||||
<td>{routeColor}</td>
|
||||
<td>{routeTextColor}</td>
|
||||
<td>{routeDesc}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
RoutesTableEntry.propTypes = {
|
||||
routeId: PropTypes.string,
|
||||
agencyId: PropTypes.string,
|
||||
routeShortName: PropTypes.string,
|
||||
routeLongName: PropTypes.string,
|
||||
routeType: PropTypes.number,
|
||||
routeColor: PropTypes.string,
|
||||
routeTextColor: PropTypes.string,
|
||||
routeDesc: PropTypes.string
|
||||
routeId: PropTypes.string,
|
||||
agencyId: PropTypes.string,
|
||||
routeShortName: PropTypes.string,
|
||||
routeLongName: PropTypes.string,
|
||||
routeType: PropTypes.number,
|
||||
routeColor: PropTypes.string,
|
||||
routeTextColor: PropTypes.string,
|
||||
routeDesc: PropTypes.string,
|
||||
};
|
||||
|
||||
export default RoutesTableEntry;
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import React from 'react';
|
||||
|
||||
const RoutesTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>route_id</th>
|
||||
<th>agency_id</th>
|
||||
<th>route_short_name</th>
|
||||
<th>route_long_name</th>
|
||||
<th>route_type</th>
|
||||
<th>route_color</th>
|
||||
<th>route_text_color</th>
|
||||
<th>route_desc</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function RoutesTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>route_id</th>
|
||||
<th>agency_id</th>
|
||||
<th>route_short_name</th>
|
||||
<th>route_long_name</th>
|
||||
<th>route_type</th>
|
||||
<th>route_color</th>
|
||||
<th>route_text_color</th>
|
||||
<th>route_desc</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default RoutesTableHead;
|
||||
|
|
|
@ -1,39 +1,46 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*controlled component: select controlled by React*/
|
||||
export default function Select({defaultValue, id, name, onChange, options, title}) {
|
||||
if (options) {
|
||||
return <form >
|
||||
<label htmlFor="input-agency">{name}: </label>
|
||||
<select
|
||||
name={name}
|
||||
id={id}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={name}
|
||||
defaultValue={defaultValue}
|
||||
title={title}
|
||||
type="text"
|
||||
required
|
||||
>
|
||||
{options.map((item, index) => (
|
||||
<option key={index} value={item}>
|
||||
{item}
|
||||
</option>
|
||||
/* controlled component: select controlled by React */
|
||||
export default function Select({
|
||||
defaultValue, id, name, onChange, options, title,
|
||||
}) {
|
||||
if (options) {
|
||||
return (
|
||||
<form>
|
||||
<label htmlFor="input-agency">
|
||||
{name}
|
||||
:
|
||||
{' '}
|
||||
</label>
|
||||
<select
|
||||
name={name}
|
||||
id={id}
|
||||
className={name}
|
||||
onChange={onChange}
|
||||
placeholder={name}
|
||||
defaultValue={defaultValue}
|
||||
title={title}
|
||||
type="text"
|
||||
required
|
||||
>
|
||||
{options.map((item, index) => (
|
||||
<option key={index} value={item}>
|
||||
{item}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</form>;
|
||||
} else {
|
||||
return <p>Select options unavailable.</p>;
|
||||
}
|
||||
};
|
||||
</select>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
return <p>Select options unavailable.</p>;
|
||||
}
|
||||
|
||||
Select.propTypes = {
|
||||
id: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
defaultValue: PropTypes.number,
|
||||
onChange: PropTypes.func,
|
||||
options: PropTypes.array,
|
||||
title: PropTypes.string
|
||||
id: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
defaultValue: PropTypes.number,
|
||||
onChange: PropTypes.func,
|
||||
options: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -2,19 +2,19 @@ import React, { Component } from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
class ServiceTableEntry extends Component {
|
||||
render () {
|
||||
return (
|
||||
<tr>
|
||||
<td>{this.props.date}</td>
|
||||
<td>{this.props.count}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<tr>
|
||||
<td>{this.props.date}</td>
|
||||
<td>{this.props.count}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ServiceTableEntry.propTypes = {
|
||||
date: PropTypes.string,
|
||||
count: PropTypes.number
|
||||
date: PropTypes.string,
|
||||
count: PropTypes.number,
|
||||
};
|
||||
|
||||
export default ServiceTableEntry;
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
class MsgsTableHead extends Component {
|
||||
render () {
|
||||
return (
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Trip Count</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Trip Count</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MsgsTableHead;
|
||||
|
|
|
@ -4,52 +4,50 @@ import Table from 'react-bootstrap/Table';
|
|||
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*/
|
||||
function ServiceTable ({service,render}) {
|
||||
/*map over msgs array and return Standortmeldungen*/
|
||||
const getService = () => {
|
||||
//iterate over object
|
||||
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];
|
||||
let count = Object.keys(objTrips).length;
|
||||
//console.log('count: ' + count);
|
||||
let time = parseInt(trips[0], 10);
|
||||
//console.log('time: ' + parseInt(time, 10));
|
||||
let date = new Date(time);
|
||||
//console.log('date: ' + date);
|
||||
return <Entry date={date.toDateString()} count={count} key={key} />;
|
||||
});
|
||||
} else {
|
||||
console.error('service NOT available');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
if (render) {
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
{/*size="sm" cuts cell padding in half*/}
|
||||
{/*variant="dark" inverts colors*/}
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead className="thead-dark">
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{getService()}</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
/* the simplest way to define a component is to write a JavaScript function */
|
||||
function ServiceTable({ service, render }) {
|
||||
/* map over msgs array and return Standortmeldungen */
|
||||
const getService = () => {
|
||||
// iterate over object
|
||||
if (service) {
|
||||
return Object.entries(service).map((trips, key) => {
|
||||
/* the strict equals operator does not converts operants of differnet type */
|
||||
// console.log('key: ' + key);
|
||||
const objTrips = trips[1];
|
||||
const count = Object.keys(objTrips).length;
|
||||
// console.log('count: ' + count);
|
||||
const time = parseInt(trips[0], 10);
|
||||
// console.log('time: ' + parseInt(time, 10));
|
||||
const date = new Date(time);
|
||||
// console.log('date: ' + date);
|
||||
return <Entry date={date.toDateString()} count={count} key={key} />;
|
||||
});
|
||||
}
|
||||
console.error('service NOT available');
|
||||
return null;
|
||||
};
|
||||
|
||||
if (render) {
|
||||
/* return a React element */
|
||||
return (
|
||||
<>
|
||||
{/* size="sm" cuts cell padding in half */}
|
||||
{/* variant="dark" inverts colors */}
|
||||
<Table striped bordered hover size="sm" variant="dark" responsive>
|
||||
<thead className="thead-dark">
|
||||
<Head />
|
||||
</thead>
|
||||
<tbody>{getService()}</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ServiceTable.propTypes = {
|
||||
service: PropTypes.object,
|
||||
render: PropTypes.bool
|
||||
service: PropTypes.object,
|
||||
render: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default ServiceTable;
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*destructure props object*/
|
||||
const ShapesTableEntry = ({
|
||||
shapeId,
|
||||
shapePtLat,
|
||||
shapePtLon,
|
||||
shapePtSequence
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{shapeId}</td>
|
||||
<td>{shapePtLat}</td>
|
||||
<td>{shapePtLon}</td>
|
||||
<td>{shapePtSequence}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function ShapesTableEntry({
|
||||
shapeId,
|
||||
shapePtLat,
|
||||
shapePtLon,
|
||||
shapePtSequence,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{shapeId}</td>
|
||||
<td>{shapePtLat}</td>
|
||||
<td>{shapePtLon}</td>
|
||||
<td>{shapePtSequence}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
ShapesTableEntry.propTypes = {
|
||||
shapeId: PropTypes.string,
|
||||
shapePtLat: PropTypes.number,
|
||||
shapePtLon: PropTypes.number,
|
||||
shapePtSequence: PropTypes.number
|
||||
shapeId: PropTypes.string,
|
||||
shapePtLat: PropTypes.number,
|
||||
shapePtLon: PropTypes.number,
|
||||
shapePtSequence: PropTypes.number,
|
||||
};
|
||||
|
||||
export default ShapesTableEntry;
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from 'react';
|
||||
|
||||
const ShapesTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>shape_id</th>
|
||||
<th>shape_pt_lat</th>
|
||||
<th>shape_pt_lon</th>
|
||||
<th>shape_pt_sequence</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function ShapesTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>shape_id</th>
|
||||
<th>shape_pt_lat</th>
|
||||
<th>shape_pt_lon</th>
|
||||
<th>shape_pt_sequence</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default ShapesTableHead;
|
||||
|
|
|
@ -1,46 +1,46 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*destructure props object*/
|
||||
const StopTimesTableEntry = ({
|
||||
tripId,
|
||||
arrivalTimeHours,
|
||||
arrivalTimeMinutes,
|
||||
departureTimeHours,
|
||||
departureTimeMinutes,
|
||||
stopId,
|
||||
stopSequence,
|
||||
pickupType,
|
||||
dropOffType,
|
||||
stopHeadsign
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{tripId}</td>
|
||||
<td>{arrivalTimeHours}</td>
|
||||
<td>{arrivalTimeMinutes}</td>
|
||||
<td>{departureTimeHours}</td>
|
||||
<td>{departureTimeMinutes}</td>
|
||||
<td>{stopId}</td>
|
||||
<td>{stopSequence}</td>
|
||||
<td>{pickupType}</td>
|
||||
<td>{dropOffType}</td>
|
||||
<td>{stopHeadsign}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function StopTimesTableEntry({
|
||||
tripId,
|
||||
arrivalTimeHours,
|
||||
arrivalTimeMinutes,
|
||||
departureTimeHours,
|
||||
departureTimeMinutes,
|
||||
stopId,
|
||||
stopSequence,
|
||||
pickupType,
|
||||
dropOffType,
|
||||
stopHeadsign,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{tripId}</td>
|
||||
<td>{arrivalTimeHours}</td>
|
||||
<td>{arrivalTimeMinutes}</td>
|
||||
<td>{departureTimeHours}</td>
|
||||
<td>{departureTimeMinutes}</td>
|
||||
<td>{stopId}</td>
|
||||
<td>{stopSequence}</td>
|
||||
<td>{pickupType}</td>
|
||||
<td>{dropOffType}</td>
|
||||
<td>{stopHeadsign}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
StopTimesTableEntry.propTypes = {
|
||||
tripId: PropTypes.string,
|
||||
arrivalTimeHours: PropTypes.number,
|
||||
arrivalTimeMinutes: PropTypes.number,
|
||||
departureTimeHours: PropTypes.number,
|
||||
departureTimeMinutes: PropTypes.number,
|
||||
stopId: PropTypes.string,
|
||||
stopSequence: PropTypes.number,
|
||||
pickupType: PropTypes.number,
|
||||
dropOffType: PropTypes.number,
|
||||
stopHeadsign: PropTypes.string
|
||||
tripId: PropTypes.string,
|
||||
arrivalTimeHours: PropTypes.number,
|
||||
arrivalTimeMinutes: PropTypes.number,
|
||||
departureTimeHours: PropTypes.number,
|
||||
departureTimeMinutes: PropTypes.number,
|
||||
stopId: PropTypes.string,
|
||||
stopSequence: PropTypes.number,
|
||||
pickupType: PropTypes.number,
|
||||
dropOffType: PropTypes.number,
|
||||
stopHeadsign: PropTypes.string,
|
||||
};
|
||||
|
||||
export default StopTimesTableEntry;
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import React from 'react';
|
||||
|
||||
const StopTimesTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>trip_id</th>
|
||||
<th>arrival_time_hours</th>
|
||||
<th>arrival_time_minutes</th>
|
||||
<th>departure_time_hours</th>
|
||||
<th>departure_time_minutes</th>
|
||||
<th>stop_id</th>
|
||||
<th>stop_sequence</th>
|
||||
<th>pickup_type</th>
|
||||
<th>drop_off_type</th>
|
||||
<th>stop_headsign</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function StopTimesTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>trip_id</th>
|
||||
<th>arrival_time_hours</th>
|
||||
<th>arrival_time_minutes</th>
|
||||
<th>departure_time_hours</th>
|
||||
<th>departure_time_minutes</th>
|
||||
<th>stop_id</th>
|
||||
<th>stop_sequence</th>
|
||||
<th>pickup_type</th>
|
||||
<th>drop_off_type</th>
|
||||
<th>stop_headsign</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default StopTimesTableHead;
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*destructure props object*/
|
||||
const StopsTableEntry = ({
|
||||
stopId,
|
||||
stopCode,
|
||||
stopName,
|
||||
stopDesc,
|
||||
stopLat,
|
||||
stopLon,
|
||||
locationType,
|
||||
parentStation,
|
||||
wheelchairBoarding,
|
||||
platformCode,
|
||||
zoneId
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{stopId}</td>
|
||||
<td>{stopCode}</td>
|
||||
<td>{stopName}</td>
|
||||
<td>{stopDesc}</td>
|
||||
<td>{stopLat}</td>
|
||||
<td>{stopLon}</td>
|
||||
<td>{locationType}</td>
|
||||
<td>{parentStation}</td>
|
||||
<td>{wheelchairBoarding}</td>
|
||||
<td>{platformCode}</td>
|
||||
<td>{zoneId}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function StopsTableEntry({
|
||||
stopId,
|
||||
stopCode,
|
||||
stopName,
|
||||
stopDesc,
|
||||
stopLat,
|
||||
stopLon,
|
||||
locationType,
|
||||
parentStation,
|
||||
wheelchairBoarding,
|
||||
platformCode,
|
||||
zoneId,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{stopId}</td>
|
||||
<td>{stopCode}</td>
|
||||
<td>{stopName}</td>
|
||||
<td>{stopDesc}</td>
|
||||
<td>{stopLat}</td>
|
||||
<td>{stopLon}</td>
|
||||
<td>{locationType}</td>
|
||||
<td>{parentStation}</td>
|
||||
<td>{wheelchairBoarding}</td>
|
||||
<td>{platformCode}</td>
|
||||
<td>{zoneId}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
StopsTableEntry.propTypes = {
|
||||
stopId: PropTypes.string,
|
||||
stopCode: PropTypes.string,
|
||||
stopName: PropTypes.string,
|
||||
stopDesc: PropTypes.string,
|
||||
stopLat: PropTypes.number,
|
||||
stopLon: PropTypes.number,
|
||||
locationType: PropTypes.number,
|
||||
parentStation: PropTypes.string,
|
||||
wheelchairBoarding: PropTypes.number,
|
||||
platformCode: PropTypes.string,
|
||||
zoneId: PropTypes.string
|
||||
stopId: PropTypes.string,
|
||||
stopCode: PropTypes.string,
|
||||
stopName: PropTypes.string,
|
||||
stopDesc: PropTypes.string,
|
||||
stopLat: PropTypes.number,
|
||||
stopLon: PropTypes.number,
|
||||
locationType: PropTypes.number,
|
||||
parentStation: PropTypes.string,
|
||||
wheelchairBoarding: PropTypes.number,
|
||||
platformCode: PropTypes.string,
|
||||
zoneId: PropTypes.string,
|
||||
};
|
||||
|
||||
export default StopsTableEntry;
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import React from 'react';
|
||||
|
||||
const StopsTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>stop_id</th>
|
||||
<th>stop_code</th>
|
||||
<th>stop_name</th>
|
||||
<th>stop_desc</th>
|
||||
<th>stop_lat</th>
|
||||
<th>stop_lon</th>
|
||||
<th>location_type</th>
|
||||
<th>parent_station</th>
|
||||
<th>wheelchair_boarding</th>
|
||||
<th>platform_code</th>
|
||||
<th>zone_id</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function StopsTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>stop_id</th>
|
||||
<th>stop_code</th>
|
||||
<th>stop_name</th>
|
||||
<th>stop_desc</th>
|
||||
<th>stop_lat</th>
|
||||
<th>stop_lon</th>
|
||||
<th>location_type</th>
|
||||
<th>parent_station</th>
|
||||
<th>wheelchair_boarding</th>
|
||||
<th>platform_code</th>
|
||||
<th>zone_id</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default StopsTableHead;
|
||||
|
|
|
@ -13,223 +13,222 @@ 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 'agency-id-name':
|
||||
return (
|
||||
<AgencyIdNameEntry
|
||||
agencyId={item.agency_id}
|
||||
agencyName={item.agency_name}
|
||||
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 'pathways':
|
||||
return (
|
||||
<PathwaysEntry
|
||||
pathwayId={item.pathway_id}
|
||||
fromStopId={item.from_stop_id}
|
||||
toStopId={item.to_stop_id}
|
||||
pathwayMode={item.pathway_mode}
|
||||
isBidirectional={item.is_bidirectional}
|
||||
length={item.length}
|
||||
traversalTime={item.traversal_time}
|
||||
stairCount={item.stair_count}
|
||||
maxSlope={item.max_slope}
|
||||
minWidth={item.min_width}
|
||||
signpostedAs={item.signposted_as}
|
||||
reversedSignpostedAs={item.reversed_signposted_as}
|
||||
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`);
|
||||
/* 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 'agency-id-name':
|
||||
return (
|
||||
<AgencyIdNameEntry
|
||||
agencyId={item.agency_id}
|
||||
agencyName={item.agency_name}
|
||||
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 'pathways':
|
||||
return (
|
||||
<PathwaysEntry
|
||||
pathwayId={item.pathway_id}
|
||||
fromStopId={item.from_stop_id}
|
||||
toStopId={item.to_stop_id}
|
||||
pathwayMode={item.pathway_mode}
|
||||
isBidirectional={item.is_bidirectional}
|
||||
length={item.length}
|
||||
traversalTime={item.traversal_time}
|
||||
stairCount={item.stair_count}
|
||||
maxSlope={item.max_slope}
|
||||
minWidth={item.min_width}
|
||||
signpostedAs={item.signposted_as}
|
||||
reversedSignpostedAs={item.reversed_signposted_as}
|
||||
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':
|
||||
const 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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
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{
|
||||
}
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
TableEntrySwitch.propTypes = {
|
||||
aryData: PropTypes.array,
|
||||
name: PropTypes.string
|
||||
aryData: PropTypes.array,
|
||||
name: PropTypes.string,
|
||||
};
|
||||
export default TableEntrySwitch;
|
||||
|
|
|
@ -13,55 +13,55 @@ 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 'agency-id-name':
|
||||
return <AgencyIdNameHead />;
|
||||
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`);
|
||||
/* 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 'agency-id-name':
|
||||
return <AgencyIdNameHead />;
|
||||
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
|
||||
name: PropTypes.string,
|
||||
};
|
||||
export default TableHeadSwitch;
|
||||
|
|
|
@ -6,54 +6,50 @@ import TableSwitchBody from './table-switch-trip-calendar-body';
|
|||
import config from '../config';
|
||||
|
||||
export default function TablePageBody({ agencyIdName }) {
|
||||
|
||||
if(agencyIdName !== undefined){
|
||||
//console.log('TablePageBody agencyIdName:'+JSON.stringify(agencyIdName));
|
||||
//console.log('TablePageBody agencyIdName.length:'+agencyIdName.length);
|
||||
const agencyId=agencyIdName.agency_id;
|
||||
//console.log('TablePageBody agencyId:'+agencyId);
|
||||
const agencyName=agencyIdName.agency_name;
|
||||
//console.log('TablePageBody agencyName:'+agencyName);
|
||||
/*store and initialise data in function component state*/
|
||||
if (agencyIdName !== undefined) {
|
||||
// console.log('TablePageBody agencyIdName:'+JSON.stringify(agencyIdName));
|
||||
// console.log('TablePageBody agencyIdName.length:'+agencyIdName.length);
|
||||
const agencyId = agencyIdName.agency_id;
|
||||
// console.log('TablePageBody agencyId:'+agencyId);
|
||||
const agencyName = agencyIdName.agency_name;
|
||||
// console.log('TablePageBody agencyName:'+agencyName);
|
||||
/* store and initialise data in function component state */
|
||||
const [tripCalendar, setTripCalendar] = useState({});
|
||||
|
||||
const getTripCalendar = async () => {
|
||||
try {
|
||||
/*get trip calendar*/
|
||||
const address=`${config.API}trip-calendar-by-agency-id?agencyid=${agencyId}`;
|
||||
//console.log('address:'+address);
|
||||
const getTripCalendar = async () => {
|
||||
try {
|
||||
/* get trip calendar */
|
||||
const address = `${config.API}trip-calendar-by-agency-id?agencyid=${agencyId}`;
|
||||
// console.log('address:'+address);
|
||||
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const res = await axios.get(address);
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const res = await axios.get(address);
|
||||
|
||||
let aryTripCalendar = res.data;
|
||||
//console.log('aryTripCalendar.length:'+aryTripCalendar.length);
|
||||
const aryTripCalendar = res.data;
|
||||
// console.log('aryTripCalendar.length:'+aryTripCalendar.length);
|
||||
setTripCalendar(aryTripCalendar);
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
};
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
useEffect(() => {
|
||||
getTripCalendar();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
getTripCalendar();
|
||||
/* 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 (
|
||||
<>
|
||||
<TableSwitchBody
|
||||
tripCalendar={tripCalendar}
|
||||
agencyId={agencyId}
|
||||
agencyName={agencyName}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return <p>Table Page Body loading...</p>
|
||||
}
|
||||
};
|
||||
return (
|
||||
<TableSwitchBody
|
||||
tripCalendar={tripCalendar}
|
||||
agencyId={agencyId}
|
||||
agencyName={agencyName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <p>Table Page Body loading...</p>;
|
||||
}
|
||||
|
||||
TablePageBody.propTypes = {
|
||||
agencyIdName: PropTypes.object
|
||||
agencyIdName: PropTypes.object,
|
||||
};
|
||||
|
|
|
@ -6,66 +6,57 @@ import TableSwitchHead from './table-switch-trip-calendar-head';
|
|||
import config from '../config';
|
||||
|
||||
export default function TablePageHead({ agencyIdName }) {
|
||||
if (agencyIdName !== undefined) {
|
||||
// console.log('TablePageHead agencyIdName:'+JSON.stringify(agencyIdName));
|
||||
// console.log('TablePageHead agencyIdName.length:'+agencyIdName.length);
|
||||
const agencyId = agencyIdName.agency_id;
|
||||
// console.log('TablePageHead agencyId:'+agencyId);
|
||||
const agencyName = agencyIdName.agency_name;
|
||||
// console.log('TablePageHead agencyName:'+agencyName);
|
||||
|
||||
if(agencyIdName !== undefined){
|
||||
//console.log('TablePageHead agencyIdName:'+JSON.stringify(agencyIdName));
|
||||
//console.log('TablePageHead agencyIdName.length:'+agencyIdName.length);
|
||||
const agencyId=agencyIdName.agency_id;
|
||||
//console.log('TablePageHead agencyId:'+agencyId);
|
||||
const agencyName=agencyIdName.agency_name;
|
||||
//console.log('TablePageHead agencyName:'+agencyName);
|
||||
/* store and initialise data in function component state */
|
||||
const [tripCalendar, setTripCalendar] = useState({});
|
||||
|
||||
/*store and initialise data in function component state*/
|
||||
const [tripCalendar, setTripCalendar] = useState({});
|
||||
const getTripCalendar = async () => {
|
||||
try {
|
||||
/* get trip calendar */
|
||||
const address = `${config.API}trip-calendar-by-agency-id?agencyid=${agencyId}`;
|
||||
// console.log('TablePageHead address:'+address);
|
||||
|
||||
const getTripCalendar = async () => {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const res = await axios.get(address);
|
||||
|
||||
try {
|
||||
/*get trip calendar*/
|
||||
const address=`${config.API}trip-calendar-by-agency-id?agencyid=${agencyId}`;
|
||||
//console.log('TablePageHead address:'+address);
|
||||
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const res = await axios.get(address);
|
||||
|
||||
let aryTripCalendar = res.data;
|
||||
//console.log('TablePageHead aryTripCalendar.length:'+aryTripCalendar.length);
|
||||
const aryTripCalendar = res.data;
|
||||
// console.log('TablePageHead aryTripCalendar.length:'+aryTripCalendar.length);
|
||||
setTripCalendar(aryTripCalendar);
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
getTripCalendar();
|
||||
|
||||
useEffect(() => {
|
||||
/* use an empty dependency array to ensure the hook is running only once */
|
||||
|
||||
getTripCalendar();
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, []);
|
||||
|
||||
/*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 (
|
||||
<>
|
||||
<TableSwitchHead
|
||||
tripCalendar={tripCalendar}
|
||||
agencyId={agencyId}
|
||||
agencyName={agencyName}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
}else{
|
||||
return <p>loading...</p>
|
||||
}
|
||||
};
|
||||
return (
|
||||
<TableSwitchHead
|
||||
tripCalendar={tripCalendar}
|
||||
agencyId={agencyId}
|
||||
agencyName={agencyName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <p>loading...</p>;
|
||||
}
|
||||
|
||||
TablePageHead.propTypes = {
|
||||
agencyIdName: PropTypes.object
|
||||
agencyIdName: PropTypes.object,
|
||||
};
|
||||
|
|
|
@ -5,58 +5,60 @@ import PropTypes from 'prop-types';
|
|||
import Input from './input';
|
||||
import TableSwitch from './table-switch';
|
||||
import Select from './select';
|
||||
import {selectOptions} from '../utils/select-options';
|
||||
import { selectOptions } from '../utils/select-options';
|
||||
|
||||
const TablePage = ({ name }) => {
|
||||
/*store and initialise data in function component state*/
|
||||
const [oset, setOset] = useState(1);
|
||||
const [limit, setLimit] = useState(parseInt(selectOptions[0],10));
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const handleClickPrev = () => {
|
||||
setOset((oset) => (oset > 1 ? --oset : oset));
|
||||
};
|
||||
const handleClickNext = () => {
|
||||
setOset((oset) => ++oset);
|
||||
};
|
||||
const handleChangeLimit = (event) => {
|
||||
setLimit((limit) => parseInt(event.target.value,10));
|
||||
};
|
||||
const handleSearch = (e) => {
|
||||
setSearchField((searchField)=>e.target.value);
|
||||
};
|
||||
if (name && name.indexOf(' ') === -1) {
|
||||
return <>
|
||||
<button onClick={handleClickPrev}>prev</button>
|
||||
<button onClick={handleClickNext}>next</button>
|
||||
<Select
|
||||
defaultValue={selectOptions[0]}
|
||||
id="tablePageLimit"
|
||||
name="tablePageLimit"
|
||||
onChange={handleChangeLimit}
|
||||
options={selectOptions}
|
||||
/>
|
||||
<Input
|
||||
id="tablePageSearch"
|
||||
name="tablePageSearch"
|
||||
onChange={handleSearch}
|
||||
placeholder="Search table globally"
|
||||
type="text"
|
||||
title="Enter search value"
|
||||
value={searchField}
|
||||
/>
|
||||
<TableSwitch
|
||||
name={name}
|
||||
isFetched={false}
|
||||
oset={oset}
|
||||
limit={limit}
|
||||
filter={searchField}
|
||||
/>
|
||||
</>;
|
||||
} else {
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
};
|
||||
function TablePage({ name }) {
|
||||
/* store and initialise data in function component state */
|
||||
const [oset, setOset] = useState(1);
|
||||
const [limit, setLimit] = useState(parseInt(selectOptions[0], 10));
|
||||
const [searchField, setSearchField] = useState('');
|
||||
const handleClickPrev = () => {
|
||||
setOset((oset) => (oset > 1 ? --oset : oset));
|
||||
};
|
||||
const handleClickNext = () => {
|
||||
setOset((oset) => ++oset);
|
||||
};
|
||||
const handleChangeLimit = (event) => {
|
||||
setLimit((limit) => parseInt(event.target.value, 10));
|
||||
};
|
||||
const handleSearch = (e) => {
|
||||
setSearchField((searchField) => e.target.value);
|
||||
};
|
||||
if (name && name.indexOf(' ') === -1) {
|
||||
return (
|
||||
<>
|
||||
<button onClick={handleClickPrev}>prev</button>
|
||||
|
||||
<button onClick={handleClickNext}>next</button>
|
||||
<Select
|
||||
defaultValue={selectOptions[0]}
|
||||
id="tablePageLimit"
|
||||
name="tablePageLimit"
|
||||
onChange={handleChangeLimit}
|
||||
options={selectOptions}
|
||||
/>
|
||||
<Input
|
||||
id="tablePageSearch"
|
||||
name="tablePageSearch"
|
||||
onChange={handleSearch}
|
||||
placeholder="Search table globally"
|
||||
type="text"
|
||||
title="Enter search value"
|
||||
value={searchField}
|
||||
/>
|
||||
<TableSwitch
|
||||
name={name}
|
||||
isFetched={false}
|
||||
oset={oset}
|
||||
limit={limit}
|
||||
filter={searchField}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
TablePage.propTypes = {
|
||||
name: PropTypes.string
|
||||
name: PropTypes.string,
|
||||
};
|
||||
export default TablePage;
|
||||
|
|
|
@ -2,39 +2,36 @@ import React, { useEffect, useState } from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import Table from 'react-bootstrap/Table';
|
||||
import TableEntry from './agency-id-name-table-entry';
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
function TableSwitchBody ({
|
||||
tripCalendar,
|
||||
agencyId,
|
||||
agencyName
|
||||
/* the simplest way to define a component is to write a JavaScript function */
|
||||
/* destructure props object */
|
||||
function TableSwitchBody({
|
||||
tripCalendar,
|
||||
agencyId,
|
||||
agencyName,
|
||||
}) {
|
||||
if(tripCalendar!==undefined &&
|
||||
agencyId!==undefined &&
|
||||
agencyName!==undefined){
|
||||
//console.log('TableSwitchBody agencyId: '+agencyId);
|
||||
//console.log('TableSwitchBody agencyName: '+agencyName);
|
||||
//console.log('TableSwitchBody tripCalendar.length: '+Object.keys(tripCalendar).length);
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<tbody>
|
||||
<TableEntry
|
||||
agencyId={agencyId}
|
||||
agencyName={agencyName}
|
||||
tripCalendar={tripCalendar}
|
||||
/>
|
||||
</tbody>
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
//console.log('TableSwitchBody waiting for prop');
|
||||
return <p>Table Switch Body loading...</p>
|
||||
}
|
||||
if (tripCalendar !== undefined
|
||||
&& agencyId !== undefined
|
||||
&& agencyName !== undefined) {
|
||||
// console.log('TableSwitchBody agencyId: '+agencyId);
|
||||
// console.log('TableSwitchBody agencyName: '+agencyName);
|
||||
// console.log('TableSwitchBody tripCalendar.length: '+Object.keys(tripCalendar).length);
|
||||
/* return a React element */
|
||||
return (
|
||||
<tbody>
|
||||
<TableEntry
|
||||
agencyId={agencyId}
|
||||
agencyName={agencyName}
|
||||
tripCalendar={tripCalendar}
|
||||
/>
|
||||
</tbody>
|
||||
);
|
||||
}
|
||||
// console.log('TableSwitchBody waiting for prop');
|
||||
return <p>Table Switch Body loading...</p>;
|
||||
}
|
||||
TableSwitchBody.propTypes = {
|
||||
tripCalendar: PropTypes.object,
|
||||
agencyId: PropTypes.string,
|
||||
agencyName: PropTypes.string
|
||||
tripCalendar: PropTypes.object,
|
||||
agencyId: PropTypes.string,
|
||||
agencyName: PropTypes.string,
|
||||
};
|
||||
export default TableSwitchBody;
|
||||
|
|
|
@ -3,25 +3,22 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import TableHead from './agency-id-name-table-head';
|
||||
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
export default function TableSwitchHead({tripCalendar}) {
|
||||
if(tripCalendar!==undefined){
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<thead>
|
||||
<TableHead
|
||||
tripCalendar={tripCalendar}
|
||||
/>
|
||||
</thead>
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return <p>loading...</p>
|
||||
}
|
||||
/* the simplest way to define a component is to write a JavaScript function */
|
||||
/* destructure props object */
|
||||
export default function TableSwitchHead({ tripCalendar }) {
|
||||
if (tripCalendar !== undefined) {
|
||||
/* return a React element */
|
||||
return (
|
||||
<thead>
|
||||
<TableHead
|
||||
tripCalendar={tripCalendar}
|
||||
/>
|
||||
</thead>
|
||||
);
|
||||
}
|
||||
return <p>loading...</p>;
|
||||
}
|
||||
|
||||
TableSwitchHead.propTypes = {
|
||||
tripCalendar: PropTypes.object
|
||||
tripCalendar: PropTypes.object,
|
||||
};
|
||||
|
|
|
@ -5,103 +5,79 @@ import PropTypes from 'prop-types';
|
|||
import TableHeadSwitch from './table-head-switch';
|
||||
import TableEntrySwitch from './table-entry-switch';
|
||||
import config from '../config';
|
||||
import {filterData} from '../utils/filter-data';
|
||||
import { filterData } from '../utils/filter-data';
|
||||
|
||||
/* the simplest way to define a component is to write a JavaScript function */
|
||||
/* destructure props object */
|
||||
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);
|
||||
|
||||
|
||||
|
||||
|
||||
/*the simplest way to define a component is to write a JavaScript function*/
|
||||
/*destructure props object*/
|
||||
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);
|
||||
|
||||
if(res.data){
|
||||
|
||||
if (res.data) {
|
||||
setAry((ary) => res.data);
|
||||
let data=filterData(res.data,name,filter);
|
||||
const data = filterData(res.data, name, filter);
|
||||
setAryFiltered((aryFiltered) => data);
|
||||
}else{
|
||||
console.error('fetch() res NOT available');
|
||||
}
|
||||
} else {
|
||||
console.error(`name ${name} not valid`);
|
||||
setAry((ary) => []);
|
||||
} else {
|
||||
console.error('fetch() res NOT available');
|
||||
}
|
||||
} else {
|
||||
console.error(`name ${name} not valid`);
|
||||
setAry((ary) => []);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
setAry((ary) => []);
|
||||
setAryFiltered((aryFiltered) => []);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
setAryFiltered((aryFiltered)=>{
|
||||
let filtered=filterData(ary,name,filter);
|
||||
return filtered;
|
||||
});
|
||||
},[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 > -1){
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<table>
|
||||
<thead>
|
||||
<TableHeadSwitch name={name}/>
|
||||
</thead>
|
||||
<tbody>
|
||||
<TableEntrySwitch aryData={aryFiltered} name={name}/>
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setAryFiltered((aryFiltered) => {
|
||||
const filtered = filterData(ary, name, filter);
|
||||
return filtered;
|
||||
});
|
||||
}, [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 > -1) {
|
||||
/* return a React element */
|
||||
return (
|
||||
<table>
|
||||
<thead>
|
||||
<TableHeadSwitch name={name} />
|
||||
</thead>
|
||||
<tbody>
|
||||
<TableEntrySwitch aryData={aryFiltered} name={name} />
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
TableSwitch.propTypes = {
|
||||
name: PropTypes.string,
|
||||
isFetched: PropTypes.bool,
|
||||
offset: PropTypes.number,
|
||||
limit: PropTypes.number,
|
||||
filter: PropTypes.string
|
||||
name: PropTypes.string,
|
||||
isFetched: PropTypes.bool,
|
||||
offset: PropTypes.number,
|
||||
limit: PropTypes.number,
|
||||
filter: PropTypes.string,
|
||||
};
|
||||
export default TableSwitch;
|
||||
|
|
|
@ -4,13 +4,12 @@ import PropTypes from 'prop-types';
|
|||
import FileSelection from './file-selection';
|
||||
|
||||
export default function Tables({ data }) {
|
||||
if (data.length > 0) {
|
||||
return <FileSelection options={data} />;
|
||||
} else {
|
||||
return <p>Selection loading...</p>;
|
||||
}
|
||||
};
|
||||
if (data.length > 0) {
|
||||
return <FileSelection options={data} />;
|
||||
}
|
||||
return <p>Selection loading...</p>;
|
||||
}
|
||||
|
||||
Tables.propTypes = {
|
||||
data: PropTypes.array
|
||||
data: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*destructure props object*/
|
||||
const TransfersTableEntry = ({
|
||||
fromStopId,
|
||||
toStopId,
|
||||
fromRouteId,
|
||||
toRouteId,
|
||||
fromTripId,
|
||||
toTripId,
|
||||
transferType,
|
||||
minTransferTime
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{fromStopId}</td>
|
||||
<td>{toStopId}</td>
|
||||
<td>{fromRouteId}</td>
|
||||
<td>{toRouteId}</td>
|
||||
<td>{fromTripId}</td>
|
||||
<td>{toTripId}</td>
|
||||
<td>{transferType}</td>
|
||||
<td>{minTransferTime}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function TransfersTableEntry({
|
||||
fromStopId,
|
||||
toStopId,
|
||||
fromRouteId,
|
||||
toRouteId,
|
||||
fromTripId,
|
||||
toTripId,
|
||||
transferType,
|
||||
minTransferTime,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{fromStopId}</td>
|
||||
<td>{toStopId}</td>
|
||||
<td>{fromRouteId}</td>
|
||||
<td>{toRouteId}</td>
|
||||
<td>{fromTripId}</td>
|
||||
<td>{toTripId}</td>
|
||||
<td>{transferType}</td>
|
||||
<td>{minTransferTime}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
TransfersTableEntry.propTypes = {
|
||||
fromStopId: PropTypes.string,
|
||||
toStopId: PropTypes.string,
|
||||
fromRouteId: PropTypes.string,
|
||||
toRouteId: PropTypes.string,
|
||||
fromTripId: PropTypes.string,
|
||||
toTripId: PropTypes.string,
|
||||
transferType: PropTypes.number,
|
||||
minTransferTime: PropTypes.number
|
||||
fromStopId: PropTypes.string,
|
||||
toStopId: PropTypes.string,
|
||||
fromRouteId: PropTypes.string,
|
||||
toRouteId: PropTypes.string,
|
||||
fromTripId: PropTypes.string,
|
||||
toTripId: PropTypes.string,
|
||||
transferType: PropTypes.number,
|
||||
minTransferTime: PropTypes.number,
|
||||
};
|
||||
|
||||
export default TransfersTableEntry;
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import React from 'react';
|
||||
|
||||
const TransfersTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>from_stop_id</th>
|
||||
<th>to_stop_id</th>
|
||||
<th>from_route_id</th>
|
||||
<th>to_route_id</th>
|
||||
<th>from_trip_id</th>
|
||||
<th>to_trip_id</th>
|
||||
<th>transfer_type</th>
|
||||
<th>min_transfer_time</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function TransfersTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>from_stop_id</th>
|
||||
<th>to_stop_id</th>
|
||||
<th>from_route_id</th>
|
||||
<th>to_route_id</th>
|
||||
<th>from_trip_id</th>
|
||||
<th>to_trip_id</th>
|
||||
<th>transfer_type</th>
|
||||
<th>min_transfer_time</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default TransfersTableHead;
|
||||
|
|
|
@ -1,33 +1,53 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function TripUpdatesRouteDayTableEntries ({array}) {
|
||||
if ( array !== undefined && array !== null && array.length > 0 ) {
|
||||
|
||||
//TODO Shall we switch from UTC to local time zone for item.timestamp_pgsql?
|
||||
//iterate over array
|
||||
return array.map((item, index) => {
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
>
|
||||
<td>{item.agency_name} |</td>
|
||||
<td>{item.agency_id} |</td>
|
||||
<td>{item.route_id} |</td>
|
||||
<td>{item.route_short_name} |</td>
|
||||
<td>{item.trip_id} |</td>
|
||||
<td>{item.trip_short_name} |</td>
|
||||
<td>{item.trip_headsign} |</td>
|
||||
<td>{item.timestamp_pgsql} |</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
}else{
|
||||
//data is empty
|
||||
return null;
|
||||
}
|
||||
};
|
||||
export default function TripUpdatesRouteDayTableEntries({ array }) {
|
||||
if (array !== undefined && array !== null && array.length > 0) {
|
||||
// TODO Shall we switch from UTC to local time zone for item.timestamp_pgsql?
|
||||
// iterate over array
|
||||
return array.map((item, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
>
|
||||
<td>
|
||||
{item.agency_name}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.agency_id}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.route_id}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.route_short_name}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.trip_id}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.trip_short_name}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.trip_headsign}
|
||||
|
|
||||
</td>
|
||||
<td>
|
||||
{item.timestamp_pgsql}
|
||||
|
|
||||
</td>
|
||||
</tr>
|
||||
));
|
||||
}
|
||||
// data is empty
|
||||
return null;
|
||||
}
|
||||
|
||||
TripUpdatesRouteDayTableEntries.propTypes = {
|
||||
array: PropTypes.array
|
||||
array: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -3,43 +3,47 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import TripUpdatesRouteDayTableEntries from './trip-updates-route-day-table-entries';
|
||||
|
||||
/*destructure props object*/
|
||||
export default function TripUpdatesRouteDayTable ({array, title, date}){
|
||||
|
||||
if ( array !== undefined && array !== null) {
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<p>Table of {array.length} {title} for {date}:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>agency_name |</th>
|
||||
<th>agency_id |</th>
|
||||
<th>route_id |</th>
|
||||
<th>route_short_name |</th>
|
||||
<th>trip_id |</th>
|
||||
<th>trip_short_name |</th>
|
||||
<th>trip_headsign |</th>
|
||||
<th>timestamp_pgsql |</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<TripUpdatesRouteDayTableEntries array={array} />
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return (
|
||||
<>
|
||||
<p>loading...</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
/* destructure props object */
|
||||
export default function TripUpdatesRouteDayTable({ array, title, date }) {
|
||||
if (array !== undefined && array !== null) {
|
||||
/* return a React element */
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Table of
|
||||
{array.length}
|
||||
{title}
|
||||
{' '}
|
||||
for
|
||||
{date}
|
||||
:
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>agency_name |</th>
|
||||
<th>agency_id |</th>
|
||||
<th>route_id |</th>
|
||||
<th>route_short_name |</th>
|
||||
<th>trip_id |</th>
|
||||
<th>trip_short_name |</th>
|
||||
<th>trip_headsign |</th>
|
||||
<th>timestamp_pgsql |</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<TripUpdatesRouteDayTableEntries array={array} />
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<p>loading...</p>
|
||||
);
|
||||
}
|
||||
TripUpdatesRouteDayTable.propTypes = {
|
||||
array: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
date: PropTypes.string
|
||||
array: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
date: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -1,31 +1,28 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function TableEntries ({array}) {
|
||||
if ( array !== undefined && array !== null && array.length > 0 ) {
|
||||
//iterate over array
|
||||
return array.map((item, index) => {
|
||||
return (
|
||||
<tr
|
||||
key={item.trip_id}
|
||||
>
|
||||
<td>{item.agency_name}</td>
|
||||
<td>{item.agency_id}</td>
|
||||
<td>{item.route_id}</td>
|
||||
<td>{item.route_short_name}</td>
|
||||
<td>{item.service_id}</td>
|
||||
<td>{item.trip_id}</td>
|
||||
<td>{item.trip_short_name}</td>
|
||||
<td>{item.trip_headsign}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
}else{
|
||||
//data is empty
|
||||
return null;
|
||||
}
|
||||
};
|
||||
export default function TableEntries({ array }) {
|
||||
if (array !== undefined && array !== null && array.length > 0) {
|
||||
// iterate over array
|
||||
return array.map((item, index) => (
|
||||
<tr
|
||||
key={item.trip_id}
|
||||
>
|
||||
<td>{item.agency_name}</td>
|
||||
<td>{item.agency_id}</td>
|
||||
<td>{item.route_id}</td>
|
||||
<td>{item.route_short_name}</td>
|
||||
<td>{item.service_id}</td>
|
||||
<td>{item.trip_id}</td>
|
||||
<td>{item.trip_short_name}</td>
|
||||
<td>{item.trip_headsign}</td>
|
||||
</tr>
|
||||
));
|
||||
}
|
||||
// data is empty
|
||||
return null;
|
||||
}
|
||||
|
||||
TableEntries.propTypes = {
|
||||
array: PropTypes.array
|
||||
array: PropTypes.array,
|
||||
};
|
||||
|
|
|
@ -3,42 +3,44 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import TableEntries from './trips-route-day-table-entries';
|
||||
|
||||
/*destructure props object*/
|
||||
export default function TripsRouteDayTable ({array, title}){
|
||||
|
||||
if ( array !== undefined && array !== null) {
|
||||
/*return a React element*/
|
||||
return (
|
||||
<>
|
||||
<p>Table of {array.length} {title} for today:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>agency_name</th>
|
||||
<th>agency_id</th>
|
||||
<th>route_id</th>
|
||||
<th>route_short_name</th>
|
||||
<th>service_id</th>
|
||||
<th>trip_id</th>
|
||||
<th>trip_short_name</th>
|
||||
<th>trip_headsign</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<TableEntries array={array} />
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return (
|
||||
<>
|
||||
<p>loading...</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
/* destructure props object */
|
||||
export default function TripsRouteDayTable({ array, title }) {
|
||||
if (array !== undefined && array !== null) {
|
||||
/* return a React element */
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Table of
|
||||
{array.length}
|
||||
{title}
|
||||
{' '}
|
||||
for today:
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>agency_name</th>
|
||||
<th>agency_id</th>
|
||||
<th>route_id</th>
|
||||
<th>route_short_name</th>
|
||||
<th>service_id</th>
|
||||
<th>trip_id</th>
|
||||
<th>trip_short_name</th>
|
||||
<th>trip_headsign</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<TableEntries array={array} />
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<p>loading...</p>
|
||||
);
|
||||
}
|
||||
TripsRouteDayTable.propTypes = {
|
||||
array: PropTypes.array,
|
||||
title: PropTypes.string
|
||||
array: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
};
|
||||
|
|
|
@ -1,46 +1,46 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*destructure props object*/
|
||||
const TripsTableEntry = ({
|
||||
routeId,
|
||||
serviceId,
|
||||
tripId,
|
||||
tripHeadsign,
|
||||
tripShortName,
|
||||
directionId,
|
||||
blockId,
|
||||
shapeId,
|
||||
wheelchairAccessible,
|
||||
bikesAllowed
|
||||
}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{routeId}</td>
|
||||
<td>{serviceId}</td>
|
||||
<td>{tripId}</td>
|
||||
<td>{tripHeadsign}</td>
|
||||
<td>{tripShortName}</td>
|
||||
<td>{directionId ? 'true' : 'false'}</td>
|
||||
<td>{blockId}</td>
|
||||
<td>{shapeId}</td>
|
||||
<td>{wheelchairAccessible}</td>
|
||||
<td>{bikesAllowed}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
/* destructure props object */
|
||||
function TripsTableEntry({
|
||||
routeId,
|
||||
serviceId,
|
||||
tripId,
|
||||
tripHeadsign,
|
||||
tripShortName,
|
||||
directionId,
|
||||
blockId,
|
||||
shapeId,
|
||||
wheelchairAccessible,
|
||||
bikesAllowed,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td>{routeId}</td>
|
||||
<td>{serviceId}</td>
|
||||
<td>{tripId}</td>
|
||||
<td>{tripHeadsign}</td>
|
||||
<td>{tripShortName}</td>
|
||||
<td>{directionId ? 'true' : 'false'}</td>
|
||||
<td>{blockId}</td>
|
||||
<td>{shapeId}</td>
|
||||
<td>{wheelchairAccessible}</td>
|
||||
<td>{bikesAllowed}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
TripsTableEntry.propTypes = {
|
||||
routeId: PropTypes.string,
|
||||
serviceId: PropTypes.string,
|
||||
tripId: PropTypes.string,
|
||||
tripHeadsign: PropTypes.string,
|
||||
tripShortName: PropTypes.string,
|
||||
directionId: PropTypes.number,
|
||||
blockId: PropTypes.string,
|
||||
shapeId: PropTypes.string,
|
||||
wheelchairAccessible: PropTypes.number,
|
||||
bikesAllowed: PropTypes.number
|
||||
routeId: PropTypes.string,
|
||||
serviceId: PropTypes.string,
|
||||
tripId: PropTypes.string,
|
||||
tripHeadsign: PropTypes.string,
|
||||
tripShortName: PropTypes.string,
|
||||
directionId: PropTypes.number,
|
||||
blockId: PropTypes.string,
|
||||
shapeId: PropTypes.string,
|
||||
wheelchairAccessible: PropTypes.number,
|
||||
bikesAllowed: PropTypes.number,
|
||||
};
|
||||
|
||||
export default TripsTableEntry;
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import React from 'react';
|
||||
|
||||
const TripsTableHead = () => {
|
||||
return (
|
||||
<tr>
|
||||
<th>route_id</th>
|
||||
<th>service_id</th>
|
||||
<th>trip_id</th>
|
||||
<th>trip_headsign</th>
|
||||
<th>trip_short_name</th>
|
||||
<th>direction_id</th>
|
||||
<th>block_id</th>
|
||||
<th>shape_id</th>
|
||||
<th>wheelchair_accessible</th>
|
||||
<th>bikes_allowed</th>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
function TripsTableHead() {
|
||||
return (
|
||||
<tr>
|
||||
<th>route_id</th>
|
||||
<th>service_id</th>
|
||||
<th>trip_id</th>
|
||||
<th>trip_headsign</th>
|
||||
<th>trip_short_name</th>
|
||||
<th>direction_id</th>
|
||||
<th>block_id</th>
|
||||
<th>shape_id</th>
|
||||
<th>wheelchair_accessible</th>
|
||||
<th>bikes_allowed</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default TripsTableHead;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export default {
|
||||
API: 'http://localhost:65529/',
|
||||
GTFS_VALIDATOR_REPORT: 'https://www.v1gtfs.vbn.api.swingbe.de/gtfs-validator/report.html',
|
||||
API: 'http://localhost:65529/',
|
||||
GTFS_VALIDATOR_REPORT: 'https://www.v1gtfs.vbn.api.swingbe.de/gtfs-validator/report.html',
|
||||
};
|
||||
|
|
67
src/main.js
67
src/main.js
|
@ -1,54 +1,57 @@
|
|||
import React from 'react';
|
||||
import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';
|
||||
import {
|
||||
BrowserRouter as Router, Route, Routes, Navigate,
|
||||
} from 'react-router-dom';
|
||||
|
||||
import Header from './components/header';
|
||||
import Home from './pages/homepage';
|
||||
import Files from './pages/files';
|
||||
//TODO Date [today] is not implemented! import Overview from './pages/overview';
|
||||
// TODO Date [today] is not implemented! import Overview from './pages/overview';
|
||||
import OverviewNext from './pages/overview-next';
|
||||
//TODO Disable this route as it is not working! import Service from './pages/service';
|
||||
//TODO Disable this route as it is way too much overhead for API and database! import TripCalendar from './pages/trip-calendar';
|
||||
// TODO Disable this route as it is not working! import Service from './pages/service';
|
||||
// TODO Disable this route as it is way too much overhead for API and database! import TripCalendar from './pages/trip-calendar';
|
||||
import Realtime from './pages/realtime';
|
||||
//TODO import Trips from './pages/trips-route-day';
|
||||
// TODO import Trips from './pages/trips-route-day';
|
||||
import Contact from './pages/contact';
|
||||
|
||||
import packageInfo from '../package.json'
|
||||
import packageInfo from '../package.json';
|
||||
|
||||
const VERSION = packageInfo.version;
|
||||
|
||||
export default function Main() {
|
||||
return (
|
||||
//Router is the router implementation for HTML5 browsers
|
||||
//Link enables Routes on an anchor tag
|
||||
//Switch returns only the first matching route rather than all
|
||||
//Route is the conditionally shown component //based on matching a path to a URL
|
||||
<Router>
|
||||
<Header />
|
||||
<h1>GTFS-Display</h1>
|
||||
<p>
|
||||
This website processes GTFS Realtime and Schedule data.
|
||||
</p>
|
||||
<Routes>
|
||||
<Route exact path="/" element={<Home />} />
|
||||
<Route exact path="/agency" element={<OverviewNext />} />
|
||||
<Route exact path="/files" element={<Files />} />
|
||||
<Route exact path="/realtime" element={<Realtime />} />
|
||||
<Route exact path="/contact" element={<Contact />} />
|
||||
<Route path="*" element={<Navigate to="/" />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
/** TODO Is this route of any value?
|
||||
return (
|
||||
// Router is the router implementation for HTML5 browsers
|
||||
// Link enables Routes on an anchor tag
|
||||
// Switch returns only the first matching route rather than all
|
||||
// Route is the conditionally shown component //based on matching a path to a URL
|
||||
<Router>
|
||||
<Header />
|
||||
<h1>GTFS-Display</h1>
|
||||
<p>
|
||||
This website processes GTFS Realtime and Schedule data.
|
||||
</p>
|
||||
<Routes>
|
||||
<Route exact path="/" element={<Home />} />
|
||||
<Route exact path="/agency" element={<OverviewNext />} />
|
||||
<Route exact path="/files" element={<Files />} />
|
||||
<Route exact path="/realtime" element={<Realtime />} />
|
||||
<Route exact path="/contact" element={<Contact />} />
|
||||
<Route path="*" element={<Navigate to="/" />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
/** TODO Is this route of any value?
|
||||
<Route exact path="/trips" element={<Trips />} />
|
||||
*/
|
||||
/** TODO Date [today] is not implemented!
|
||||
/** TODO Date [today] is not implemented!
|
||||
<Route exact path="/overview-today" element={<Overview />} />
|
||||
*/
|
||||
|
||||
/** TODO Disable this route as it is not working!
|
||||
/** TODO Disable this route as it is not working!
|
||||
<Route exact path="/service" element={<Service />} />
|
||||
*/
|
||||
|
||||
/** TODO Disable this route as it is way too much overhead for API and database!
|
||||
/** TODO Disable this route as it is way too much overhead for API and database!
|
||||
<Route exact path="/trip-calendar" element={<TripCalendar />} />
|
||||
*/
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,92 +7,92 @@ import AgencySelect from '../components/agency-select';
|
|||
import Input from '../components/input';
|
||||
|
||||
export default function AgencyPerDay() {
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
const agencyNameDefault = 'Select GTFS agency_name';
|
||||
|
||||
const agencyNameDefault = 'Select GTFS agency_name';
|
||||
/* store and initialize data in function component state */
|
||||
const [strngAgencyId, setStrngAgencyId] = useState(agencyNameDefault);
|
||||
|
||||
/*store and initialize data in function component state*/
|
||||
const [strngAgencyId, setStrngAgencyId] = useState(agencyNameDefault);
|
||||
const [rryAgencyPerDay, setRryAgencyPerDay] = useState([]);
|
||||
const [rryAgencies, setRryAgencies] = useState([]);
|
||||
|
||||
const [rryAgencyPerDay, setRryAgencyPerDay] = useState([]);
|
||||
const [rryAgencies, setRryAgencies] = useState([]);
|
||||
// TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1
|
||||
|| e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date) => e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
//TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1 ||
|
||||
e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date)=>e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
const getRryAgencies = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const getRryAgencies = async () => {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const address = `${config.API}agencyids`;
|
||||
//console.log('trip-updates-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
//console.log('trip-updates-route-day res.data.length: Agencies: ' + res.data.length);
|
||||
setRryAgencies((rryAgencies) => res.data);
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
// console.log('trip-updates-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
// console.log('trip-updates-route-day res.data.length: Agencies: ' + res.data.length);
|
||||
setRryAgencies((rryAgencies) => res.data);
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getRryAgencyPerDay = async () => {
|
||||
if ( strngAgencyId !== agencyNameDefault &&
|
||||
date !== dateDefault) {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const getRryAgencyPerDay = async () => {
|
||||
if (strngAgencyId !== agencyNameDefault
|
||||
&& date !== dateDefault) {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const address = `${config.API}trip-updates-by-agency-day?agencyid=${strngAgencyId}&day=${date}`;
|
||||
//console.log('trip-updates-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if ( res.data !== undefined && res.data !== null ) {
|
||||
//console.log('trip-updates-route-day res.data.length: AgencyPerDay: ' + res.data.length);
|
||||
setRryAgencyPerDay((rryAgencyPerDay) => res.data);
|
||||
// console.log('trip-updates-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if (res.data !== undefined && res.data !== null) {
|
||||
// console.log('trip-updates-route-day res.data.length: AgencyPerDay: ' + res.data.length);
|
||||
setRryAgencyPerDay((rryAgencyPerDay) => res.data);
|
||||
} else {
|
||||
console.error('ERROR: trip-updates by routes and day request FAILED');
|
||||
console.error('ERROR: trip-updates by routes and day request FAILED');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleChangeAgencyId = (event) => {
|
||||
//console.log('trip-updates-route-day: handleChangeAgencyId() value: ' + event.target.value);
|
||||
setStrngAgencyId((strngAgencyId) => event.target.value);
|
||||
};
|
||||
const handleChangeAgencyId = (event) => {
|
||||
// console.log('trip-updates-route-day: handleChangeAgencyId() value: ' + event.target.value);
|
||||
setStrngAgencyId((strngAgencyId) => event.target.value);
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
getRryAgencies();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, []);
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
useEffect(() => {
|
||||
getRryAgencies();
|
||||
/* use an empty dependency array to ensure the hook is running only once */
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
//console.log('trip-updates-route-day: useEffect() strngAgencyId: ' + strngAgencyId);
|
||||
getRryAgencyPerDay();
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [strngAgencyId, date]);
|
||||
useEffect(() => {
|
||||
// console.log('trip-updates-route-day: useEffect() strngAgencyId: ' + strngAgencyId);
|
||||
getRryAgencyPerDay();
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, [strngAgencyId, date]);
|
||||
|
||||
|
||||
return <>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<AgencySelect rry={rryAgencies} name={agencyNameDefault} onChange={handleChangeAgencyId} />
|
||||
<AgencyPerDayTable array={rryAgencyPerDay} title={'routes'} date={date}/>
|
||||
</>;
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<AgencySelect rry={rryAgencies} name={agencyNameDefault} onChange={handleChangeAgencyId} />
|
||||
<AgencyPerDayTable array={rryAgencyPerDay} title="routes" date={date} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,27 +1,46 @@
|
|||
import React from 'react';
|
||||
|
||||
import packageInfo from '../../package.json'
|
||||
import packageInfo from '../../package.json';
|
||||
|
||||
const VERSION = packageInfo.version;
|
||||
|
||||
export default function Contact() {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
For questions about this website please do not hesitate to reach out to dialog (at) swingbe (dot) de.
|
||||
</p>
|
||||
<p>
|
||||
Please feel <b>free</b> to <b>use</b>, <b>study</b>, <b>share</b> or <b>improve</b> the{' '}
|
||||
<a
|
||||
href="https://git.wtf-eg.de/dancingCycle/gtfs-display"
|
||||
target="_blank"
|
||||
>
|
||||
source
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
<p>
|
||||
Version: {VERSION}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
For questions about this website please do not hesitate to reach out to dialog (at) swingbe (dot) de.
|
||||
</p>
|
||||
<p>
|
||||
Please feel
|
||||
{' '}
|
||||
<b>free</b>
|
||||
{' '}
|
||||
to
|
||||
<b>use</b>
|
||||
,
|
||||
<b>study</b>
|
||||
,
|
||||
<b>share</b>
|
||||
{' '}
|
||||
or
|
||||
<b>improve</b>
|
||||
{' '}
|
||||
the
|
||||
{' '}
|
||||
<a
|
||||
href="https://git.wtf-eg.de/dancingCycle/gtfs-display"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
source
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
<p>
|
||||
Version:
|
||||
{' '}
|
||||
{VERSION}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,16 @@ import axios from 'axios';
|
|||
import Tables from '../components/tables';
|
||||
import gtfs from '../utils/gtfs';
|
||||
|
||||
const Files = () => {
|
||||
return <fieldset>
|
||||
<legend><b>GTFS Schedule</b> file overview</legend>
|
||||
<Tables data={gtfs.datasetFiles} />
|
||||
</fieldset>;
|
||||
};
|
||||
function Files() {
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>
|
||||
<b>GTFS Schedule</b>
|
||||
{' '}
|
||||
file overview
|
||||
</legend>
|
||||
<Tables data={gtfs.datasetFiles} />
|
||||
</fieldset>
|
||||
);
|
||||
}
|
||||
export default Files;
|
||||
|
|
|
@ -6,60 +6,61 @@ import GroupAgencyPerDayTable from '../components/group-agency-per-day-table';
|
|||
import Input from '../components/input';
|
||||
|
||||
export default function GroupAgencyPerDay() {
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
const [rryGroupAgencyPerDay, setRryGroupAgencyPerDay] = useState([]);
|
||||
const [rryAgencies, setRryAgencies] = useState([]);
|
||||
|
||||
const [rryGroupAgencyPerDay, setRryGroupAgencyPerDay] = useState([]);
|
||||
const [rryAgencies, setRryAgencies] = useState([]);
|
||||
// TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1
|
||||
|| e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date) => e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
//TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1 ||
|
||||
e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date)=>e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
const getRryGroupAgencyPerDay = async () => {
|
||||
if ( date !== dateDefault) {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const getRryGroupAgencyPerDay = async () => {
|
||||
if (date !== dateDefault) {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const address = `${config.API}trip-updates-by-group-agency-day?day=${date}`;
|
||||
//console.log('address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if ( res.data !== undefined && res.data !== null ) {
|
||||
//console.log('res.data.length: ' + res.data.length);
|
||||
setRryGroupAgencyPerDay((rryGroupAgencyPerDay) => res.data);
|
||||
// console.log('address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if (res.data !== undefined && res.data !== null) {
|
||||
// console.log('res.data.length: ' + res.data.length);
|
||||
setRryGroupAgencyPerDay((rryGroupAgencyPerDay) => res.data);
|
||||
} else {
|
||||
console.error('ERROR: trip-updates by routes and day request FAILED');
|
||||
console.error('ERROR: trip-updates by routes and day request FAILED');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
getRryGroupAgencyPerDay();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [date]);
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
useEffect(() => {
|
||||
getRryGroupAgencyPerDay();
|
||||
/* use an empty dependency array to ensure the hook is running only once */
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, [date]);
|
||||
|
||||
return <>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<GroupAgencyPerDayTable array={rryGroupAgencyPerDay} title={'agencies'} date={date}/>
|
||||
</>;
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<GroupAgencyPerDayTable array={rryGroupAgencyPerDay} title="agencies" date={date} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
|
||||
//TODO enable import GtfsValidatorReport from '../components/gtfs-validator-report.js';
|
||||
// TODO enable import GtfsValidatorReport from '../components/gtfs-validator-report.js';
|
||||
import GtfsFiles from '../components/gtfs-files';
|
||||
|
||||
export default function Homepage() {
|
||||
return <GtfsFiles />;
|
||||
};
|
||||
return <GtfsFiles />;
|
||||
}
|
||||
|
|
|
@ -5,32 +5,28 @@ import OverviewTable from '../components/overview-next-table';
|
|||
import config from '../config';
|
||||
|
||||
export default function OverviewNext() {
|
||||
const [cnts, setCnts] = useState([]);
|
||||
|
||||
const [cnts, setCnts] = useState([]);
|
||||
const getCnts = async () => {
|
||||
try {
|
||||
/* get cnts */
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const res = await axios.get(`${config.API}rts-stps-trps-cnt`);
|
||||
|
||||
const getCnts = async () => {
|
||||
try {
|
||||
/*get cnts*/
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const res = await axios.get(`${config.API}rts-stps-trps-cnt`);
|
||||
|
||||
if ( res !== null && res !== undefined ) {
|
||||
setCnts(res.data);
|
||||
if (res !== null && res !== undefined) {
|
||||
setCnts(res.data);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getCnts();
|
||||
}, []);
|
||||
|
||||
|
||||
if ( cnts === null || cnts === undefined || cnts.length === 0 ) {
|
||||
return <p>loading...</p>;
|
||||
} else {
|
||||
return <OverviewTable overview={cnts} />;
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getCnts();
|
||||
}, []);
|
||||
|
||||
if (cnts === null || cnts === undefined || cnts.length === 0) {
|
||||
return <p>loading...</p>;
|
||||
}
|
||||
return <OverviewTable overview={cnts} />;
|
||||
}
|
||||
|
|
|
@ -5,132 +5,131 @@ import OverviewTable from '../components/overview-table';
|
|||
import config from '../config';
|
||||
|
||||
export default function Overview() {
|
||||
/* store data in function component state */
|
||||
/* initialise as empty array */
|
||||
const [overview, setOverview] = useState([]);
|
||||
const [agencies, setAgencies] = useState(false);
|
||||
const [wait, setWait] = useState(false);
|
||||
|
||||
/*store data in function component state*/
|
||||
/*initialise as empty array*/
|
||||
const [overview, setOverview] = useState([]);
|
||||
const [agencies, setAgencies] = useState(false);
|
||||
const [wait, setWait] = useState(false);
|
||||
const handleAsyncOps = async (isMounted) => {
|
||||
/* get data for each agency */
|
||||
for (let j = 0; j < overview.length; j++) {
|
||||
// console.log('j: ' + j);
|
||||
let isBreaking = false;
|
||||
// 1. Make a shallow copy of the objects
|
||||
const aryObjs = [...overview];
|
||||
/// ///console.log('aryObjs len: ' + aryObjs.length);
|
||||
// 2. Make a shallow copy of the object you want to mutate
|
||||
const obj = { ...aryObjs[j] };
|
||||
// 3. Replace the property you're intested in
|
||||
const agencyId = obj.agency_id;
|
||||
/// /console.log('agencyId: ' + agencyId);
|
||||
let routeCount = obj.route_count;
|
||||
// console.log('routeCount: ' + routeCount);
|
||||
if (routeCount === null) {
|
||||
const resRouteCount = await axios.get(
|
||||
`${config.API}route-count?agencyid=${agencyId}`,
|
||||
);
|
||||
obj.route_count = resRouteCount.data;
|
||||
routeCount = obj.route_count;
|
||||
// console.log('routeCount: ' + routeCount);
|
||||
isBreaking = true;
|
||||
}
|
||||
let tripCount = obj.trip_count;
|
||||
// console.log('tripCount: ' + tripCount);
|
||||
if (tripCount === null) {
|
||||
const resTripCount = await axios.get(
|
||||
`${config.API}trip-count?agencyid=${agencyId}`,
|
||||
);
|
||||
obj.trip_count = resTripCount.data;
|
||||
tripCount = obj.trip_count;
|
||||
// console.log('tripCount: ' + tripCount);
|
||||
isBreaking = true;
|
||||
}
|
||||
// 4. Put it back into the array. N.B. we *are* mutating the array here, but that's why we made a copy first
|
||||
aryObjs[j] = obj;
|
||||
if (isBreaking && isMounted) {
|
||||
// 5. Set the state to the new copy
|
||||
setOverview((overview) => aryObjs);
|
||||
setWait((wait) => !wait);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleAsyncOps = async (isMounted) => {
|
||||
/*get data for each agency*/
|
||||
for (var j = 0; j < overview.length; j++) {
|
||||
//console.log('j: ' + j);
|
||||
let isBreaking = false;
|
||||
// 1. Make a shallow copy of the objects
|
||||
const aryObjs = [...overview];
|
||||
//////console.log('aryObjs len: ' + aryObjs.length);
|
||||
// 2. Make a shallow copy of the object you want to mutate
|
||||
const obj = { ...aryObjs[j] };
|
||||
// 3. Replace the property you're intested in
|
||||
const agencyId = obj.agency_id;
|
||||
////console.log('agencyId: ' + agencyId);
|
||||
let routeCount = obj.route_count;
|
||||
//console.log('routeCount: ' + routeCount);
|
||||
if (routeCount === null) {
|
||||
const resRouteCount = await axios.get(
|
||||
`${config.API}route-count?agencyid=${agencyId}`
|
||||
);
|
||||
obj.route_count = resRouteCount.data;
|
||||
routeCount = obj.route_count;
|
||||
//console.log('routeCount: ' + routeCount);
|
||||
isBreaking = true;
|
||||
}
|
||||
let tripCount = obj.trip_count;
|
||||
//console.log('tripCount: ' + tripCount);
|
||||
if (tripCount === null) {
|
||||
const resTripCount = await axios.get(
|
||||
`${config.API}trip-count?agencyid=${agencyId}`
|
||||
);
|
||||
obj.trip_count = resTripCount.data;
|
||||
tripCount = obj.trip_count;
|
||||
//console.log('tripCount: ' + tripCount);
|
||||
isBreaking = true;
|
||||
}
|
||||
// 4. Put it back into the array. N.B. we *are* mutating the array here, but that's why we made a copy first
|
||||
aryObjs[j] = obj;
|
||||
if (isBreaking && isMounted) {
|
||||
// 5. Set the state to the new copy
|
||||
setOverview((overview) => aryObjs);
|
||||
setWait((wait) => !wait);
|
||||
break;
|
||||
}
|
||||
const getAgencies = async (isMounted) => {
|
||||
try {
|
||||
/* get agencies */
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const res = await axios.get(`${config.API}agency-all`);
|
||||
|
||||
const aryOv = res.data;
|
||||
for (let i = 0; i < aryOv.length; i++) {
|
||||
const agencyId = aryOv[i].agency_id;
|
||||
const agencyName = aryOv[i].agency_name;
|
||||
const objOvItem = {};
|
||||
objOvItem.agency_id = agencyId;
|
||||
objOvItem.agency_name = agencyName;
|
||||
objOvItem.route_count = null;
|
||||
objOvItem.trip_count = null;
|
||||
objOvItem.day = null;
|
||||
|
||||
/* set state */
|
||||
if (isMounted) {
|
||||
// TODO Study! Is objOvitem added to array overview?
|
||||
setOverview((overview) => [...overview, objOvItem]);
|
||||
}
|
||||
}
|
||||
|
||||
/* set... is an async function and you cannot get the state value immediately after update. Use useEffect hook instead */
|
||||
setAgencies((agencies) => !agencies);
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
/* declare let isMounted = true inside useEffect, which will be changed in the cleanup callback, as soon as the component is unmounted. Before state updates, check this variable conditionally. */
|
||||
let isMounted = true;
|
||||
if (wait) {
|
||||
setWait((wait) => !wait);
|
||||
handleAsyncOps(isMounted);
|
||||
}
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [wait]);
|
||||
|
||||
const getAgencies = async (isMounted) => {
|
||||
try {
|
||||
/*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;
|
||||
let agencyName = aryOv[i].agency_name;
|
||||
let objOvItem = {};
|
||||
objOvItem['agency_id'] = agencyId;
|
||||
objOvItem['agency_name'] = agencyName;
|
||||
objOvItem['route_count'] = null;
|
||||
objOvItem['trip_count'] = null;
|
||||
objOvItem['day'] = null;
|
||||
|
||||
/*set state*/
|
||||
if (isMounted) {
|
||||
//TODO Study! Is objOvitem added to array overview?
|
||||
setOverview((overview) => [...overview, objOvItem]);
|
||||
}
|
||||
}
|
||||
|
||||
/*set... is an async function and you cannot get the state value immediately after update. Use useEffect hook instead*/
|
||||
setAgencies((agencies) => !agencies);
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
/* If you want to get an updated state value then use useEffect hook with dependency array. React will execute this hook after each state update. */
|
||||
useEffect(() => {
|
||||
/* declare let isMounted = true inside useEffect, which will be changed in the cleanup callback, as soon as the component is unmounted. Before state updates, check this variable conditionally. */
|
||||
let isMounted = true;
|
||||
/// ///console.log('useEffect() agencies: ' + agencies);
|
||||
if (agencies) {
|
||||
/// /console.log('agencies available');
|
||||
handleAsyncOps(isMounted);
|
||||
} else {
|
||||
/// /console.log('agencies not available');
|
||||
}
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [agencies]);
|
||||
|
||||
useEffect(() => {
|
||||
/*declare let isMounted = true inside useEffect, which will be changed in the cleanup callback, as soon as the component is unmounted. Before state updates, check this variable conditionally.*/
|
||||
let isMounted = true;
|
||||
if (wait) {
|
||||
setWait((wait) => !wait);
|
||||
handleAsyncOps(isMounted);
|
||||
}
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [wait]);
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
useEffect(() => {
|
||||
/* declare let isMounted = true inside useEffect, which will be changed in the cleanup callback, as soon as the component is unmounted. Before state updates, check this variable conditionally. */
|
||||
let isMounted = true;
|
||||
|
||||
/*If you want to get an updated state value then use useEffect hook with dependency array. React will execute this hook after each state update.*/
|
||||
useEffect(() => {
|
||||
/*declare let isMounted = true inside useEffect, which will be changed in the cleanup callback, as soon as the component is unmounted. Before state updates, check this variable conditionally.*/
|
||||
let isMounted = true;
|
||||
//////console.log('useEffect() agencies: ' + agencies);
|
||||
if (agencies) {
|
||||
////console.log('agencies available');
|
||||
handleAsyncOps(isMounted);
|
||||
} else {
|
||||
////console.log('agencies not available');
|
||||
}
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [agencies]);
|
||||
getAgencies(isMounted);
|
||||
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
/*declare let isMounted = true inside useEffect, which will be changed in the cleanup callback, as soon as the component is unmounted. Before state updates, check this variable conditionally.*/
|
||||
let isMounted = true;
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
/* use an empty dependency array to ensure the hook is running only once */
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, []);
|
||||
|
||||
getAgencies(isMounted);
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
/*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 <OverviewTable overview={overview} />;
|
||||
};
|
||||
return <OverviewTable overview={overview} />;
|
||||
}
|
||||
|
|
|
@ -6,60 +6,61 @@ import PerDayTable from '../components/per-day-table';
|
|||
import Input from '../components/input';
|
||||
|
||||
export default function PerDay() {
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
const [rryPerDay, setRryPerDay] = useState([]);
|
||||
const [rryAgencies, setRryAgencies] = useState([]);
|
||||
|
||||
const [rryPerDay, setRryPerDay] = useState([]);
|
||||
const [rryAgencies, setRryAgencies] = useState([]);
|
||||
// TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1
|
||||
|| e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date) => e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
//TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1 ||
|
||||
e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date)=>e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchData = async () => {
|
||||
if ( date !== dateDefault) {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const fetchData = async () => {
|
||||
if (date !== dateDefault) {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const address = `${config.API}trip-updates-by-day?day=${date}`;
|
||||
//console.log('address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if ( res.data !== undefined && res.data !== null ) {
|
||||
//console.log('res.data.length: ' + res.data.length);
|
||||
setRryPerDay((rryPerDay) => res.data);
|
||||
// console.log('address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if (res.data !== undefined && res.data !== null) {
|
||||
// console.log('res.data.length: ' + res.data.length);
|
||||
setRryPerDay((rryPerDay) => res.data);
|
||||
} else {
|
||||
console.error('ERROR: trip-updates by routes and day request FAILED');
|
||||
console.error('ERROR: trip-updates by routes and day request FAILED');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [date]);
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
/* use an empty dependency array to ensure the hook is running only once */
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, [date]);
|
||||
|
||||
return <>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<PerDayTable array={rryPerDay} title={'feeds'} date={date}/>
|
||||
</>;
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<PerDayTable array={rryPerDay} title="feeds" date={date} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,17 +4,16 @@ import RadioButton from '../components/radio-button';
|
|||
import Rltm from '../components/realtime';
|
||||
|
||||
export default function Realtime() {
|
||||
const [state, setState] = useState('');
|
||||
const [state, setState] = useState('');
|
||||
|
||||
const handleChange = (e) => {
|
||||
setState(e.target.value);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<RadioButton state={state} onChange={handleChange}/>
|
||||
<br />
|
||||
<Rltm state={state} />
|
||||
</>
|
||||
);
|
||||
|
||||
};
|
||||
const handleChange = (e) => {
|
||||
setState(e.target.value);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<RadioButton state={state} onChange={handleChange} />
|
||||
<br />
|
||||
<Rltm state={state} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,78 +7,79 @@ import ChartBar from '../components/chart-bar';
|
|||
import ChartLine from '../components/chart-line';
|
||||
import GtfsService from '../utils/gtfs-service';
|
||||
import config from '../config';
|
||||
const Service = () => {
|
||||
/*store route as string*/
|
||||
const [route, setRoute] = useState('');
|
||||
const [render, setRender] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [objService, setObjService] = useState({});
|
||||
const [time, setTime] = useState([]);
|
||||
const [trip, setTrip] = useState([]);
|
||||
|
||||
/*fetch objService in a JavaScript function*/
|
||||
const getObjService = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
let url = `${config.API}servicedays?routeshortname=${route}`;
|
||||
setLoading(true);
|
||||
const objService = await axios.get(url);
|
||||
setLoading(false);
|
||||
setRender(true);
|
||||
function Service() {
|
||||
/* store route as string */
|
||||
const [route, setRoute] = useState('');
|
||||
const [render, setRender] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [objService, setObjService] = useState({});
|
||||
const [time, setTime] = useState([]);
|
||||
const [trip, setTrip] = useState([]);
|
||||
|
||||
/*set state*/
|
||||
setObjService(objService.data);
|
||||
const aryTripCount = GtfsService.getAryTripCount(objService);
|
||||
setTrip(aryTripCount);
|
||||
const aryTime = GtfsService.getAryTime(objService);
|
||||
const aryDate = aryTime.map((time) => new Date(time).toDateString());
|
||||
setTime(aryDate);
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
/* fetch objService in a JavaScript function */
|
||||
const getObjService = async () => {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const url = `${config.API}servicedays?routeshortname=${route}`;
|
||||
setLoading(true);
|
||||
const objService = await axios.get(url);
|
||||
setLoading(false);
|
||||
setRender(true);
|
||||
|
||||
const handleSubmit = () => {
|
||||
event.preventDefault();
|
||||
getObjService();
|
||||
};
|
||||
/* set state */
|
||||
setObjService(objService.data);
|
||||
const aryTripCount = GtfsService.getAryTripCount(objService);
|
||||
setTrip(aryTripCount);
|
||||
const aryTime = GtfsService.getAryTime(objService);
|
||||
const aryDate = aryTime.map((time) => new Date(time).toDateString());
|
||||
setTime(aryDate);
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (e) => {
|
||||
setRoute(e.target.value);
|
||||
};
|
||||
const handleSubmit = () => {
|
||||
event.preventDefault();
|
||||
getObjService();
|
||||
};
|
||||
|
||||
/*element representing user-defined React component*/
|
||||
const msgTable = <ServiceTable render={render} service={objService} />;
|
||||
const bar = <ChartBar route={route} time={time} trip={trip} />;
|
||||
const line = <ChartLine route={route} time={time} trip={trip} />;
|
||||
const handleChange = (e) => {
|
||||
setRoute(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormValue
|
||||
value={route}
|
||||
valueName={'route'}
|
||||
onSubmit={handleSubmit}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Loading loading={loading} />
|
||||
<div
|
||||
style={{
|
||||
height: '500px',
|
||||
width: '900px'
|
||||
}}
|
||||
>
|
||||
{bar}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
height: '500px',
|
||||
width: '900px'
|
||||
}}
|
||||
>
|
||||
{line}
|
||||
</div>
|
||||
{msgTable}
|
||||
</>
|
||||
);
|
||||
};
|
||||
/* element representing user-defined React component */
|
||||
const msgTable = <ServiceTable render={render} service={objService} />;
|
||||
const bar = <ChartBar route={route} time={time} trip={trip} />;
|
||||
const line = <ChartLine route={route} time={time} trip={trip} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormValue
|
||||
value={route}
|
||||
valueName="route"
|
||||
onSubmit={handleSubmit}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Loading loading={loading} />
|
||||
<div
|
||||
style={{
|
||||
height: '500px',
|
||||
width: '900px',
|
||||
}}
|
||||
>
|
||||
{bar}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
height: '500px',
|
||||
width: '900px',
|
||||
}}
|
||||
>
|
||||
{line}
|
||||
</div>
|
||||
{msgTable}
|
||||
</>
|
||||
);
|
||||
}
|
||||
export default Service;
|
||||
|
|
|
@ -7,59 +7,59 @@ import TablePageHead from '../components/table-page-trip-calendar-head';
|
|||
import TablePageBody from '../components/table-page-trip-calendar-body';
|
||||
|
||||
export default function TripCalendar() {
|
||||
/* store and initialize data in function component state */
|
||||
const [agencyIds, setAgencyIds] = useState([]);
|
||||
|
||||
/*store and initialize data in function component state*/
|
||||
const [agencyIds, setAgencyIds] = useState([]);
|
||||
const getAgencyIds = async () => {
|
||||
try {
|
||||
/* get agencyIds */
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const res = await axios.get(`${config.API}agencyids`);
|
||||
|
||||
const getAgencyIds = async () => {
|
||||
try {
|
||||
/*get agencyIds*/
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const res = await axios.get(`${config.API}agencyids`);
|
||||
|
||||
let aryAgencyIds = res.data;
|
||||
//console.log('TripCalendar aryAgencyIds.length:'+aryAgencyIds.length);
|
||||
const aryAgencyIds = res.data;
|
||||
// console.log('TripCalendar aryAgencyIds.length:'+aryAgencyIds.length);
|
||||
setAgencyIds(aryAgencyIds);
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
getAgencyIds();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, []);
|
||||
|
||||
const agencysTableBody = agencyIds.map(value =>
|
||||
<TablePageBody
|
||||
className={value.agency_name}
|
||||
agencyIdName={value}
|
||||
key={value.agency_id}
|
||||
/>
|
||||
);
|
||||
const agencysTableHead = <TablePageHead
|
||||
className='tablePageHead'
|
||||
agencyIdName={agencyIds[0]}
|
||||
/>
|
||||
if(agencyIds.length > 0){
|
||||
/*TODO Introduce thead and tbody in Table?*/
|
||||
return <>
|
||||
<Table
|
||||
striped
|
||||
bordered
|
||||
hover
|
||||
size="sm"
|
||||
variant="dark"
|
||||
responsive
|
||||
>
|
||||
{agencysTableHead}
|
||||
{agencysTableBody}
|
||||
</Table>
|
||||
</>
|
||||
}else{
|
||||
return <p>loading...</p>
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
useEffect(() => {
|
||||
getAgencyIds();
|
||||
/* use an empty dependency array to ensure the hook is running only once */
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, []);
|
||||
|
||||
const agencysTableBody = agencyIds.map((value) => (
|
||||
<TablePageBody
|
||||
className={value.agency_name}
|
||||
agencyIdName={value}
|
||||
key={value.agency_id}
|
||||
/>
|
||||
));
|
||||
const agencysTableHead = (
|
||||
<TablePageHead
|
||||
className="tablePageHead"
|
||||
agencyIdName={agencyIds[0]}
|
||||
/>
|
||||
);
|
||||
if (agencyIds.length > 0) {
|
||||
/* TODO Introduce thead and tbody in Table? */
|
||||
return (
|
||||
<Table
|
||||
striped
|
||||
bordered
|
||||
hover
|
||||
size="sm"
|
||||
variant="dark"
|
||||
responsive
|
||||
>
|
||||
{agencysTableHead}
|
||||
{agencysTableBody}
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
return <p>loading...</p>;
|
||||
}
|
||||
|
|
|
@ -8,134 +8,133 @@ import RouteSelect from '../components/route-select';
|
|||
import Input from '../components/input';
|
||||
|
||||
export default function TripUpdates() {
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
|
||||
const dateDefault = 'Select date';
|
||||
const [date, setDate] = useState(dateDefault);
|
||||
const agencyNameDefault = 'Select GTFS agency_name';
|
||||
const routeNameDefault = 'Select GTFS route_short_name';
|
||||
|
||||
const agencyNameDefault = 'Select GTFS agency_name';
|
||||
const routeNameDefault = 'Select GTFS route_short_name';
|
||||
/* store and initialize data in function component state */
|
||||
const [strngAgencyId, setStrngAgencyId] = useState(agencyNameDefault);
|
||||
const [strngRouteId, setStrngRouteId] = useState(routeNameDefault);
|
||||
|
||||
/*store and initialize data in function component state*/
|
||||
const [strngAgencyId, setStrngAgencyId] = useState(agencyNameDefault);
|
||||
const [strngRouteId, setStrngRouteId] = useState(routeNameDefault);
|
||||
const [rryTripUpdates, setRryTripUpdates] = useState([]);
|
||||
const [rryAgencies, setRryAgencies] = useState([]);
|
||||
const [rryRoutes, setRryRoutes] = useState([]);
|
||||
|
||||
const [rryTripUpdates, setRryTripUpdates] = useState([]);
|
||||
const [rryAgencies, setRryAgencies] = useState([]);
|
||||
const [rryRoutes, setRryRoutes] = useState([]);
|
||||
// TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1
|
||||
|| e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date) => e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
//TODO How do we handle invalid date input?
|
||||
const handleDate = (e) => {
|
||||
if (e.target.value.indexOf('2023') !== -1 ||
|
||||
e.target.value.indexOf('2024') !== -1) {
|
||||
setDate((date)=>e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
const getRryAgencies = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const getRryAgencies = async () => {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const address = `${config.API}agencyids`;
|
||||
//console.log('trip-updates-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
//console.log('trip-updates-route-day res.data.length: Agencies: ' + res.data.length);
|
||||
setRryAgencies((rryAgency) => res.data);
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
// console.log('trip-updates-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
// console.log('trip-updates-route-day res.data.length: Agencies: ' + res.data.length);
|
||||
setRryAgencies((rryAgency) => res.data);
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getRryRoutes = async () => {
|
||||
if ( strngAgencyId !== agencyNameDefault ) {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const getRryRoutes = async () => {
|
||||
if (strngAgencyId !== agencyNameDefault) {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const address = `${config.API}routes?agencyid=${strngAgencyId}`;
|
||||
//console.log('trip-updates-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if ( res.data !== undefined && res.data !== null ) {
|
||||
//console.log('trip-updates-route-day res.data.length: Routes: ' + res.data.length);
|
||||
setRryRoutes((rryRoutes) => res.data);
|
||||
if ( res.data.length > 0 ) {
|
||||
// console.log('trip-updates-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if (res.data !== undefined && res.data !== null) {
|
||||
// console.log('trip-updates-route-day res.data.length: Routes: ' + res.data.length);
|
||||
setRryRoutes((rryRoutes) => res.data);
|
||||
if (res.data.length > 0) {
|
||||
setStrngRouteId((strngRouteId) => res.data[0].route_id);
|
||||
} else {
|
||||
} else {
|
||||
console.error('ERROR: agency has NO routes');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error('ERROR: routes by agency request FAILED');
|
||||
console.error('ERROR: routes by agency request FAILED');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getRryTripUpdates = async () => {
|
||||
if ( strngRouteId !== routeNameDefault &&
|
||||
date !== dateDefault) {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
//console.log('route: ' + strngRouteId);
|
||||
const getRryTripUpdates = async () => {
|
||||
if (strngRouteId !== routeNameDefault
|
||||
&& date !== dateDefault) {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
// console.log('route: ' + strngRouteId);
|
||||
const address = `${config.API}trip-updates-by-route-day?routeid=${strngRouteId}&day=${date}`;
|
||||
//console.log('trip-updates-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if ( res.data !== undefined && res.data !== null ) {
|
||||
//console.log('trip-updates-route-day res.data.length: TripUpdates: ' + res.data.length);
|
||||
setRryTripUpdates((rryTripUpdates) => res.data);
|
||||
// console.log('trip-updates-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if (res.data !== undefined && res.data !== null) {
|
||||
// console.log('trip-updates-route-day res.data.length: TripUpdates: ' + res.data.length);
|
||||
setRryTripUpdates((rryTripUpdates) => res.data);
|
||||
} else {
|
||||
console.error('ERROR: trip-updates by routes and day request FAILED');
|
||||
console.error('ERROR: trip-updates by routes and day request FAILED');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleChangeAgencyId = (event) => {
|
||||
//console.log('trip-updates-route-day: handleChangeAgencyId() value: ' + event.target.value);
|
||||
setStrngAgencyId((strngAgencyId) => event.target.value);
|
||||
};
|
||||
const handleChangeAgencyId = (event) => {
|
||||
// console.log('trip-updates-route-day: handleChangeAgencyId() value: ' + event.target.value);
|
||||
setStrngAgencyId((strngAgencyId) => event.target.value);
|
||||
};
|
||||
|
||||
const handleChangeRouteId = (event) => {
|
||||
//console.log('trip-updates-route-day: handleChangeRouteId() value: ' + event.target.value);
|
||||
setStrngRouteId((strngRouteId) => event.target.value);
|
||||
};
|
||||
const handleChangeRouteId = (event) => {
|
||||
// console.log('trip-updates-route-day: handleChangeRouteId() value: ' + event.target.value);
|
||||
setStrngRouteId((strngRouteId) => event.target.value);
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
getRryAgencies();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, []);
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
useEffect(() => {
|
||||
getRryAgencies();
|
||||
/* use an empty dependency array to ensure the hook is running only once */
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
//console.log('trip-updates-route-day: useEffect() strngAgencyId: ' + strngAgencyId);
|
||||
getRryRoutes();
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [strngAgencyId]);
|
||||
useEffect(() => {
|
||||
// console.log('trip-updates-route-day: useEffect() strngAgencyId: ' + strngAgencyId);
|
||||
getRryRoutes();
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, [strngAgencyId]);
|
||||
|
||||
useEffect(() => {
|
||||
//console.log('trip-updates-route-day: useEffect() strngRouteId: ' + strngRouteId);
|
||||
getRryTripUpdates();
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [strngRouteId, date]);
|
||||
useEffect(() => {
|
||||
// console.log('trip-updates-route-day: useEffect() strngRouteId: ' + strngRouteId);
|
||||
getRryTripUpdates();
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, [strngRouteId, date]);
|
||||
|
||||
|
||||
//TODO get rry based on route_id!
|
||||
return <>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<AgencySelect rry={rryAgencies} name={agencyNameDefault} onChange={handleChangeAgencyId} />
|
||||
<RouteSelect rry={rryRoutes} name={routeNameDefault} onChange={handleChangeRouteId} />
|
||||
<TripUpdatesRouteDayTable array={rryTripUpdates} title={'trips'} date={date}/>
|
||||
</>;
|
||||
};
|
||||
// TODO get rry based on route_id!
|
||||
return (
|
||||
<>
|
||||
<label>
|
||||
<Input
|
||||
id="inputDate"
|
||||
name={dateDefault}
|
||||
onChange={handleDate}
|
||||
placeholder="Enter date ${dateDefault}"
|
||||
type="date"
|
||||
title="Enter date ${dateDefault}"
|
||||
value={date}
|
||||
/>
|
||||
</label>
|
||||
<AgencySelect rry={rryAgencies} name={agencyNameDefault} onChange={handleChangeAgencyId} />
|
||||
<RouteSelect rry={rryRoutes} name={routeNameDefault} onChange={handleChangeRouteId} />
|
||||
<TripUpdatesRouteDayTable array={rryTripUpdates} title="trips" date={date} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,112 +7,111 @@ import AgencySelect from '../components/agency-select';
|
|||
import RouteSelect from '../components/route-select';
|
||||
|
||||
export default function Trips() {
|
||||
const agencyNameDefault = 'Select GTFS agency_name';
|
||||
const routeNameDefault = 'Select GTFS route_short_name';
|
||||
|
||||
const agencyNameDefault = 'Select GTFS agency_name';
|
||||
const routeNameDefault = 'Select GTFS route_short_name';
|
||||
/* store and initialize data in function component state */
|
||||
const [strngAgencyId, setStrngAgencyId] = useState(agencyNameDefault);
|
||||
const [strngRouteId, setStrngRouteId] = useState(routeNameDefault);
|
||||
const [rryTrips, setRryTrips] = useState([]);
|
||||
const [rryAgencies, setRryAgencies] = useState([]);
|
||||
const [rryRoutes, setRryRoutes] = useState([]);
|
||||
|
||||
/*store and initialize data in function component state*/
|
||||
const [strngAgencyId, setStrngAgencyId] = useState(agencyNameDefault);
|
||||
const [strngRouteId, setStrngRouteId] = useState(routeNameDefault);
|
||||
const [rryTrips, setRryTrips] = useState([]);
|
||||
const [rryAgencies, setRryAgencies] = useState([]);
|
||||
const [rryRoutes, setRryRoutes] = useState([]);
|
||||
|
||||
const getRryAgencies = async () => {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const getRryAgencies = async () => {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const address = `${config.API}agencyids`;
|
||||
//console.log('trips-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
//console.log('trips-route-day res.data.length: Agencies: ' + res.data.length);
|
||||
setRryAgencies((rryAgency) => res.data);
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
};
|
||||
// console.log('trips-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
// console.log('trips-route-day res.data.length: Agencies: ' + res.data.length);
|
||||
setRryAgencies((rryAgency) => res.data);
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getRryRoutes = async () => {
|
||||
if ( strngAgencyId !== agencyNameDefault ) {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const getRryRoutes = async () => {
|
||||
if (strngAgencyId !== agencyNameDefault) {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const address = `${config.API}routes?agencyid=${strngAgencyId}`;
|
||||
//console.log('trips-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if ( res.data !== undefined && res.data !== null ) {
|
||||
//console.log('trips-route-day res.data.length: Routes: ' + res.data.length);
|
||||
setRryRoutes((rryRoutes) => res.data);
|
||||
if ( res.data.length > 0 ) {
|
||||
// console.log('trips-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if (res.data !== undefined && res.data !== null) {
|
||||
// console.log('trips-route-day res.data.length: Routes: ' + res.data.length);
|
||||
setRryRoutes((rryRoutes) => res.data);
|
||||
if (res.data.length > 0) {
|
||||
setStrngRouteId((strngRouteId) => res.data[0].route_id);
|
||||
} else {
|
||||
} else {
|
||||
console.error('ERROR: agency has NO routes');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error('ERROR: routes by agency request FAILED');
|
||||
console.error('ERROR: routes by agency request FAILED');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getRryTrips = async () => {
|
||||
if ( strngRouteId !== routeNameDefault ) {
|
||||
try {
|
||||
/*TODO handle errors: https://www.valentinog.com/blog/await-react/*/
|
||||
const getRryTrips = async () => {
|
||||
if (strngRouteId !== routeNameDefault) {
|
||||
try {
|
||||
/* TODO handle errors: https://www.valentinog.com/blog/await-react/ */
|
||||
const date = new Date();
|
||||
const dateShort = date.getFullYear() + '-' + (date.getMonth()+1) + '-' + date.getDate();
|
||||
//console.log('trips-route-day dateShort: ' + dateShort);
|
||||
const dateShort = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
|
||||
// console.log('trips-route-day dateShort: ' + dateShort);
|
||||
const address = `${config.API}trips-by-route-day?routeid=${strngRouteId}&day=${dateShort}`;
|
||||
//console.log('trips-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if ( res.data !== undefined && res.data !== null ) {
|
||||
//console.log('trips-route-day res.data.length: Trips: ' + res.data.length);
|
||||
setRryTrips((rryTrips) => res.data);
|
||||
// console.log('trips-route-day res.data.length: address: ' + address);
|
||||
const res = await axios.get(address);
|
||||
if (res.data !== undefined && res.data !== null) {
|
||||
// console.log('trips-route-day res.data.length: Trips: ' + res.data.length);
|
||||
setRryTrips((rryTrips) => res.data);
|
||||
} else {
|
||||
console.error('ERROR: trips by routes and day request FAILED');
|
||||
console.error('ERROR: trips by routes and day request FAILED');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('err.message: ' + err.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(`err.message: ${err.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleChangeAgencyId = (event) => {
|
||||
//console.log('trips-route-day: handleChangeAgencyId() value: ' + event.target.value);
|
||||
setStrngAgencyId((strngAgencyId) => event.target.value);
|
||||
};
|
||||
const handleChangeAgencyId = (event) => {
|
||||
// console.log('trips-route-day: handleChangeAgencyId() value: ' + event.target.value);
|
||||
setStrngAgencyId((strngAgencyId) => event.target.value);
|
||||
};
|
||||
|
||||
const handleChangeRouteId = (event) => {
|
||||
//console.log('trips-route-day: handleChangeRouteId() value: ' + event.target.value);
|
||||
setStrngRouteId((strngRouteId) => event.target.value);
|
||||
};
|
||||
const handleChangeRouteId = (event) => {
|
||||
// console.log('trips-route-day: handleChangeRouteId() value: ' + event.target.value);
|
||||
setStrngRouteId((strngRouteId) => event.target.value);
|
||||
};
|
||||
|
||||
/*this hook is run after a DOM update. Changing state might result in an infinite loop*/
|
||||
/*hook need to be placed in body of the function component in which it is used*/
|
||||
useEffect(() => {
|
||||
getRryAgencies();
|
||||
/*use an empty dependency array to ensure the hook is running only once*/
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, []);
|
||||
/* this hook is run after a DOM update. Changing state might result in an infinite loop */
|
||||
/* hook need to be placed in body of the function component in which it is used */
|
||||
useEffect(() => {
|
||||
getRryAgencies();
|
||||
/* use an empty dependency array to ensure the hook is running only once */
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
//console.log('trips-route-day: useEffect() strngAgencyId: ' + strngAgencyId);
|
||||
getRryRoutes();
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [strngAgencyId]);
|
||||
useEffect(() => {
|
||||
// console.log('trips-route-day: useEffect() strngAgencyId: ' + strngAgencyId);
|
||||
getRryRoutes();
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, [strngAgencyId]);
|
||||
|
||||
useEffect(() => {
|
||||
//console.log('trips-route-day: useEffect() strngRouteId: ' + strngRouteId);
|
||||
getRryTrips();
|
||||
/*TODO study dependency array: https://reactjs.org/docs/hooks-effect.html*/
|
||||
}, [strngRouteId]);
|
||||
useEffect(() => {
|
||||
// console.log('trips-route-day: useEffect() strngRouteId: ' + strngRouteId);
|
||||
getRryTrips();
|
||||
/* TODO study dependency array: https://reactjs.org/docs/hooks-effect.html */
|
||||
}, [strngRouteId]);
|
||||
|
||||
|
||||
//TODO get rry based on route_id!
|
||||
return <>
|
||||
<AgencySelect rry={rryAgencies} name={agencyNameDefault} onChange={handleChangeAgencyId} />
|
||||
<RouteSelect rry={rryRoutes} name={routeNameDefault} onChange={handleChangeRouteId} />
|
||||
<TripsRouteDayTable array={rryTrips} title={'Trips'} />
|
||||
</>;
|
||||
};
|
||||
// TODO get rry based on route_id!
|
||||
return (
|
||||
<>
|
||||
<AgencySelect rry={rryAgencies} name={agencyNameDefault} onChange={handleChangeAgencyId} />
|
||||
<RouteSelect rry={rryRoutes} name={routeNameDefault} onChange={handleChangeRouteId} />
|
||||
<TripsRouteDayTable array={rryTrips} title="Trips" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue