47 Commits

Author SHA1 Message Date
5c59866dc4 Add: More progress regarding findstops button 2020-12-10 09:56:24 +01:00
d304b250a2 Add: Json files for nearby busstops and a component for accessing said json files 2020-12-09 17:54:28 +01:00
68b6e4e836 Polish and button functionality for traffic info page 2020-12-08 12:28:33 +01:00
3accd7806a Add help message for button errors 2020-12-08 12:28:32 +01:00
b207b464bd Merge pull request #9 from thefeli73/we-select-user
Add: Multiple disruptions
2020-12-08 12:10:51 +01:00
2d2ec96533 Add: Multiple disruptions 2020-12-08 12:10:08 +01:00
359c0a8192 Merge pull request #8 from thefeli73/we-select-user
Add: Select user buttons
2020-12-08 11:55:46 +01:00
3c0fc6fe1f Add: Select user buttons 2020-12-08 11:54:34 +01:00
c7517f185c Merge pull request #7 from thefeli73/we-fix-broken-git
We fix broken git
2020-12-08 10:43:20 +01:00
d39f114d5c Fix 2of2 2020-12-08 10:42:50 +01:00
a0ff50ab23 Fix 1of2 2020-12-08 10:41:31 +01:00
ca1ca3884d Merge pull request #6 from thefeli73/we-demo-disruption-first
Add: code to fetch disruption data and see if it is relevant
2020-12-08 10:30:41 +01:00
ea2a18f3ad Add: code to fetch disruption data and see if it is relevant 2020-12-08 10:29:03 +01:00
75b4ecc4ed Merge pull request #5 from thefeli73/we-json-examples
Add: json files for scenarios
2020-12-08 09:38:22 +01:00
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
3bc1ff9a1a Add and update classes for client-side data management 2020-11-27 17:32:35 +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
87f9661993 Merge pull request #2 from williameriksson126/we-VT-API-Access-Token-tests
We vt api access token tests
2020-11-27 09:43:58 +01:00
58 changed files with 1290 additions and 257 deletions

View File

@ -25,20 +25,37 @@ Tutorials för React går att hitta [här](https://www.youtube.com/playlist?list
* ``public/index.html`` är den enda HTML-fil vi kommer ha i appen, detta eftersom vi bygger en s.k. SPA (Single Page Application). Man ändrar oftast inget i denna fil utöver möjligtvis innehållet i ``<head>``, detta eftersom React hanterar hela vårt UI.
* Ursprungspunkten för React är ``src/index.js``.
<!--
## Upplägg
``` mermaid
```mermaid
classDiagram
class User
User : String deviceId
User : Coordinates location
User : nearbyStops()
class User
User : Subscription[] subs
User : Location loc
class Coordinates
Coordinates : Float lon
Coordinates : Float lat
class Line
class Stop
Stop : String name
Stop : Track[] locations
Stop : Departure[] departures
class Subscription
Subscription : Line line
class Departure
Departure : String lineName
Departure : Stop finalStop
Departure : String time
Departure : String trafficInfo
```
-->
class Track
Track : String name
User <.. Coordinates
User <.. Stop
Stop <.. Departure
Departure <.. Stop
Stop <.. Track
```

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,36 @@
{
"LocationList": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestLocation.xsd",
"servertime": "16:48",
"serverdate": "2020-12-09",
"StopLocation": [
{
"name": "Bollestadsvägen, Kungälv",
"id": "9022014014754001",
"lat": "57.888940",
"lon": "11.885663",
"track": "A"
},
{
"name": "Bollestadsvägen, Kungälv",
"id": "9021014014754000",
"lat": "57.889030",
"lon": "11.885708"
},
{
"name": "Bollestadsvägen, Kungälv",
"id": "9022014014754002",
"lat": "57.889111",
"lon": "11.885753",
"track": "B"
},
{
"name": "Bredsten, Kungälv",
"id": "9022014014753002",
"lat": "57.886450",
"lon": "11.889529",
"track": "B"
}
]
}
}

View File

@ -0,0 +1,36 @@
{
"LocationList": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestLocation.xsd",
"servertime": "16:47",
"serverdate": "2020-12-09",
"StopLocation": [
{
"name": "Ekelöv västra, Kungälv",
"id": "9022014014020001",
"lat": "57.892527",
"lon": "11.865321",
"track": "A"
},
{
"name": "Ekelöv västra, Kungälv",
"id": "9021014014020000",
"lat": "57.892608",
"lon": "11.865312"
},
{
"name": "Ekelöv västra, Kungälv",
"id": "9022014014020002",
"lat": "57.892689",
"lon": "11.865285",
"track": "B"
},
{
"name": "Ekelöv östra, Kungälv",
"id": "9022014014021002",
"lat": "57.892994",
"lon": "11.873923",
"track": "B"
}
]
}
}

