31 Commits

Author SHA1 Message Date
3080359dcd Merge branch 'main' into we-json-examples 2020-12-08 09:38:11 +01:00
3d7e6cf52f Add: json files for scenarios 2020-12-08 09:36:19 +01:00
34f4b8af18 Merge pull request #4 from thefeli73/we-Disruption-base
We disruption base
2020-12-08 09:18:21 +01:00
7c59fa2825 Merge branch 'main' into we-Disruption-base 2020-12-08 09:18:00 +01:00
31263e919e Minor modifications to Example API components and base classes 2020-12-08 09:13:38 +01:00
d40420ad2b Remove irrelevant button errors in console 2020-12-04 12:02:45 +01:00
4ce76dbe90 Merge branch 'aw-disruption-control' into main 2020-12-04 11:53:37 +01:00
051afedcc5 Add user name to navigation drawer 2020-12-04 11:52:41 +01:00
bff5a73c8c Merge branch 'main' into aw-disruption-control 2020-12-04 11:49:28 +01:00
093199d0e0 Add global data variable 2020-12-04 11:48:56 +01:00
25d66f9195 Updated class changes in TrafficEntry 2020-12-04 11:47:42 +01:00
4e36270130 Format TrafficInfo.js 2020-12-04 11:13:55 +01:00
c36d6afea7 Merge to work on aw branch 2020-12-04 10:51:09 +01:00
ff8a87c961 Hack: Nothing is done just commiting to swap branch 2020-12-04 10:45:22 +01:00
c3edd2d74f Add basic component for calls to traffic disruption API 2020-12-04 10:08:11 +01:00
b324250c79 Merge remote-tracking branch 'origin/aw-client-side-classes' into aw-disruption-control 2020-12-04 09:59:51 +01:00
e35524fa19 Merge pull request #3 from williameriksson126/we-AccessToken-class
Add: AccessToken now updated to seperate class
2020-11-30 10:21:10 +01:00
521d3b2e63 Add: AccessToken now updated to seperate class 2020-11-30 10:18:18 +01:00
177bbdf89d Add possibility of closing popups 2020-11-27 17:25:29 +01:00
a1b078f418 Add misc CSS 2020-11-27 17:23:25 +01:00
66dbc66ec4 Add generalized button class 2020-11-27 17:06:14 +01:00
f86b9ee220 Add popup class 2020-11-27 17:04:19 +01:00
daaa9a62f4 Add navigation drawer content and make it expandable 2020-11-27 16:17:56 +01:00
38a6f7c786 Add new color 2020-11-27 16:16:28 +01:00
24dd1361f6 Fix traffic info entries overlapping stop title 2020-11-27 16:16:01 +01:00
e8cfc33991 Add word-break to bottom menu button labels 2020-11-27 16:15:27 +01:00
a1158d4525 Move and rename Disruption 2020-11-27 14:00:05 +01:00
1067277cb8 Allow scroll for entries on traffic info page 2020-11-27 13:58:01 +01:00
a3810491e9 Remove default logo 2020-11-27 13:45:27 +01:00
b8322417a0 Fix some React errors and warnings 2020-11-27 13:43:33 +01:00
fc29d7d327 Non-existing button 2020-11-27 11:41:20 +01:00
42 changed files with 793 additions and 199 deletions

48
package-lock.json generated
View File

