12 Commits

35 changed files with 559 additions and 64 deletions

View File

@ -0,0 +1,29 @@
{
"DepartureBoard": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestDepartureBoard.xsd",
"servertime": "10:09",
"serverdate": "2020-12-10",
"Departure": {
"name": "Buss MEXP",
"sname": "MEXP",
"journeyNumber": "24",
"type": "BUS",
"stopid": "9022014014754002",
"stop": "Bollestadsvägen, Kungälv",
"time": "10:09",
"date": "2020-12-10",
"journeyid": "9015014621000024",
"direction": "Marstrand",
"track": "B",
"rtTime": "10:11",
"rtDate": "2020-12-10",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=347217%2F124275%2F19874%2F105802%2F80%3Fdate%3D2020-12-10%26station_evaId%3D14754002%26station_type%3Ddep%26format%3Djson%26"
}
}
}
}

View File

@ -0,0 +1,29 @@
{
"DepartureBoard": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestDepartureBoard.xsd",
"servertime": "10:10",
"serverdate": "2020-12-10",
"Departure": {
"name": "Buss MEXP",
"sname": "MEXP",
"journeyNumber": "24",
"type": "BUS",
"stopid": "9022014014020002",
"stop": "Ekelöv västra, Kungälv",
"time": "10:10",
"date": "2020-12-10",
"journeyid": "9015014621000024",
"direction": "Marstrand",
"track": "B",
"rtTime": "10:13",
"rtDate": "2020-12-10",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=740262%2F255290%2F59460%2F217024%2F80%3Fdate%3D2020-12-10%26station_evaId%3D14020002%26station_type%3Ddep%26format%3Djson%26"
}
}
}
}

View File

@ -0,0 +1,27 @@
{
"DepartureBoard": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestDepartureBoard.xsd",
"servertime": "10:10",
"serverdate": "2020-12-10",
"Departure": {
"name": "Buss MEXP",
"sname": "MEXP",
"journeyNumber": "24",
"type": "BUS",
"stopid": "9022014014751002",
"stop": "Guddeby, Kungälv",
"time": "10:07",
"date": "2020-12-10",
"journeyid": "9015014621000024",
"direction": "Marstrand",
"track": "B",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=473190%2F166266%2F666560%2F175550%2F80%3Fdate%3D2020-12-10%26station_evaId%3D14751002%26station_type%3Ddep%26format%3Djson%26"
}
}
}
}

View File

@ -0,0 +1,31 @@
{
"DepartureBoard": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestDepartureBoard.xsd",
"servertime": "10:11",
"serverdate": "2020-12-10",
"Departure": [
{
"name": "Buss 928",
"sname": "928",
"journeyNumber": "10",
"type": "BUS",
"stopid": "9022014014225001",
"stop": "Skrämmenborg, Kungälv",
"time": "15:19",
"date": "2020-12-10",
"journeyid": "9015014692800010",
"direction": "Kärna",
"track": "A",
"rtTime": "15:19",
"rtDate": "2020-12-10",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=261732%2F87569%2F149176%2F12656%2F80%3Fdate%3D2020-12-10%26station_evaId%3D14225001%26station_type%3Ddep%26format%3Djson%26"
}
}
]
}
}

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

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
import User from './classes/User.js';
import Disruption from './classes/Disruption.js'
import Coordinates from "./classes/Coordinates.js";
import Coordinates from './classes/Coordinates.js';
import Stop from './classes/Stop.js'
let globalData = {
user: new User(
@ -10,6 +11,8 @@ let globalData = {
"9022014014020001"
),
disruption: new Disruption(
),
stop: new Stop(
)
};

View File

@ -3,17 +3,22 @@
lineName : String (Linjenamnet)
finalStop : Stop (Ändhållplats)
time : String (Avgångstid)
originalTime : String (Ursprunglig Avgångstid)
newTime : String (Ny Avgångstid)
trafficInfo : String (Trafikinformation)
*/
class Departure {
constructor(lineName, finalStop, time, trafficInfo) {
constructor(lineName, finalStop, originalTime, trafficInfo) {
this.lineName = lineName;
this.finalStop = finalStop;
this.time = time;
this.originalTime = originalTime;
this.trafficInfo = trafficInfo;
}
timeUpdate(time) {
this.newTime = time;
}
}
export default Departure;

View File

@ -7,8 +7,11 @@
*/
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;
}

View File

@ -13,7 +13,7 @@ class Button extends Component {
func();
});
} else {
console.log("Error when parsing Button onClick functions.");
console.log("Error when parsing Button onClick functions. Make sure the functions are passed as an array.");
}
}
}

View File

@ -3,7 +3,7 @@ import addNotification from "react-push-notification";
import globData from '../GlobalData.js';
import ex1 from '../APIexamples/disruption1.json'
import ex2 from '../APIexamples/disruption1.json'
import ex2 from '../APIexamples/disruption2.json'
import Button from './Button.js';
import disruptIcon from '../img/flash.svg';
@ -11,23 +11,29 @@ import disruptIcon from '../img/flash.svg';
class DisruptionButton extends Button {
state = {
jsonLocation: this.props.path,
user: globData.user,
disruption: ""
}
genDisrupt = () => {
console.log(globData.disruption)
for (let stopPoint of ex1.affectedStopPoints) {
if(stopPoint.gid === this.state.user.stoppointgid){
this.state.disruption = ex1
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
console.log(globData.disruption)
addNotification({
title: "Warning",
subtitle: "This is a subtitle",

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

@ -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

@ -2,12 +2,14 @@ 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 {
@ -63,7 +65,13 @@ class NavigationDrawer extends Component {
<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>

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,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,6 +7,29 @@ import busIcon from '../img/bus.svg';
import warningIcon from '../img/warning.svg';
class TrafficEntry extends Component {
state = {
expanded: false
};
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;
@ -14,25 +38,40 @@ class TrafficEntry extends Component {
<div className="trafficEntry">
<div>
<div className="timeColumn">
<span>{this.props.departure.time}</span>
{!lineInterference &&
<span>{this.props.departure.originalTime}</span>
}
{lineInterference &&
<>
<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 className="lineColumn">
<div>
<span className="lineName">{this.props.departure.lineName}</span>
<img src={busIcon} alt=""></img>
<span className="destination">{this.props.departure.finalStop}</span>
<span className="destination">{"Mot " + this.props.departure.finalStop}</span>
</div>
{lineInterference &&
<p>{trafficInfo} <u>Visa mer</u></p>
<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

@ -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>Till:</label>
<input type="text" placeholder="Hållplats/Adress/Plats" />
<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;

View File

@ -1,3 +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,6 +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

@ -14,15 +14,31 @@
font-weight: 100;
}
#stopTitle div {
display: flex;
flex-direction: row;
#stopTitle h1 {
font-size: 9vw;
}
#stopTitle h3 {
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 {
width: auto;
height: 100%;

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

@ -12,20 +12,24 @@ import Departure from "../../classes/Departure.js";
class TrafficInfo extends Component {
render() {
/* TEST DATA - TO BE REPLACED */
let testStop = new Stop(
"Lemmingsgatan",
["Läge A", "Läge B", "Läge C"],
[
new Departure(
"519",
"Mot Heden",
"Heden",
"11:59",
"Trafikolycka vid Partille Centrum."
"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", "Mot Västra Eriksberg", "12:07"),
new Departure("58", "Västra Eriksberg", "12:07"),
]
);
testStop.departures[0].timeUpdate("16:50");
/* TEST DATA - TO BE REPLACED */
return (
<>
<Header title="Trafikinfo" />

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