View File

@ -0,0 +1,36 @@
{
"LocationList": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestLocation.xsd",
"servertime": "16:45",
"serverdate": "2020-12-09",
"StopLocation": [
{
"name": "Guddeby, Kungälv",
"id": "9022014014751001",
"lat": "57.874665",
"lon": "11.903884",
"track": "A"
},
{
"name": "Guddeby, Kungälv",
"id": "9021014014751000",
"lat": "57.874710",
"lon": "11.903929"
},
{
"name": "Guddeby, Kungälv",
"id": "9022014014751002",
"lat": "57.874746",
"lon": "11.903965",
"track": "B"
},
{
"name": "Stället, Kungälv",
"id": "9022014014744001",
"lat": "57.869784",
"lon": "11.904172",
"track": "A"
}
]
}
}

View File

@ -0,0 +1,35 @@
{
"LocationList": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestLocation.xsd",
"servertime": "16:44",
"serverdate": "2020-12-09",
"StopLocation": [
{
"name": "Skrämmenborg, Kungälv",
"id": "9021014014225000",
"lat": "57.863528",
"lon": "11.867406"
},
{
"name": "Skrämmenborg, Kungälv",
"id": "9022014014225001",
"lat": "57.863528",
"lon": "11.867406",
"track": "A"
},
{
"name": "Kuröd, Kungälv",
"id": "9022014014762002",
"lat": "57.856966",
"lon": "11.863774",
"track": "B"
},
{
"name": "Kuröd, Kungälv",
"id": "9021014014762000",
"lat": "57.856831",
"lon": "11.864260"
}
]
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,39 +1,37 @@
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">
<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;

19
src/GlobalData.js Normal file
View File

@ -0,0 +1,19 @@
import User from './classes/User.js';
import Disruption from './classes/Disruption.js'
import Coordinates from './classes/Coordinates.js';
import Stop from './classes/Stop.js'
let globalData = {
user: new User(
"test",
"123",
new Coordinates(),
"9022014014020001"
),
disruption: new Disruption(
),
stop: new Stop(
)
};
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

@ -0,0 +1,15 @@
/*
Denna klass är en modell för platskoordinater.
lon : Float (Longitud)
lat : Float (Latitud)
*/
class Coordinates {
constructor(lon, lat) {
this.lon = lon;
this.lat = lat;
}
}
export default Coordinates;

View File

@ -2,17 +2,22 @@
Denna klass är en modell för avgångar.
lineName : String (Linjenamnet)
destination : String (Exempelvis "Mot Heden")
time : String (Avgångstid)
info : String (Trafikinformation)
finalStop : Stop (Ändhållplats)
originalTime : String (Ursprunglig Avgångstid)
newTime : String (Ny Avgångstid)
trafficInfo : String (Trafikinformation)
*/
class Departure {
constructor(lineName, destination, time, info) {
constructor(lineName, finalStop, originalTime, trafficInfo) {
this.lineName = lineName;
this.destination = destination;
this.time = time;
this.info = info;
this.finalStop = finalStop;
this.originalTime = originalTime;
this.trafficInfo = trafficInfo;
}
timeUpdate(time) {
this.newTime = time;
}
}

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 Disruption;

View File

@ -2,16 +2,30 @@
Denna klass är en modell för hållplatser.
name : String (Hållplatsens namn)
locations : String[] (Möjliga lägen)
locations : Track[] (Möjliga lägen)
departures : Departure[] (Avgångar från hållplatsen)
*/
class Stop {
constructor(name, locations, departures) {
constructor(name, id, lat, lon, locations, departures) {
this.name = name;
this.id = id;
this.lat = lat;
this.lon = lon;
this.locations = locations;
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 Stop;

13
src/classes/Track.js Normal file
View File

@ -0,0 +1,13 @@
/*
Denna klass är en modell för hållplatslägen, ex. "Läge A" eller "Spår 3".
name : String (Lägets namn)
*/
class Track {
constructor(name) {
this.name = name;
}
}
export default Track;

18
src/classes/User.js Normal file
View File

@ -0,0 +1,18 @@
/*
Denna klass är en modell för användare.
name : String (Användarnamn)
deviceId : Int (Enhetens ID)
location : Coordinates (Användarens koordinater)
*/
class User {
constructor(name, deviceId, location, stoppointgid) {
this.name = name;
this.deviceId = deviceId;
this.location = location;
this.stoppointgid = stoppointgid;
}
}
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. Make sure the functions are passed as an array.");
}
}
}
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,57 @@
import addNotification from "react-push-notification";
import globData from '../GlobalData.js';
import ex1 from '../APIexamples/disruption1.json'
import ex2 from '../APIexamples/disruption2.json'
import Button from './Button.js';
import disruptIcon from '../img/flash.svg';
class DisruptionButton extends Button {
state = {
jsonLocation: this.props.path,
disruption: ""
}
genDisrupt = () => {
this.state.disruption = ""
if(this.state.jsonLocation === "ex1"){
for (let stopPoint of ex1.affectedStopPoints) {
if(stopPoint.gid === globData.user.stoppointgid){
this.state.disruption = ex1
}
}
} else if (this.state.jsonLocation === "ex2"){
for (let stopPoint of ex2.affectedStopPoints) {
if(stopPoint.gid === globData.user.stoppointgid){
this.state.disruption = ex2
}
}
}
console.log(this.state.disruption)
globData.disruption = this.state.disruption
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

@ -0,0 +1,45 @@
import globData from '../GlobalData.js';
import locationuser1 from '../APIexamples/locationuser1.json'
import locationuser2 from '../APIexamples/locationuser2.json'
import locationuser3 from '../APIexamples/locationuser3.json'
import locationuser4 from '../APIexamples/locationuser4.json'
import StopSelectButton from './StopSelectButton.js';
import Button from './Button.js';
import disruptIcon from '../img/flash.svg';
class FindStops extends Button {
state = {
locations : []
}
findStops = () => {
if(globData.user.deviceId === "1"){
this.state.locations = locationuser1.LocationList.StopLocation
}else if (globData.user.deviceId === "2"){
this.state.locations = locationuser2.LocationList.StopLocation
}else if (globData.user.deviceId === "3"){
this.state.locations = locationuser3.LocationList.StopLocation
}else if (globData.user.deviceId === "4"){
this.state.locations = locationuser4.LocationList.StopLocation
}
}
render() {
return (
<>
<Button onClick={[this.findStops]} className="disruptBtn">
<img src={disruptIcon} alt="" />
<span>Select nearby stops</span>
</Button>
{this.state.locations.map((item) =>
<StopSelectButton stop={item}/>
)}
</>
);
}
}
export default FindStops;

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

@ -5,7 +5,7 @@ import './css/MainArea.css';
class MainArea extends Component {
render() {
return (
<main>
<main style={this.props.style}>
{this.props.children}
</main>
);

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,83 @@
import './css/NavigationDrawer.css';
import React, { Component } from 'react';
import globalData from '../GlobalData.js';
import DisruptionButton from "./DisruptionButton.js";
import SelectUserButton from "./SelectUserButton.js"
import Popup from './Popup.js';
import Button from './Button.js';
import './css/NavigationDrawer.css';
import userIcon from '../img/user.svg';
import FindStops from './FindStops.js';
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">
<SelectUserButton path={"user1"} username="user1"/>
<SelectUserButton path={"user2"} username="user2"/>
<SelectUserButton path={"user3"} username="user3"/>
<SelectUserButton path={"user4"} username="user4"/>
<FindStops/>
<DisruptionButton path={"ex1"} onClick={[this.showPopup, this.close]} />
<DisruptionButton path={"ex2"} 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,36 @@
import globData from '../GlobalData.js';
import user1 from '../APIexamples/user1.json'
import user2 from '../APIexamples/user2.json'
import user3 from '../APIexamples/user3.json'
import user4 from '../APIexamples/user4.json'
import Button from './Button.js';
import disruptIcon from '../img/flash.svg';
class SelectUserButton extends Button {
selectUser = () => {
if(this.props.path === "user1"){
globData.user = user1
}else if (this.props.path === "user2"){
globData.user = user2
}else if (this.props.path === "user3"){
globData.user = user3
}else if (this.props.path === "user4"){
globData.user = user4
}
}
render() {
return (
<Button onClick={[this.selectUser]} className="disruptBtn">
<img src={disruptIcon} alt="" />
<span>{this.props.username}</span>
</Button>
);
}
}
export default SelectUserButton;

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

@ -0,0 +1,22 @@
import React, {Component} from 'react';
import globalData from '../GlobalData';
import Button from './Button.js';
class StopSelectButton extends Component {
selectStop = () => {
globalData.stop = this.props.stop
}
render() {
return (
<>
<Button onClick={[this.selectStop]}>
<span>{this.props.stop.name}</span>
</Button>
</>
);
}
}
// TODO Add css
export default StopSelectButton

View File

View File

@ -1,4 +1,5 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import './css/TrafficInfo.css';
@ -6,35 +7,71 @@ import busIcon from '../img/bus.svg';
import warningIcon from '../img/warning.svg';
class TrafficEntry extends Component {
render() {
let trafficInfo = this.props.departure.info;
let lineInterference = trafficInfo != "" && trafficInfo != null;
let infoElem = <></>;
state = {
expanded: false
};
if (trafficInfo != "" && trafficInfo != null)
infoElem = <p>{trafficInfo} <u>Visa mer</u></p>
toggle = () => {
if (this.state.expanded)
this.collapse();
else
this.expand();
};
expand = () => {
this.setState({
expanded: true
});
};
collapse = () => {
this.setState({
expanded: false
});
};
render() {
let trafficInfo = this.props.departure.trafficInfo;
let lineInterference = trafficInfo !== "" && trafficInfo !== null && trafficInfo !== undefined;
return (
<div class="trafficEntry">
<div className="trafficEntry">
<div>
<div class="timeColumn">
<span>{this.props.departure.time}</span>
<div className="timeColumn">
{!lineInterference &&
<span>{this.props.departure.originalTime}</span>
}
{lineInterference &&
<img src={warningIcon}></img>
<>
<div style={{display: "flex", flexDirection: "column"}}>
<span style={{color: "red", fontWeight: "bold"}}>{this.props.departure.newTime}</span>
<span style={{textDecoration: "line-through"}}>{this.props.departure.originalTime}</span>
</div>
<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">{"Mot " + this.props.departure.finalStop}</span>
</div>
{infoElem}
{lineInterference &&
<div className="infoWrapper" onClick={this.toggle}>
<p className={`${this.state.expanded ? "expanded" : ""}`}>{trafficInfo}</p>
<span style={{display: (this.state.expanded ? "none" : "block") }}><u>Visa mer</u></span>
</div>
}
</div>
</div>
{lineInterference &&
<button>Hitta annan resväg</button>
<Link to={
{ pathname: "/travel"
, to: this.props.departure.finalStop
}
}>Hitta annan resväg</Link>
}
</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

@ -5,10 +5,10 @@ class TripSelector extends Component {
return (
<form>
<label>Från:</label>
<input type="text" placeholder="Hållplats/Adress/Plats" />
<input type="text" placeholder="Hållplats/Adress/Plats" defaultValue={this.props.from}/>
<hr/>
<label for="lname">Till:</label>
<input type="text" placeholder="Hållplats/Adress/Plats" />
<label>Till:</label>
<input type="text" placeholder="Hållplats/Adress/Plats" defaultValue={this.props.to} />
</form>
);
}

View File

@ -1,7 +1,7 @@
#bottomMenu {
width: 100%;
height: 9vh;
min-height: 60px;
min-height: 70px;
background: white;
display: flex;
justify-content: space-evenly;
@ -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,7 @@
button:active {
background: rgba(0, 0, 0, 0.1);
}
a:active {
background: rgba(0, 0, 0, 0.1);
}

View File

@ -3,7 +3,7 @@ header {
display: flex;
flex-direction: row;
align-items: center;
padding: 15px 15px 15vh 15px;
padding: 15px 15px 12vh 15px;
top: 0;
background: linear-gradient(90deg, var(--colorVT1), var(--colorVT2));
}

View File

@ -3,5 +3,6 @@ main {
flex: 1 1 auto;
display: flex;
flex-flow: column;
justify-content: space-evenly;
justify-content: flex-start;
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,19 +7,36 @@
flex-direction: column;
justify-content: space-evenly;
padding: 0 5vw;
z-index: 4;
}
#stopTitle h1, #stopTitle h3 {
font-weight: 100;
}
#stopTitle div {
display: flex;
flex-direction: row;
#stopTitle h1 {
font-size: 9vw;
}
#stopTitle h3 {
color: rgba(0, 0, 0, 0.4);
font-size: 5vw;
color: var(--colorDiscrete);
}
@media screen and (min-width: 350px) {
#stopTitle h1 {
font-size: 35px;
}
#stopTitle h3 {
font-size: 20px;
color: var(--colorDiscrete);
}
}
#stopTitle div {
display: flex;
flex-direction: row;
}
#stopTitle button {

View File

@ -1,6 +1,7 @@
#trafficList {
height: 100%;
margin-top: 40px;
padding-bottom: 40px;
background: white;
}
@ -10,8 +11,9 @@
justify-content: space-evenly;
align-items: center;
width: 100vw;
padding: 6vw 0;
padding: 8vw 0;
background: white;
font-size: 3.5vw;
}
.trafficEntry div {
@ -19,13 +21,25 @@
display: flex;
flex-direction: row;
justify-content: space-evenly;
margin-bottom: 8px;
}
margin-bottom: 2vh;
}
.trafficEntry div:only-child {
margin-bottom: 0;
}
.trafficEntry div:only-child > .timeColumn,
.trafficEntry div:only-child > .lineColumn {
margin-bottom: 0;
}
.trafficEntry div:only-child > .timeColumn {
justify-content: center !important;
}
.trafficEntry div p {
text-align: left;
font-size: 3.5vw;
padding: 3vw 0;
padding: 3vh 0 0 0;
}
.trafficEntry div div {
@ -33,25 +47,6 @@
flex-direction: column;
}
.timeColumn {
flex-basis: 15%;
justify-content: flex-start;
align-items: center;
}
.timeColumn img {
width: 20px;
}
.lineColumn {
flex-basis: 75%;
}
.lineColumn img {
width: 30px;
margin-right: 10px;
}
.trafficEntry div div div {
display: flex;
flex-direction: row;
@ -59,6 +54,53 @@
align-items: flex-end;
}
.timeColumn {
flex-basis: 15%;
justify-content: space-between !important;
align-items: center;
}
.timeColumn div {
align-items: center !important;
}
.timeColumn img {
width: 3.5vw;
}
.lineColumn {
flex-basis: 75%;
max-width: 75%;
}
.lineColumn div {
margin-bottom: 0px;
}
.lineColumn img {
width: 7.5vw;
margin-right: 10px;
}
.infoWrapper p {
text-overflow: ellipsis;
overflow: hidden;
flex-basis: 75%;
flex-grow: 1;
display: block;
white-space: nowrap;
max-height: 3.5vw;
}
.infoWrapper span {
flex-basis: 25%;
}
.expanded {
white-space: normal !important;
max-height: none !important;
}
.lineName {
background: var(--colorLine);
color: white;
@ -69,11 +111,10 @@
}
.destination {
font-size: 100%;
text-align: left;
}
.trafficEntry button {
.trafficEntry a {
width: 90%;
font-size: 4vw;
font-weight: bold;
@ -81,4 +122,5 @@
padding: 4vw 0;
border-radius: var(--borderRadius);
box-shadow: var(--boxShadow);
text-decoration: none;
}

View File

@ -8,7 +8,7 @@ class Tickets extends Component {
return (
<>
<Header title="Biljetter" />
<MainArea>
<MainArea style={{justifyContent: "space-evenly"}}>
<p>Du har inga biljetter</p>
</MainArea>
</>

View File

@ -19,7 +19,7 @@ class TicketsBuy extends Component {
<MenuButton label="Periodbiljett" icon={calendarIcon} />
<MenuButton label="Dygnsbiljett" icon={recurringIcon} />
</TopMenu>
<MainArea>
<MainArea style={{justifyContent: "space-evenly"}}>
<p>Du har inga tidigare köp</p>
</MainArea>
</>

View File

@ -1,25 +1,34 @@
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")
],
);
/* TEST DATA - TO BE REPLACED */
let testStop = new Stop(
"Lemmingsgatan",
["Läge A", "Läge B", "Läge C"],
[
new Departure(
"519",
"Heden",
"11:59",
"Trafikolycka vid Partille Centrum. Olyckan ska ha inträffat i höjd med brandstationen och det är oklart om någon är skadad. Polis på väg. Två av bilarna behöver bärgas från platsen. Inga uppgifter om personskador."
),
new Departure("58", "Västra Eriksberg", "12:07"),
]
);
testStop.departures[0].timeUpdate("16:50");
/* TEST DATA - TO BE REPLACED */
return (
<>
@ -35,4 +44,4 @@ class TrafficInfo extends Component {
}
}
export default TrafficInfo;
export default TrafficInfo;

View File

@ -13,9 +13,12 @@ class Travel extends Component {
<>
<Header title="Reseplanering" />
<TopMenu>
<TripSelector />
<TripSelector
from={this.props.location.from}
to={this.props.location.to}
/>
</TopMenu>
<MainArea>
<MainArea style={{justifyContent: "space-evenly"}}>
</MainArea>
</>
);

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);