@ -3446,6 +3446,15 @@
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
"optional": true
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"optional": true,
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@ -6343,6 +6352,12 @@
}
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"optional": true
},
"filesize": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@ -10133,6 +10148,12 @@
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
},
"nan": {
"version": "2.14.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
"optional": true
},
"nanoid": {
"version": "3.1.16",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.16.tgz",
@ -12255,6 +12276,11 @@
"whatwg-fetch": "^3.4.1"
}
},
"react-axios": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/react-axios/-/react-axios-2.0.3.tgz",
"integrity": "sha512-63kY2iupdRgbvPq9G8xmM0NWUnt2Q5YmpotMoLQsxKOzKXKZg2Lo6CzF/bcZvtmv3WnfjBU6Bg8nZQO28eIAZw=="
},
"react-dev-utils": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.0.tgz",
@ -12360,6 +12386,16 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-native-push-notification": {
"version": "6.1.3",
"resolved": "https://registry.npmjs.org/react-native-push-notification/-/react-native-push-notification-6.1.3.tgz",
"integrity": "sha512-qNbFCkObCXwSFQbK6hJyx1Bym1D7V4XM8iN2L6eL3GAdNLmeBTdLdx3mPbKJtuaDJ1+deniFTQ2rz6hU4ELOXA=="
},
"react-push-notification": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/react-push-notification/-/react-push-notification-1.3.0.tgz",
"integrity": "sha512-hyYKZqwtNOgRP74fAafVIivEr99vUtH0nDgcWkPKd302BhMuUMr5wuuEX236bSbCoM4nxlOge1m0CKIEtWBqLA=="
},
"react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@ -15252,7 +15288,11 @@
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"optional": true
"optional": true,
"requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
}
},
"glob-parent": {
"version": "3.1.0",
@ -15838,7 +15878,11 @@
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"optional": true
"optional": true,
"requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
}
},
"glob-parent": {
"version": "3.1.0",

View File

@ -8,7 +8,10 @@
"@testing-library/user-event": "^12.2.2",
"axios": "^0.21.0",
"react": "^17.0.1",
"react-axios": "^2.0.3",
"react-dom": "^17.0.1",
"react-native-push-notification": "^6.1.3",
"react-push-notification": "^1.3.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.0",
"web-vitals": "^0.2.4"

View File

@ -0,0 +1,15 @@
{
"situationNumber": "RT1",
"severity":"normal",
"title":"Stannar inte på dessa hållplatser",
"affectedStopPoints":[
{
"gid": "9022014014020001",
"name": "Ekelöv västra, Kungälv"
},
{
"gid": "9022014014751001",
"name": "Guddeby, Kungälv"
}
]
}

View File

@ -0,0 +1,11 @@
{
"situationNumber": "RT2",
"severity":"normal",
"title":"Försening",
"affectedStopPoints":[
{
"gid": "9021014014225000",
"name": "Skrämmenborg, Kungälv"
}
]
}

View File

@ -0,0 +1,5 @@
{
"name":"1",
"deviceId":"1",
"location":"9022014014754001"
}

View File

@ -0,0 +1,5 @@
{
"name":"2",
"deviceId":"2",
"location":"9022014014020001"
}

View File

@ -0,0 +1,5 @@
{
"name":"3",
"deviceId":"3",
"location":"9022014014751001"
}

View File

@ -0,0 +1,5 @@
{
"name":"4",
"deviceId":"4",
"location":"9021014014225000"
}

View File

@ -1,39 +1,39 @@
import './variables.css';
import './App.css';
import "./variables.css";
import "./App.css";
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import React, { Component } from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import NavigationDrawer from './components/NavigationDrawer.js'
import BottomMenu from './components/BottomMenu.js'
import AccessToken from './components/AccessToken.js'
import NearbyStation from './components/NearbyStation';
import BottomMenu from "./components/BottomMenu.js";
import NearbyStation from "./components/NearbyStation.js";
import Disruption from "./components/Disruption.js";
import StationDisruption from "./components/StationDisruption.js";
import Tickets from './components/pages/Tickets.js';
import TicketsBuy from './components/pages/TicketsBuy.js';
import Travel from './components/pages/Travel.js';
import TrafficInfo from './components/pages/TrafficInfo.js';
import Tickets from "./components/pages/Tickets.js";
import TicketsBuy from "./components/pages/TicketsBuy.js";
import Travel from "./components/pages/Travel.js";
import TrafficInfo from "./components/pages/TrafficInfo.js";
import "./variables.css";
import './variables.css';
class App extends Component {
render() {
return (
<Router>
<div className="App">
<NavigationDrawer />
render() {
return (
<Router>
<div className="App">
<NearbyStation/>
<Disruption/>
<Route path="/" exact component={TicketsBuy} />
<Route path="/tickets" exact component={Tickets} />
<Route path="/ticketsBuy" exact component={TicketsBuy} />
<Route path="/travel" exact component={Travel} />
<Route path="/traffic" exact component={TrafficInfo} />
<Route path="/" exact component={TicketsBuy} />
<Route path="/tickets" exact component={Tickets} />
<Route path="/ticketsBuy" exact component={TicketsBuy} />
<Route path="/travel" exact component={Travel} />
<Route path="/traffic" exact component={TrafficInfo} />
<BottomMenu />
</div>
</Router>
);
}
<BottomMenu />
</div>
</Router>
);
}
}
export default App;

12
src/GlobalData.js Normal file
View File

@ -0,0 +1,12 @@
import User from './classes/User.js';
import Coordinates from "./classes/Coordinates.js";
let globalData = {
user: new User(
"test",
"123",
new Coordinates()
)
};
export default globalData;

View File

@ -0,0 +1,21 @@
import axios from 'axios';
class AccessToken {
credentials = 'NXR5N2d4bUFmUWxVSERIZG03a2dhcVh3SzVJYTp3cElPVVJuSkpjVHRPNnJPUlltWVlQcTR3WGth'
device = '123'
constructor() {
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + this.credentials
};
axios.post('https://api.vasttrafik.se/token','grant_type=client_credentials&scope=device_'+this.device, {headers} )
.then(response => {
console.log(response);
this.token = response.data.access_token
});
}
}
export default AccessToken

