Display destination name
This commit is contained in:
parent
3d6037a56a
commit
97d2d4c460
6 changed files with 38 additions and 60 deletions
|
@ -4,6 +4,7 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||||
|
"@fortawesome/free-regular-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.16",
|
"@fortawesome/react-fontawesome": "^0.1.16",
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
|
|
10
src/App.css
10
src/App.css
|
@ -7,16 +7,6 @@ body {
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholder:empty:before {
|
|
||||||
content: "\200b";
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder {
|
|
||||||
display: inline-block;
|
|
||||||
width: 50px;
|
|
||||||
background-color: #c9c9c9;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
25
src/App.tsx
25
src/App.tsx
|
@ -1,18 +1,19 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import Tcl, {ILigne} from "./Tcl";
|
import Tcl, {ILigne, IStop} from "./Tcl";
|
||||||
import {clearInterval, setInterval} from "timers";
|
import {clearInterval, setInterval} from "timers";
|
||||||
import {Col, Container, Dropdown, DropdownButton, Row} from "react-bootstrap";
|
import {Button, Col, Container, Row} from "react-bootstrap";
|
||||||
import {IStationInfo, IStationsInfoWrapper, IStationsStatusWrapper, IVelovStation} from "./IVelov";
|
import {IStationInfo, IStationsInfoWrapper, IStationsStatusWrapper, IVelovStation} from "./IVelov";
|
||||||
import Velov from "./Velov";
|
import Velov from "./Velov";
|
||||||
|
|
||||||
|
|
||||||
interface ITclFilteredApi {
|
interface ITclFilteredApi {
|
||||||
passages: ILigne[];
|
passages: ILigne[];
|
||||||
|
stop: IStop;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IAppState {
|
interface IAppState {
|
||||||
passages: ILigne[];
|
tcl?: ITclFilteredApi;
|
||||||
refreshDate?: string;
|
refreshDate?: string;
|
||||||
stations: IVelovStation[];
|
stations: IVelovStation[];
|
||||||
}
|
}
|
||||||
|
@ -21,6 +22,7 @@ class App extends React.Component<{}, IAppState> {
|
||||||
timerId?: ReturnType<typeof setInterval>;
|
timerId?: ReturnType<typeof setInterval>;
|
||||||
refreshSeconds: number;
|
refreshSeconds: number;
|
||||||
monitoredVelovStationIds: string[] = [];
|
monitoredVelovStationIds: string[] = [];
|
||||||
|
monitoredTclStopId: string;
|
||||||
|
|
||||||
constructor(props: {}) {
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -31,26 +33,23 @@ class App extends React.Component<{}, IAppState> {
|
||||||
if (velovStationIds) {
|
if (velovStationIds) {
|
||||||
this.monitoredVelovStationIds = velovStationIds.split(";");
|
this.monitoredVelovStationIds = velovStationIds.split(";");
|
||||||
}
|
}
|
||||||
|
this.monitoredTclStopId = urlParams.get("tclStopId") || "290";
|
||||||
if (this.refreshSeconds <= 5) {
|
if (this.refreshSeconds <= 5) {
|
||||||
this.refreshSeconds = 60;
|
this.refreshSeconds = 60;
|
||||||
}
|
}
|
||||||
this.state = {passages: [{ligne: undefined, delais: [undefined]}], stations: []};
|
this.state = {stations: []};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div>
|
return <div>
|
||||||
<Container className="main">
|
<Container className="main">
|
||||||
<Row sm={2} md={3} className="g-4">
|
<Row sm={2} md={3} className="g-4">
|
||||||
{this.state.passages.map((ligne) => <Tcl key={ligne.ligne} ligne={ligne.ligne}
|
{this.state.tcl?.passages.map((ligne) => <Tcl key={ligne.ligne} {...ligne}/>)}
|
||||||
delais={ligne.delais}/>)}
|
{this.state.stations.map((station) => <Velov key={station.info.station_id} {...station}/>)}
|
||||||
{this.state.stations.map((station) => <Velov key={station.info.station_id} info={station.info} status={station.status}/>)}
|
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<DropdownButton variant="secondary" size="lg" title="Refresh">
|
<Button variant="secondary" size="lg" onClick={this.refreshData}>Refresh</Button>
|
||||||
<Dropdown.Item onClick={this.refreshData}>Data</Dropdown.Item>
|
|
||||||
<Dropdown.Item onClick={this.reload}>Full page</Dropdown.Item>
|
|
||||||
</DropdownButton>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -91,7 +90,7 @@ class App extends React.Component<{}, IAppState> {
|
||||||
private refresh() {
|
private refresh() {
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
headers.set("Authorization", `Basic ${process.env.REACT_APP_TCL_AUTH}`);
|
headers.set("Authorization", `Basic ${process.env.REACT_APP_TCL_AUTH}`);
|
||||||
const tclPromise = http<ITclFilteredApi>("https://tcl.augendre.info/stop/290", {
|
const tclPromise = http<ITclFilteredApi>(`https://tcl.augendre.info/stop/${this.monitoredTclStopId}`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: headers
|
headers: headers
|
||||||
});
|
});
|
||||||
|
@ -126,7 +125,7 @@ class App extends React.Component<{}, IAppState> {
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
refreshDate: new Date().toLocaleString("fr-fr"),
|
refreshDate: new Date().toLocaleString("fr-fr"),
|
||||||
passages: tcl.passages,
|
tcl: tcl,
|
||||||
stations: stations,
|
stations: stations,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
46
src/Tcl.tsx
46
src/Tcl.tsx
|
@ -1,14 +1,20 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
|
||||||
import {faBus} from '@fortawesome/free-solid-svg-icons'
|
import {faBus, faDirections} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
import {faClock} from '@fortawesome/free-regular-svg-icons'
|
||||||
import {Card, Col, ListGroup} from "react-bootstrap";
|
import {Card, Col, ListGroup} from "react-bootstrap";
|
||||||
import {placeholder} from "./utils";
|
|
||||||
|
|
||||||
export type PassageType = string | undefined;
|
export type PassageType = string | undefined;
|
||||||
|
|
||||||
|
export interface IStop {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ILigne {
|
export interface ILigne {
|
||||||
ligne?: string;
|
ligne: string;
|
||||||
delais: PassageType[];
|
delais: PassageType[];
|
||||||
|
destination: IStop;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Tcl extends React.Component<ILigne> {
|
export default class Tcl extends React.Component<ILigne> {
|
||||||
|
@ -16,33 +22,17 @@ export default class Tcl extends React.Component<ILigne> {
|
||||||
return <Col>
|
return <Col>
|
||||||
<Card>
|
<Card>
|
||||||
<Card.Header>
|
<Card.Header>
|
||||||
<FontAwesomeIcon icon={faBus}/> {placeholder(this.props.ligne)}
|
<FontAwesomeIcon icon={faBus}/> {this.props.ligne}
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
<Passages passages={this.props.delais}/>
|
<ListGroup variant="flush">
|
||||||
|
<ListGroup.Item>
|
||||||
|
<FontAwesomeIcon icon={faDirections}/> {this.props.destination.name}
|
||||||
|
</ListGroup.Item>
|
||||||
|
{this.props.delais.map((passage, index) => <ListGroup.Item key={index}>
|
||||||
|
<FontAwesomeIcon icon={faClock}/> {passage}
|
||||||
|
</ListGroup.Item>)}
|
||||||
|
</ListGroup>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPassagesProps {
|
|
||||||
passages: PassageType[];
|
|
||||||
}
|
|
||||||
|
|
||||||
class Passages extends React.Component<IPassagesProps> {
|
|
||||||
render() {
|
|
||||||
return <ListGroup variant="flush">
|
|
||||||
{this.props.passages?.map((passage, index) => <Passage key={index} passage={passage}/>)}
|
|
||||||
</ListGroup>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
interface IPassageProps {
|
|
||||||
passage: PassageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Passage extends React.Component<IPassageProps> {
|
|
||||||
render() {
|
|
||||||
return <ListGroup.Item>{placeholder(this.props.passage)}</ListGroup.Item>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
export function placeholder(value?: string) {
|
|
||||||
if (value === undefined) {
|
|
||||||
return <span className="placeholder"/>
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1254,6 +1254,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@fortawesome/fontawesome-common-types" "^0.2.36"
|
"@fortawesome/fontawesome-common-types" "^0.2.36"
|
||||||
|
|
||||||
|
"@fortawesome/free-regular-svg-icons@^5.15.4":
|
||||||
|
version "5.15.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz#b97edab436954333bbeac09cfc40c6a951081a02"
|
||||||
|
integrity sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==
|
||||||
|
dependencies:
|
||||||
|
"@fortawesome/fontawesome-common-types" "^0.2.36"
|
||||||
|
|
||||||
"@fortawesome/free-solid-svg-icons@^5.15.4":
|
"@fortawesome/free-solid-svg-icons@^5.15.4":
|
||||||
version "5.15.4"
|
version "5.15.4"
|
||||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz#2a68f3fc3ddda12e52645654142b9e4e8fbb6cc5"
|
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz#2a68f3fc3ddda12e52645654142b9e4e8fbb6cc5"
|
||||||
|
|
Loading…
Reference in a new issue