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