View File

@ -12,4 +12,4 @@ class Coordinates {
}
}
export default Coordinates;
export default Coordinates;

24
src/classes/Disruption.js Normal file
View File

@ -0,0 +1,24 @@
/*
Denna klass är en modell för störningar.
*/
class Disruption {
constructor(startTime, locations, departures) {
this.startTime = startTime;
this.affectedLines = affectedLines;
this.departures = departures;
}
}
/*
Från västtrafiks api ett element i listan av hållplatser ser ut som följande
"id": "string",
"lon": "string",
"idx": "string",
"weight": "string",
"name": "string",
"track": "string",
"lat": "string"
*/
export default Disruption;

View File

@ -14,4 +14,15 @@ class Stop {
}
}
/*
Från västtrafiks api ett element i listan av hållplatser ser ut som följande
"id": "string",
"lon": "string",
"idx": "string",
"weight": "string",
"name": "string",
"track": "string",
"lat": "string"
*/
export default Stop;

View File

@ -1,14 +1,17 @@
/*
Denna klass är en modell för användare.
deviceId : String (Enhetens ID)
name : String (Användarnamn)
deviceId : Int (Enhetens ID)
location : Coordinates (Användarens koordinater)
*/
class User {
constructor(deviceId, location) {
constructor(name, deviceId, location) {
this.name = name;
this.deviceId = deviceId;
this.location = location;
this.stoppointgid = stoppointgid;
}
}

11
src/classes/disruption.js Normal file
View File

@ -0,0 +1,11 @@
class Disruption {
constructor(situationNumber, severity, title, affectedStopPoints) {
this.situationNumber = situationNumber;
this.severity = severity;
this.title = title;
this.affectedStopPoints = affectedStopPoints;
}
}
export default User;

View File

@ -1,65 +0,0 @@
import React from 'react';
import axios from 'axios';
var globToken = ''
const GetToken = () => {
const vars = {
credentials: 'NXR5N2d4bUFmUWxVSERIZG03a2dhcVh3SzVJYTp3cElPVVJuSkpjVHRPNnJPUlltWVlQcTR3WGth',
token: undefined,
device: '123',
}
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + vars.credentials
};
axios.post('https://api.vasttrafik.se/token','grant_type=client_credentials&scope=device_'+vars.device, { headers })
.then(response => {
console.log(response);
globToken = response.data.access_token
});
}
class AccessToken extends React.Component {
state = {
token: 'No Token',
}
handleChange = event => {
this.setState({ token: event.target.value});
}
handleSubmit = event => {
event.preventDefault();
this.setState({
credentials: 'Attempting to send token'
});
GetToken();
}
handleFetch = event => {
event.preventDefault();
this.setState({token: globToken})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<button type="submit">Get Token</button>
</form>
<h1>
{this.state.token}
</h1>
<form onSubmit={this.handleFetch}>
<button type="submit">fetch</button>
</form>
</div>
)
}
}
export default AccessToken

