9 Commits

31 changed files with 443 additions and 64 deletions

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", "name":"1",
"deviceId":"1", "deviceId":"1",
"location":"9022014014754001" "stoppointgid":"9022014014754001"
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,8 +7,11 @@
*/ */
class Stop { class Stop {
constructor(name, locations, departures) { constructor(name, id, lat, lon, locations, departures) {
this.name = name; this.name = name;
this.id = id;
this.lat = lat;
this.lon = lon;
this.locations = locations; this.locations = locations;
this.departures = departures; this.departures = departures;
} }

View File

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

View File

@ -2,12 +2,14 @@ import React, { Component } from 'react';
import globalData from '../GlobalData.js'; import globalData from '../GlobalData.js';
import DisruptionButton from "./DisruptionButton.js"; import DisruptionButton from "./DisruptionButton.js";
import SelectUserButton from "./SelectUserButton.js"
import Popup from './Popup.js'; import Popup from './Popup.js';
import Button from './Button.js'; import Button from './Button.js';
import './css/NavigationDrawer.css'; import './css/NavigationDrawer.css';
import userIcon from '../img/user.svg'; import userIcon from '../img/user.svg';
import FindStops from './FindStops.js';
class NavigationDrawer extends Component { class NavigationDrawer extends Component {
@ -63,7 +65,13 @@ class NavigationDrawer extends Component {
<span>example@gmail.com</span> <span>example@gmail.com</span>
</header> </header>
<div id="navList"> <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={"ex1"} onClick={[this.showPopup, this.close]} />
<DisruptionButton path={"ex2"} onClick={[this.showPopup, this.close]} />
</div> </div>
<hr /> <hr />
<span id="version">Projektgrupp 3 - Utmaning 7</span> <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 React, { Component } from 'react';
import { Link } from 'react-router-dom';
import './css/TrafficInfo.css'; import './css/TrafficInfo.css';
@ -6,6 +7,29 @@ import busIcon from '../img/bus.svg';
import warningIcon from '../img/warning.svg'; import warningIcon from '../img/warning.svg';
class TrafficEntry extends Component { 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() { render() {
let trafficInfo = this.props.departure.trafficInfo; let trafficInfo = this.props.departure.trafficInfo;
let lineInterference = trafficInfo !== "" && trafficInfo !== null && trafficInfo !== undefined; let lineInterference = trafficInfo !== "" && trafficInfo !== null && trafficInfo !== undefined;
@ -14,25 +38,40 @@ class TrafficEntry extends Component {
<div className="trafficEntry"> <div className="trafficEntry">
<div> <div>
<div className="timeColumn"> <div className="timeColumn">
<span>{this.props.departure.time}</span> {!lineInterference &&
<span>{this.props.departure.originalTime}</span>
}
{lineInterference && {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> <img src={warningIcon} alt=""></img>
</>
} }
</div> </div>
<div className="lineColumn"> <div className="lineColumn">
<div> <div>
<span className="lineName">{this.props.departure.lineName}</span> <span className="lineName">{this.props.departure.lineName}</span>
<img src={busIcon} alt=""></img> <img src={busIcon} alt=""></img>
<span className="destination">{this.props.departure.finalStop}</span> <span className="destination">{"Mot " + this.props.departure.finalStop}</span>
</div> </div>
{lineInterference && {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>
</div> </div>
{lineInterference && {lineInterference &&
<button>Hitta annan resväg</button> <Link to={
{ pathname: "/travel"
, to: this.props.departure.finalStop
}
}>Hitta annan resväg</Link>
} }
</div> </div>
); );

View File

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

View File

@ -1,7 +1,7 @@
#bottomMenu { #bottomMenu {
width: 100%; width: 100%;
height: 9vh; height: 9vh;
min-height: 60px; min-height: 70px;
background: white; background: white;
display: flex; display: flex;
justify-content: space-evenly; justify-content: space-evenly;

View File

@ -1,3 +1,7 @@
button:active { button:active {
background: rgba(0, 0, 0, 0.1); 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; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 15px 15px 15vh 15px; padding: 15px 15px 12vh 15px;
top: 0; top: 0;
background: linear-gradient(90deg, var(--colorVT1), var(--colorVT2)); background: linear-gradient(90deg, var(--colorVT1), var(--colorVT2));
} }

View File

@ -3,6 +3,6 @@ main {
flex: 1 1 auto; flex: 1 1 auto;
display: flex; display: flex;
flex-flow: column; flex-flow: column;
justify-content: space-evenly; justify-content: flex-start;
overflow: hidden scroll; overflow: hidden scroll;
} }

View File

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

View File

@ -1,6 +1,7 @@
#trafficList { #trafficList {
height: 100%; height: 100%;
margin-top: 40px; margin-top: 40px;
padding-bottom: 40px;
background: white; background: white;
} }
@ -10,8 +11,9 @@
justify-content: space-evenly; justify-content: space-evenly;
align-items: center; align-items: center;
width: 100vw; width: 100vw;
padding: 6vw 0; padding: 8vw 0;
background: white; background: white;
font-size: 3.5vw;
} }
.trafficEntry div { .trafficEntry div {
@ -19,13 +21,25 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-evenly; 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 { .trafficEntry div p {
text-align: left; text-align: left;
font-size: 3.5vw; padding: 3vh 0 0 0;
padding: 3vw 0;
} }
.trafficEntry div div { .trafficEntry div div {
@ -33,25 +47,6 @@
flex-direction: column; 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 { .trafficEntry div div div {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -59,6 +54,53 @@
align-items: flex-end; 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 { .lineName {
background: var(--colorLine); background: var(--colorLine);
color: white; color: white;
@ -69,11 +111,10 @@
} }
.destination { .destination {
font-size: 100%;
text-align: left; text-align: left;
} }
.trafficEntry button { .trafficEntry a {
width: 90%; width: 90%;
font-size: 4vw; font-size: 4vw;
font-weight: bold; font-weight: bold;
@ -81,4 +122,5 @@
padding: 4vw 0; padding: 4vw 0;
border-radius: var(--borderRadius); border-radius: var(--borderRadius);
box-shadow: var(--boxShadow); box-shadow: var(--boxShadow);
text-decoration: none;
} }

View File

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

View File

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

View File

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

View File

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