View File

@ -1,14 +1,30 @@
import React, {Component} from 'react';
import React, { Component } from 'react';
import './css/Button.css';
class Button extends Component {
render() {
// Multiple onClick functions
onClick = () => {
if (this.props.onClick !== null
&& this.props.onClick !== undefined) {
if (Array.isArray(this.props.onClick)) {
this.props.onClick.forEach(func => {
func();
});
} else {
console.log("Error when parsing Button onClick functions.");
}
}
}
render() {
return (
<a href={this.props.destination}>
{this.props.title}
</a>
<button className={this.props.className} onClick={this.onClick}>
{this.props.children}
</button>
);
}
}
// TODO Add css
export default Button
export default Button;

View File

@ -0,0 +1,60 @@
import React from 'react';
import axios from 'axios';
import AccessToken from '../classes/AccessToken'
class Diruption extends React.Component {
state = {
gid: '9022014005700002',
disruptions: [],
token: undefined,
tokenClass: new AccessToken()
}
handleChangeGid = event => {
this.setState({ lat: event.target.value});
}
handleSubmit = event => {
event.preventDefault();
const headers = {
'Authorization': 'Bearer ' + this.state.tokenClass.token
};
console.log('Attempted connection')
axios.get('https://api.vasttrafik.se/ts/v1/traffic-situations/stoppoint/'+this.state.gid, { headers })
//axios.get('https://api.vasttrafik.se/ts/v1/traffic-situations/stoppoint/9022014005700002', { headers })
.then(response => {
console.log(response)
this.setState({
disruptions: response.data
})
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Stoppoint Gid:
<input type="text" name="gid" onChange={this.handleChangeGid} />
</label>
<button type="submit">Find traffic disruptions</button>
</form>
<h1>
{this.state.gid}
</h1>
{this.state.disruptions.map((item) =>
<div>
<h1>
{item.description}
</h1>
</div>
)}
</div>
)
}
}
export default Diruption

View File

@ -0,0 +1,29 @@
import addNotification from "react-push-notification";
import Button from './Button.js';
import disruptIcon from '../img/flash.svg';
class DisruptionButton extends Button {
genDisrupt = () => {
addNotification({
title: "Warning",
subtitle: "This is a subtitle",
message: "This is a very long message",
theme: "blue",
native: true, // when using native, your OS will handle theming.
});
}
render() {
return (
<Button onClick={this.props.onClick.concat([this.genDisrupt])} className="disruptBtn">
<img src={disruptIcon} alt="" />
<span>Generera Störning</span>
</Button>
);
}
}
export default DisruptionButton;

View File

@ -1,14 +1,31 @@
import React, { Component } from 'react';
import NavigationDrawer from './NavigationDrawer.js';
import './css/Header.css';
import navIcon from '../img/menu.svg'
class Header extends Component {
constructor(props) {
super(props);
this.navDrawerElem = React.createRef();
}
handleClick = () => {
this.navDrawerElem.current.toggle();
};
render() {
return (
<header>
<button id="navBtn"><img src={navIcon} /></button>
<h1 id="pageTitle">{this.props.title}</h1>
</header>
<>
<NavigationDrawer ref={this.navDrawerElem} />
<header>
<button id="navBtn"><img src={navIcon} alt="" onClick={this.handleClick} /></button>
<h1 id="pageTitle">{this.props.title}</h1>
</header>
</>
);
}
}

View File

@ -1,20 +1,21 @@
import React, { Component } from 'react';
import Button from './Button.js';
class MenuButton extends Component {
class MenuButton extends Button {
render() {
if (this.props.childOrderReverse) {
return (
<button>
<Button>
<span>{this.props.label}</span>
<img src={this.props.icon}/>
</button>
<img src={this.props.icon} alt="" />
</Button>
);
} else {
return (
<button>
<img src={this.props.icon}/>
<Button>
<img src={this.props.icon} alt="" />
<span>{this.props.label}</span>
</button>
</Button>
);
}
}

View File

@ -1,10 +1,75 @@
import './css/NavigationDrawer.css';
import React, { Component } from 'react';
import globalData from '../GlobalData.js';
import DisruptionButton from "./DisruptionButton.js";
import Popup from './Popup.js';
import Button from './Button.js';
import './css/NavigationDrawer.css';
import userIcon from '../img/user.svg';
class NavigationDrawer extends Component {
constructor(props) {
super(props);
this.popupElem = React.createRef();
}
state = {
open: false
};
toggle = () => {
if (this.state.open)
this.close();
else
this.open();
};
open = () => {
this.setState({
open: true
});
};
close = () => {
this.setState({
open: false
});
};
showPopup = () => {
this.popupElem.current.show();
};
render() {
return (
<div id="navDrawer"></div>
<>
<Popup ref={this.popupElem}>
<h3>Välj hållplats:</h3>
<ul>
<li><Button>Hållplats 1</Button></li>
<li><Button>Hållplats 2</Button></li>
<li><Button>Hållplats 3</Button></li>
<li><Button>Hållplats 4</Button></li>
</ul>
</Popup>
<div id="navDrawer" className={`${this.state.open ? "open" : ""}`}>
<header>
<img src={userIcon} alt="" />
<span>{globalData.user.name}</span>
<span>example@gmail.com</span>
</header>
<div id="navList">
<DisruptionButton onClick={[this.showPopup, this.close]} />
</div>
<hr />
<span id="version">Projektgrupp 3 - Utmaning 7</span>
</div>
<div id="clickArea" className={`${this.state.open ? "" : "hidden"}`} onClick={this.close} />
</>
);
}
}

View File

@ -1,5 +1,8 @@
import React from 'react';
import axios from 'axios';
import AccessToken from '../classes/AccessToken';
import StopComponent from './StopComponent';
import Stop from '../classes/Stop';
class NearbyStation extends React.Component {
state = {
@ -7,7 +10,7 @@ class NearbyStation extends React.Component {
long: '12.0',
stops: [],
token: undefined,
device: '123',
tokenClass: new AccessToken()
}
handleChangeLat = event => {
@ -18,20 +21,16 @@ class NearbyStation extends React.Component {
this.setState({ long: event.target.value});
}
handleChangeToken = event => {
this.setState({ token: event.target.value})
}
handleSubmit = event => {
event.preventDefault();
const headers = {
'Authorization': 'Bearer ' + this.state.token
'Authorization': 'Bearer ' + this.state.tokenClass.token
};
console.log('Attempted connection')
axios.get('https://api.vasttrafik.se/bin/rest.exe/v2/location.nearbystops?originCoordLat='+this.state.lat+'&originCoordLong='+this.state.long+'&maxNo=20&format=json', { headers })
axios.get('https://api.vasttrafik.se/bin/rest.exe/v2/location.nearbystops?originCoordLat='+this.state.lat+'&originCoordLong='+this.state.long+'&maxNo=5&format=json', { headers })
.then(response => {
console.log(response.data.LocationList.StopLocation)
this.setState({
@ -52,10 +51,6 @@ class NearbyStation extends React.Component {
Longitude coord:
<input type="text" name="long" onChange={this.handleChangeLong} />
</label>
<label>
Token:
<input type="text" name="token" onChange={this.handleChangeToken} />
</label>
<button type="submit">Stops</button>
</form>
<h1>
@ -65,32 +60,11 @@ class NearbyStation extends React.Component {
{this.state.long}
</h1>
{this.state.stops.map((item) =>
<div>
<h1>
{item.name},
{item.id},
{item.lat},
{item.lon},
{item.track}
</h1>
</div>
<StopComponent stop={item} />
)}
</div>
)
}
}
export default NearbyStation
//https://api.vasttrafik.se/bin/rest.exe/v2/location.nearbystops?originCoordLat=57.5987&originCoordLong=11.9454&maxNo=20&format=json
//https://api.vasttrafik.se/bin/rest.exe/v2/location.nearbystops
//'https://reqres.in/api/articles'
//'https://api.vasttrafik.se/token'
//grant_type=client_credentials&scope=<device_id>
//BPvMjPidHckBtETZxr3dHP1rptQa
//z5MFCS_wwmqprc0s4iLZWBAUJdga

36
src/components/Popup.js Normal file
View File

@ -0,0 +1,36 @@
import React, { Component } from 'react';
import './css/Popup.css';
class Popup extends Component {
state = {
visible: false
};
show = () => {
this.setState({
visible: true
});
};
hide = () => {
this.setState({
visible: false
});
};
render() {
return (
<>
<div className={`${this.state.visible ? "" : "hidden"}` + " popupClose"} onClick={this.hide} />
<div className={`${this.state.visible ? "visible" : ""}` + " popup " + this.props.className}>
{this.props.children}
</div>
</>
);
}
}
export default Popup;

View File

@ -0,0 +1,64 @@
import React from 'react';
import axios from 'axios';
import AccessToken from '../classes/AccessToken'
class StationDisruption extends React.Component {
state = {
gid: '9022014005700002',
lat: '57.7',
long: '12.0',
disruptions: [],
token: undefined,
tokenClass: new AccessToken()
}
handleChangeGid = event => {
this.setState({ lat: event.target.value});
}
handleSubmit = event => {
event.preventDefault();
const headers = {
'Authorization': 'Bearer ' + this.state.tokenClass.token
};
console.log('Attempted connection')
axios.get('https://api.vasttrafik.se/bin/rest.exe/v2/location.nearbystops?originCoordLat='+this.state.lat+'&originCoordLong='+this.state.long+'&maxNo=5&format=json', { headers })
.then(response => {
console.log(response.data.LocationList.StopLocation)
})
axios.get('https://api.vasttrafik.se/ts/v1/traffic-situations/stoppoint/'+this.state.gid, { headers })
.then(response => {
console.log(response)
this.setState({
disruptions: response.data
})
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Stoppoint Gid:
<input type="text" name="gid" onChange={this.handleChangeGid} />
</label>
<button type="submit">Find traffic disruptions</button>
</form>
<h1>
{this.state.gid}
</h1>
{this.state.disruptions.map((item) =>
<div>
<h1>
{item.description}
</h1>
</div>
)}
</div>
)
}
}
export default StationDisruption

View File

@ -0,0 +1,19 @@
import React, {Component} from 'react';
class StopComponent extends Component {
render() {
return (
<div>
<h1>
{this.props.stop.name},
{this.props.stop.id},
{this.props.stop.lat},
{this.props.stop.lon},
{this.props.stop.track}
</h1>
</div>
);
}
}
// TODO Add css
export default StopComponent

View File

@ -7,29 +7,27 @@ import warningIcon from '../img/warning.svg';
class TrafficEntry extends Component {
render() {
let trafficInfo = this.props.departure.info;
let lineInterference = trafficInfo != "" && trafficInfo != null;
let infoElem = <></>;
if (trafficInfo != "" && trafficInfo != null)
infoElem = <p>{trafficInfo} <u>Visa mer</u></p>
let trafficInfo = this.props.departure.trafficInfo;
let lineInterference = trafficInfo !== "" && trafficInfo !== null && trafficInfo !== undefined;
return (
<div class="trafficEntry">
<div className="trafficEntry">
<div>
<div class="timeColumn">
<div className="timeColumn">
<span>{this.props.departure.time}</span>
{lineInterference &&
<img src={warningIcon}></img>
<img src={warningIcon} alt=""></img>
}
</div>
<div class="lineColumn">
<div className="lineColumn">
<div>
<span class="lineName">{this.props.departure.lineName}</span>
<img src={busIcon}></img>
<span class="destination">{this.props.departure.destination}</span>
<span className="lineName">{this.props.departure.lineName}</span>
<img src={busIcon} alt=""></img>
<span className="destination">{this.props.departure.finalStop}</span>
</div>
{infoElem}
{lineInterference &&
<p>{trafficInfo} <u>Visa mer</u></p>
}
</div>
</div>

View File

@ -8,18 +8,20 @@ class TrafficList extends Component {
render() {
let entries = [];
let i = 0; // React requires elems in array to have associated unique key
this.props.departures.forEach(departure => {
entries.push(
<TrafficEntry departure={departure} />
<TrafficEntry key={i++} departure={departure} />
);
});
// Add separator between every element
const intersperse = (arr, sep) => arr.reduce((a,v)=>[...a,v,sep],[]).slice(0,-1);
entries = intersperse(entries, (<hr />));
entries = intersperse(entries, (<hr key={i++} />));
// Add separator after the last element
entries.push(<hr />);
entries.push(<hr key={i++} />);
return (
<div id="trafficList">

View File

@ -7,7 +7,7 @@ class TripSelector extends Component {
<label>Från:</label>
<input type="text" placeholder="Hållplats/Adress/Plats" />
<hr/>
<label for="lname">Till:</label>
<label>Till:</label>
<input type="text" placeholder="Hållplats/Adress/Plats" />
</form>
);

View File

@ -22,6 +22,7 @@
flex-direction: column;
align-items: center;
justify-content: space-evenly;
word-break: break-word;
}
#bottomMenu button:active {

View File

@ -0,0 +1,3 @@
button:active {
background: rgba(0, 0, 0, 0.1);
}

View File

@ -4,4 +4,5 @@ main {
display: flex;
flex-flow: column;
justify-content: space-evenly;
overflow: hidden scroll;
}

View File

@ -0,0 +1,83 @@
#navDrawer {
width: 70vw;
height: 100%;
position: fixed;
top: 0;
left: -70vw;
background: white;
overflow: hidden;
z-index: 10;
transition: .35s;
display: flex;
flex-flow: column;
}
.open {
left: 0 !important;
}
#navDrawer header {
width: 100%;
padding: 4vh 0;
color: white;
font-size: 16px;
flex-basis: 15vh;
flex-direction: column;
justify-content: space-evenly;
}
#navDrawer header img {
width: 35px;
}
#navList {
flex-basis: 70vh;
display: flex;
flex-flow: column;
align-items: flex-start;
}
.disruptBtn {
height: 50px;
width: 100%;
padding: 0 0 0 5vw;
display: flex;
align-items: center;
align-self: flex-start;
font-size: 14px;
}
.disruptBtn:active {
background: rgba(0, 0, 0, 0.1);
}
.disruptBtn img {
height: 55%;
margin-right: 10px;
}
#clickArea {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.75);
position: fixed;
z-index: 5;
transition: .15s;
}
#navDrawer hr {
width: 90%;
margin: 0 10px 5px 0;
align-self: flex-end;
opacity: 0.5;
flex-basis: auto;
}
#version {
align-self: flex-end;
margin-right: 10px;
font-size: 14px;
color: var(--colorDiscrete);
min-height: 50px;
}

View File

@ -0,0 +1,44 @@
.popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
transform-origin: center;
background: white;
width: 55vw;
height: 39vh;
padding: 3vh 5vw;
box-shadow: var(--boxShadow);
border-radius: var(--borderRadius);
transition: .35s;
z-index: 11;
}
.visible {
pointer-events: all;
transform: translate(-50%, -50%) scale(1);
}
.popup h3 {
margin-bottom: 20px;
}
.popup ul {
list-style: none;
}
.popup li button {
width: 100%;
padding: 8% 0;
font-size: 16px;
}
.popupClose {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.75);
z-index: 11;
}

View File

@ -7,6 +7,7 @@
flex-direction: column;
justify-content: space-evenly;
padding: 0 5vw;
z-index: 4;
}
#stopTitle h1, #stopTitle h3 {
@ -19,7 +20,7 @@
}
#stopTitle h3 {
color: rgba(0, 0, 0, 0.4);
color: var(--colorDiscrete);
}
#stopTitle button {

View File

@ -1,25 +1,30 @@
import React, { Component } from 'react';
import React, { Component } from "react";
import Header from '../Header.js';
import TopMenu from '../TopMenu.js';
import MainArea from '../MainArea.js';
import StopTitle from '../StopTitle.js';
import TrafficList from '../TrafficList.js';
import Header from "../Header.js";
import TopMenu from "../TopMenu.js";
import MainArea from "../MainArea.js";
import StopTitle from "../StopTitle.js";
import TrafficList from "../TrafficList.js";
import Stop from "../../classes/Stop.js";
import Departure from "../../classes/Departure.js";
import Stop from '../../classes/Stop.js';
import Departure from '../../classes/Departure.js';
class TrafficInfo extends Component {
render() {
let testStop =
new Stop(
"Lemmingsgatan",
["Läge A", "Läge B", "Läge C"],
[
new Departure("519", "Mot Heden", "11:59", "Trafikolycka vid Partille Centrum."),
new Departure("58", "Mot Västra Eriksberg", "12:07")
],
);
let testStop = new Stop(
"Lemmingsgatan",
["Läge A", "Läge B", "Läge C"],
[
new Departure(
"519",
"Mot Heden",
"11:59",
"Trafikolycka vid Partille Centrum."
),
new Departure("58", "Mot Västra Eriksberg", "12:07"),
]
);
return (
<>
@ -35,4 +40,4 @@ class TrafficInfo extends Component {
}
}
export default TrafficInfo;
export default TrafficInfo;

44
src/img/flash.svg Normal file
View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M400.268,175.599c-1.399-3.004-4.412-4.932-7.731-4.932h-101.12l99.797-157.568c1.664-2.628,1.766-5.956,0.265-8.678
C389.977,1.69,387.109,0,384.003,0H247.47c-3.234,0-6.187,1.826-7.637,4.719l-128,256c-1.323,2.637-1.178,5.777,0.375,8.294
c1.562,2.517,4.301,4.053,7.262,4.053h87.748l-95.616,227.089c-1.63,3.883-0.179,8.388,3.413,10.59
c1.382,0.845,2.918,1.254,4.446,1.254c2.449,0,4.864-1.05,6.537-3.029l273.067-324.267
C401.206,182.161,401.667,178.611,400.268,175.599z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1005 B

22
src/img/user.svg Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 460.8 460.8" style="enable-background:new 0 0 460.8 460.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<g>
<path class="st0" d="M230.4,0c-65.8,0-119.6,53.8-119.6,119.6s53.8,119.6,119.6,119.6s119.6-53.8,119.6-119.6S296.3,0,230.4,0z"/>
</g>
</g>
<g>
<g>
<path class="st0" d="M435.8,334.9c-3.1-7.8-7.3-15.2-12-21.9c-24-35.5-61.1-59-102.9-64.8c-5.2-0.5-11,0.5-15.2,3.7
c-21.9,16.2-48.1,24.6-75.2,24.6s-53.3-8.4-75.2-24.6c-4.2-3.1-9.9-4.7-15.2-3.7c-41.8,5.7-79.4,29.3-102.9,64.8
c-4.7,6.8-8.9,14.6-12,21.9c-1.6,3.1-1,6.8,0.5,9.9c4.2,7.3,9.4,14.6,14.1,20.9c7.3,9.9,15.2,18.8,24,27.2
c7.3,7.3,15.7,14.1,24,20.9c41.3,30.8,90.9,47,142.1,47s100.8-16.2,142.1-47c8.4-6.3,16.7-13.6,24-20.9c8.4-8.4,16.7-17.2,24-27.2
c5.2-6.8,9.9-13.6,14.1-20.9C436.8,341.7,437.3,338,435.8,334.9z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -27,4 +27,9 @@ html, body, #root, #app {
button {
background: none;
border: none;
}
.hidden {
opacity: 0;
pointer-events: none;
}

View File

@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -3,6 +3,7 @@
--colorVT2: rgb(25, 212, 245);
--colorBg: rgb(240, 248, 250);
--colorLine: rgb(0, 108, 144);
--colorDiscrete: rgba(0, 0, 0, 0.4);
--topMenuHeight: 15vh;
--borderRadius: calc(var(--topMenuHeight) / 15);