Making some progress
This commit is contained in:
parent
c41d4b4cec
commit
7d74fcc3e0
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -7,6 +7,7 @@
|
|||||||
<title>Svelte app</title>
|
<title>Svelte app</title>
|
||||||
|
|
||||||
<link rel='icon' type='image/png' href='/favicon.png'>
|
<link rel='icon' type='image/png' href='/favicon.png'>
|
||||||
|
<!--<link rel='stylesheet' href='/global.css'>-->
|
||||||
<link rel='stylesheet' href='/build/bundle.css'>
|
<link rel='stylesheet' href='/build/bundle.css'>
|
||||||
|
|
||||||
<script defer src='/build/bundle.js'></script>
|
<script defer src='/build/bundle.js'></script>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
// Import the list of routes
|
// Import the list of routes
|
||||||
import routes from './routes'
|
import routes from './routes'
|
||||||
import Header from "./components/Header.svelte";
|
import Header from "./components/Header.svelte";
|
||||||
|
let currentPage;
|
||||||
|
|
||||||
function conditionsFailed(event) {
|
function conditionsFailed(event) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
@ -15,6 +16,8 @@
|
|||||||
function routeLoaded(event) {
|
function routeLoaded(event) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.info('Caught event routeLoaded', event.detail)
|
console.info('Caught event routeLoaded', event.detail)
|
||||||
|
currentPage = event.detail.name;
|
||||||
|
console.log('currentPage', currentPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles event bubbling up from nested routes
|
// Handles event bubbling up from nested routes
|
||||||
@ -27,9 +30,25 @@
|
|||||||
|
|
||||||
|
|
||||||
<style lang="scss" global>
|
<style lang="scss" global>
|
||||||
@import "./css/custom.scss";
|
@import "node_modules/spectre.css/src/spectre.scss";
|
||||||
|
/* @import "./css/custom.scss";*/
|
||||||
|
/*@import './fonts/fonts.css';
|
||||||
|
@import './fonts/gotham.css';*/
|
||||||
|
@import './fonts/fujicons.css';
|
||||||
|
|
||||||
|
.up,
|
||||||
|
.ontime,
|
||||||
|
.trendUp {
|
||||||
|
color: #4CAF50 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.down,
|
||||||
|
.delayed,
|
||||||
|
.trendDown {
|
||||||
|
color: #F44336 !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<Header/>
|
<Header page={currentPage}/>
|
||||||
<Router {routes} on:conditionsFailed={conditionsFailed} on:routeLoaded={routeLoaded} on:routeEvent={routeEvent} />
|
<Router {routes} on:conditionsFailed={conditionsFailed} on:routeLoaded={routeLoaded} on:routeEvent={routeEvent} />
|
||||||
|
@ -1,32 +1,51 @@
|
|||||||
<script>
|
<script>
|
||||||
import {link, push, pop, replace, location, querystring} from 'svelte-spa-router';
|
import {pop} from 'svelte-spa-router';
|
||||||
import active from 'svelte-spa-router/active'
|
|
||||||
|
|
||||||
|
export let page;
|
||||||
let titleText = 'Traintimes';
|
let titleText = 'Traintimes';
|
||||||
let currentMode = 1;
|
$: currentMode = (page === 'Home') ? 0 : 1;
|
||||||
|
|
||||||
$: titleText = $location;
|
|
||||||
function goBack() {
|
function goBack() {
|
||||||
console.log('>> Header:goBack');
|
pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
/*#appbar-more-vert {
|
||||||
|
width: 31px;
|
||||||
|
height: 31px;
|
||||||
|
color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appbar-more-vert {
|
||||||
|
line-height: 31px;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
}*/
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<header id="header">
|
<header class="navbar bg-primary">
|
||||||
<div class="mui-appbar mui--appbar-line-height mui--z2">
|
|
||||||
|
<section class="navbar-section">
|
||||||
{#if currentMode === 1}
|
{#if currentMode === 1}
|
||||||
<div class='mui-col-xs-1 mui-col-md-1 mui--appbar-height'>
|
<span on:click={goBack} class="" >
|
||||||
<a on:click={goBack} class="">
|
<i class="fa-2x fa fa-back" style="color:white;"></i>
|
||||||
<i class="fa-3x fa fa-back mui--align-middle" style="color:white;"></i>
|
</span>
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
<div class='mui-col-xs-11 mui-col-md-11 mui--appbar-height titleBar'>{titleText}</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
<span class="text-bold navbar-brand mx-2 text-uppercase">{titleText}</span>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="navbar-section">
|
||||||
|
<a href="/#/settings" class="btn btn-link text-secondary">Settings</a>
|
||||||
|
<a href="/#/favourites" class="btn btn-link text-secondary">Favourites</a>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
</header>
|
</header>
|
||||||
|
60
src/components/SettingsEditor.svelte
Normal file
60
src/components/SettingsEditor.svelte
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<script>
|
||||||
|
import SettingsInput from "./SettingsInput.svelte";
|
||||||
|
|
||||||
|
let startStation;
|
||||||
|
let destStation;
|
||||||
|
let deleteEnabled = false;
|
||||||
|
|
||||||
|
function deleteItem(){
|
||||||
|
console.log('>> Delete item');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeEditor() {
|
||||||
|
console.log('>> Close item');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveEditor() {
|
||||||
|
console.log('>> Save editor');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<span>SettingsEditor</span>
|
||||||
|
<div class="mui-container ">
|
||||||
|
<div class="mui-row card">
|
||||||
|
<div class="mui--text-headline">New Route</div>
|
||||||
|
<div class="mui--align-middle">
|
||||||
|
<div class='mui-col-xs-12 mui-col-md-5'>
|
||||||
|
<SettingsInput bind:returnValue={startStation} label="Departure Station" name="startStation"/>
|
||||||
|
</div>
|
||||||
|
<div class='mui-col-xs-12 mui-col-md-2'>
|
||||||
|
<i class="fa fa-thick-arrow fa-2x mui--align-middle">
|
||||||
|
</div>
|
||||||
|
<div class='mui-col-xs-12 mui-col-md-5'>
|
||||||
|
<SettingsInput bind:returnValue={destStation} label="Destination Station" name="destStation"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my text-right">
|
||||||
|
<button class="btn btn-danger btn-sm" id="delete" type="button" disabled={deleteEnabled} on:click={deleteItem}>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm" type="button" on:click={closeEditor}>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary btn-sm" id="save" type="button" on:click={saveEditor}>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
52
src/components/SettingsInput.svelte
Normal file
52
src/components/SettingsInput.svelte
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<script>
|
||||||
|
import {debounce} from '../libs/utils';
|
||||||
|
import {onMount} from 'svelte';
|
||||||
|
import {searchStation} from '../libs/stations';
|
||||||
|
|
||||||
|
export let returnValue;
|
||||||
|
export let value;
|
||||||
|
|
||||||
|
export let name;
|
||||||
|
export let label;
|
||||||
|
|
||||||
|
let debouncedDoSearch;
|
||||||
|
let searchResults = [];
|
||||||
|
|
||||||
|
// $: visible = (searchResults.length > 0) ?
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
debouncedDoSearch = debounce(doSearch, 500);
|
||||||
|
});
|
||||||
|
|
||||||
|
function doSearch() {
|
||||||
|
returnValue = '';
|
||||||
|
if (value.length >= 2)
|
||||||
|
searchResults = searchStation(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectItem(e) {
|
||||||
|
let [id, name] = e.target.dataset.content.split(',');
|
||||||
|
|
||||||
|
returnValue = id;
|
||||||
|
value = name;
|
||||||
|
|
||||||
|
searchResults = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<span class="mui-dropdown--right">
|
||||||
|
<label for={name}>{label}</label>
|
||||||
|
<input {name} on:keyup={debouncedDoSearch} bind:value />
|
||||||
|
{#if searchResults.length > 0}
|
||||||
|
<ul class="mui-dropdown__menu mui--is-open">
|
||||||
|
{#each searchResults as item, index}
|
||||||
|
<li><div on:click={selectItem} data-content="{item}">{item[1]} ({item[0]})</div></li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
</span>
|
12
src/components/SettingsList.svelte
Normal file
12
src/components/SettingsList.svelte
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
background: #f55a4e;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<span>SettingsList</span>
|
@ -1,17 +1,90 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import {onMount, onDestroy} from 'svelte';
|
||||||
|
import axios from 'axios';
|
||||||
|
import {push} from 'svelte-spa-router';
|
||||||
|
|
||||||
|
import reducer from '../libs/reducer';
|
||||||
|
|
||||||
export let fromStation;
|
export let fromStation;
|
||||||
export let destStation;
|
export let destStation;
|
||||||
|
|
||||||
|
let list = []
|
||||||
|
let otherDetails = {};
|
||||||
|
let baseUrl = 'http://localhost:8100';
|
||||||
|
let doUpdate = true;
|
||||||
|
onMount(async () => {
|
||||||
|
|
||||||
|
await fetchData();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function fetchData() {
|
||||||
|
if (doUpdate === true) {
|
||||||
|
const routeUrl = `/gettrains?from=${fromStation}&to=${destStation}`
|
||||||
|
const url = baseUrl.concat(routeUrl)
|
||||||
|
await axios.get(url)
|
||||||
|
.then((d) => {
|
||||||
|
list = reducer.reduceTrainTimetable(d.data)
|
||||||
|
otherDetails = reducer.reduceOtherDetails(d.data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function viewService(e) {
|
||||||
|
push(`/service/${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
* {
|
|
||||||
background: #f55a4e;
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<span>TimetableList</span>
|
<section>
|
||||||
{fromStation} to {destStation}
|
{#if otherDetails.nrMessagesExist === true}
|
||||||
|
<div class="mui--bg-danger mui--text-white nrccAlert" style="padding:2px;">
|
||||||
|
<ul>
|
||||||
|
{#each otherDetails.nrMessages as item}
|
||||||
|
<li><i class="fa fa-info mui--align-middle"></i> {item.msg}
|
||||||
|
{#if item.link}
|
||||||
|
<a href={item.link}>{item.linkText}</a>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if list.length > 0}
|
||||||
|
|
||||||
|
{#each list as item}
|
||||||
|
<div class="mui-row card mui--align-bottom">
|
||||||
|
<div class="mui-col-xs-5 mui-col-md-4 mui--align-middle">
|
||||||
|
<span on:click={viewService(item.serviceIdUrlSafe)}>{item.location}</span>
|
||||||
|
<span class="mui--text-accent">{item.carriageCount}</span>
|
||||||
|
<div>
|
||||||
|
{#if item.via}
|
||||||
|
<em class="mui--text-accent via">{item.via}</em>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mui-col-xs-2 mui-col-md-3 mui--text-center mui--align-middle time">{item.time}</div>
|
||||||
|
|
||||||
|
{#if item.isCancelled}
|
||||||
|
<div class="mui-col-xs-5 mui-col-md-5 mui--text-center mui--align-middle delayed"><i class="fa fa-alert fa-1x mui--align-middle"></i>{item.cancel}</div>
|
||||||
|
{:else}
|
||||||
|
<div class="mui-col-xs-3 mui-col-md-3 mui--text-center mui--align-middle {item.statusMode}">{item.status}</div>
|
||||||
|
<div class="mui-col-xs-2 mui-col-md-2 mui--text-center mui--align-middle">{item.platform}</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
let status;
|
let status;
|
||||||
let timetablePath;
|
let timetablePath;
|
||||||
let interval = 0;
|
let interval = 0;
|
||||||
|
let due = 0;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
status = (trainData.eta === 'On time') ? 'ontime' : 'delayed';
|
status = (trainData.eta === 'On time') ? 'ontime' : 'delayed';
|
||||||
@ -28,31 +29,47 @@
|
|||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (LocalStorage.exists(`${startStation}${destStation}`)) {
|
if (LocalStorage.exists(`${startStation}${destStation}`)) {
|
||||||
const fromLS = JSON.parse(LocalStorage.load(`${startStation}${destStation}`));
|
const fromLS = JSON.parse(LocalStorage.load(`${startStation}${destStation}`));
|
||||||
trainData = {...trainData, ...fromLS};
|
trainData = {...trainData, ...fromLS.trainData};
|
||||||
}
|
due = fromLS.due;
|
||||||
|
startStationName = fromLS.startStationName;
|
||||||
|
destStationName = fromLS.destStationName;
|
||||||
|
url = fromLS.url;
|
||||||
|
} else {
|
||||||
startStationName = findStation(startStation);
|
startStationName = findStation(startStation);
|
||||||
destStationName = findStation(destStation);
|
destStationName = findStation(destStation);
|
||||||
url = `${baseUrl}/getnexttraintimes?from=${startStation}&to=${destStation}`;
|
url = `${baseUrl}/getnexttraintimes?from=${startStation}&to=${destStation}`;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = new Date().getTime();
|
||||||
|
if (now > due) {
|
||||||
updateTrain();
|
updateTrain();
|
||||||
|
} else {
|
||||||
|
interval = 0
|
||||||
|
interval = setTimeout(updateTrain, due - now);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(async () => {
|
onDestroy(async () => {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
LocalStorage.save(`${startStation}${destStation}`, JSON.stringify(trainData));
|
const store = {due, trainData, startStationName, destStationName, url};
|
||||||
|
LocalStorage.save(`${startStation}${destStation}`, JSON.stringify(store));
|
||||||
});
|
});
|
||||||
|
|
||||||
function onClick() {
|
function onClick() {
|
||||||
console.log('Onclick', timetablePath);
|
|
||||||
push(timetablePath);
|
push(timetablePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateTrain() {
|
async function updateTrain() {
|
||||||
console.log(`Update: ${startStation} / ${destStation}`)
|
console.log(`Update: ${startStation} / ${destStation}`)
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
|
|
||||||
const hours = now.getHours()
|
const hours = now.getHours()
|
||||||
const limit = (hours < 6) ? 3600000 : 95000
|
const limit = (hours < 6) ? 3600000 : 95000
|
||||||
const mod = limit - (now.getTime() % limit)
|
const mod = limit - (now.getTime() % limit)
|
||||||
|
due = now.getTime() + mod;
|
||||||
|
|
||||||
await getTrain()
|
await getTrain()
|
||||||
clearTimeout(interval)
|
clearTimeout(interval)
|
||||||
interval = 0
|
interval = 0
|
||||||
@ -76,14 +93,29 @@
|
|||||||
margin: 6px 0;
|
margin: 6px 0;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.TRcard {
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff;
|
||||||
|
min-height: 48px;
|
||||||
|
margin: 0.5rem 8px;
|
||||||
|
border-bottom-color: #666666;
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2),
|
||||||
|
0 1px 5px 0 rgba(0, 0, 0, 0.12);
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
border-radius: 0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="mui-row card">
|
<div class="columns TRcard">
|
||||||
<div class='mui-col-xs-7 mui-col-md-7 entry'>
|
<div class='column col-7 entry'>
|
||||||
<div>{startStationName}</div>
|
<div>{startStationName}</div>
|
||||||
<div>{destStationName}</div>
|
<div>{destStationName}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='mui-col-xs-5 mui-col-md-5 mui--text-right'>
|
<div class='column col-5 text-right entry'>
|
||||||
<span class="mui-btn mui-btn--flat time {status}" on:click={onClick}>{displayTime}</span>
|
<span class="btn {status}" on:click={onClick}>{displayTime}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +1,64 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import {onMount, onDestroy} from 'svelte';
|
||||||
|
import {minuteFloor, LocalStorage} from '../libs/utils'
|
||||||
|
import axios from 'axios';
|
||||||
|
import reducer from '../libs/reducer';
|
||||||
|
|
||||||
|
export let serviceId;
|
||||||
|
|
||||||
|
let list = [];
|
||||||
|
let baseUrl = 'http://localhost:8100';
|
||||||
|
let doUpdate = true;
|
||||||
|
let serviceInterval;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
fetchServiceData();
|
||||||
|
|
||||||
|
serviceInterval = setInterval(() => {
|
||||||
|
console.log('Do service update')
|
||||||
|
fetchServiceData()
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(async () => {
|
||||||
|
clearInterval(serviceInterval);
|
||||||
|
});
|
||||||
|
|
||||||
|
function fetchServiceData() {
|
||||||
|
console.log('>> TrainService: fetchServiceData');
|
||||||
|
// http://localhost:8100/getservice?serviceid=TDKWvQdeuviRyNYP7lk7gA
|
||||||
|
if (doUpdate === true) {
|
||||||
|
const routeUrl = `/getservice?serviceid=${serviceId}`
|
||||||
|
const url = baseUrl.concat(routeUrl)
|
||||||
|
axios.get(url)
|
||||||
|
.then((d) => {
|
||||||
|
console.log(d);
|
||||||
|
list = reducer.reduceTrainService(d.data);
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
* {
|
|
||||||
background: #f55a4e;
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<span>TrainService</span>
|
<section>
|
||||||
|
<div class="mui-row card mui--align-bottom">
|
||||||
|
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">Station</div>
|
||||||
|
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">Due</div>
|
||||||
|
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">Estimated</div>
|
||||||
|
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">Arrived</div>
|
||||||
|
</div>
|
||||||
|
{#if list.length > 0}
|
||||||
|
{#each list as item}
|
||||||
|
<div class="mui-row card mui--align-bottom {item.classCancel}">
|
||||||
|
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">{item.locationName}</div>
|
||||||
|
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">{item.st}</div>
|
||||||
|
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle {item.etMode}">{item.et}</div>
|
||||||
|
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle {item.atMode}">{item.at}</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</section>
|
||||||
|
132
src/libs/reducer.js
Normal file
132
src/libs/reducer.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* Created by WebStorm.
|
||||||
|
* User: martin
|
||||||
|
* Date: 20/04/2020
|
||||||
|
* Time: 12:01
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const reducer = {
|
||||||
|
reduceOtherDetails (data) {
|
||||||
|
const nrMessages = [];
|
||||||
|
// we have national rail messages so put a box at the top
|
||||||
|
// <div class="mui--bg-danger .mui--text-white" style="height:10px;"></div>
|
||||||
|
let index = 0;
|
||||||
|
const anchorRegex = /<\s*[aA].*?href\s*=\s*(?:"|')(.*?)(?:"|')[^>]*>(.*?)<\s*?\/\s*?[aA]\s*?>/;
|
||||||
|
|
||||||
|
if (typeof data.nrccMessages === 'object' && data.nrccMessages !== null)
|
||||||
|
for (const item of data.nrccMessages) {
|
||||||
|
const newObj = { 'index': 0, 'msg': '', 'link': null, 'linkText': '' };
|
||||||
|
|
||||||
|
let msg = item.value.replace(' ">', '">').replace('</A>', '</a>').replace('<A ', '<a ').replace(/<\/*[pP]>/gi, '');
|
||||||
|
const anchor = anchorRegex.exec(item.value);
|
||||||
|
msg = msg.replace(anchorRegex, '');
|
||||||
|
|
||||||
|
newObj.index = index;
|
||||||
|
newObj.msg = msg;
|
||||||
|
if (anchor !== null) {
|
||||||
|
newObj.link = anchor[1];
|
||||||
|
newObj.linkText = anchor[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
nrMessages.push(newObj);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { nrMessages, 'nrMessagesExist': nrMessages.length > 0 };
|
||||||
|
},
|
||||||
|
reduceTrainTimetable (data) {
|
||||||
|
const services = [];
|
||||||
|
let ws = '';
|
||||||
|
const symbol = ['💠', '🚉'];
|
||||||
|
if (typeof data === 'object' && data !== null) {
|
||||||
|
console.log('>> reduceTrainService');
|
||||||
|
console.log(data);
|
||||||
|
if (typeof data.trainServices === 'object' && data.trainServices !== null)
|
||||||
|
for (const item of data.trainServices) {
|
||||||
|
// console.log(item)
|
||||||
|
const dest = item.destination[0];
|
||||||
|
const via = dest.via !== null ? dest.via : '';
|
||||||
|
const platform = item.platform !== null ? item.platform : `${symbol[0]}`;
|
||||||
|
// 🚉 💠
|
||||||
|
// const time = item.sta !== null ? item.sta : `<em class="mui--text-accent-secondary">D</em> ${item.std}`
|
||||||
|
const time = item.sta !== null ? item.sta : `D ${item.std}`;
|
||||||
|
const isDeparture = item.sta === null;
|
||||||
|
const status = item.eta !== null ? item.eta : item.etd;
|
||||||
|
const trainLength = item.length;
|
||||||
|
|
||||||
|
const carriageCount = (trainLength > 0) ? ` (${trainLength} 🚃) ` : '';
|
||||||
|
|
||||||
|
const statusMode = (status.toLowerCase() === 'on time') ? 'ontime' : 'delayed';
|
||||||
|
const delayReason = (item.delayReason !== null) ? item.delayReason : '';
|
||||||
|
|
||||||
|
const cancelReason = (item.cancelReason !== null) ? item.cancelReason : 'No reason given 🤷';
|
||||||
|
|
||||||
|
const serviceIdUrlSafe = item.serviceIdUrlSafe;
|
||||||
|
|
||||||
|
services.push({ 'location': dest.locationName, 'time': time, 'status': status, 'platform': platform, 'cancel': cancelReason, 'type': 'train', 'delay': delayReason, 'carriageCount': carriageCount, 'via': via, 'statusMode': statusMode, 'isCancelled': item.isCancelled, 'isDeparture': isDeparture, 'serviceIdUrlSafe': serviceIdUrlSafe });
|
||||||
|
if (!item.isCancelled)
|
||||||
|
ws = `${ws}<tr><td data-id="${item.serviceIdUrlSafe}" class="station">${dest.locationName}${carriageCount}${via}</td>
|
||||||
|
<td class="mui--text-center time">${time}</td>
|
||||||
|
<td class="mui--text-center ${statusMode}">${status}</td>
|
||||||
|
<td class="mui--text-center">${platform}</td>
|
||||||
|
</tr>${delayReason}`;
|
||||||
|
else
|
||||||
|
ws = `${ws}<tr><td>${dest.locationName} ${via}</td><td>${time}</td>
|
||||||
|
<td colspan="2" class="delayed">❌ ${cancelReason}</td></tr>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof data.busServices === 'object' && data.busServices !== null)
|
||||||
|
for (const item of data.busServices) {
|
||||||
|
const dest = item.destination[0];
|
||||||
|
const via = dest.via !== null ? dest.via : '';
|
||||||
|
const platform = item.platform !== null ? item.platform : '';
|
||||||
|
const time = item.sta !== null ? item.sta : `D ${item.std}`;
|
||||||
|
const status = item.eta !== null ? item.eta : item.etd;
|
||||||
|
services.push({ 'location': dest.locationName, 'time': time, 'status': status, 'platform': platform, 'cancel': item.cancelReason, 'type': 'bus', 'via': via });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(services);
|
||||||
|
|
||||||
|
return services;
|
||||||
|
},
|
||||||
|
reduceTrainService (d) {
|
||||||
|
let callingpoints = [];
|
||||||
|
|
||||||
|
const departureTime = d.sta || d.std;
|
||||||
|
const departureStatus = d.eta || d.etd;
|
||||||
|
|
||||||
|
const currentLocation = { 'locationName': d.locationName, 'crs': d.crs, 'st': d.sta, 'et': d.eta, 'at': d.ata, 'isCancelled': d.isCancelled, 'length': d.length, 'detachFront': d.detachFront, 'adhocAlerts': d.adhocAlerts };
|
||||||
|
|
||||||
|
if (d.previousCallingPoints !== null)
|
||||||
|
callingpoints = callingpoints.concat(d.previousCallingPoints[0].callingPoint);
|
||||||
|
|
||||||
|
callingpoints.push(currentLocation);
|
||||||
|
|
||||||
|
if (d.subsequentCallingPoints !== null)
|
||||||
|
callingpoints = callingpoints.concat(d.subsequentCallingPoints[0].callingPoint);
|
||||||
|
|
||||||
|
callingpoints = callingpoints.map((item) => {
|
||||||
|
// console.log(item)
|
||||||
|
item.et = (item.et === null) ? '' : item.et;
|
||||||
|
item.at = (item.at === null) ? '' : item.at;
|
||||||
|
|
||||||
|
item.etMode = (item.et.toLowerCase() === 'on time') ? 'ontime' : 'delayed';
|
||||||
|
item.atMode = (item.at.toLowerCase() === 'on time') ? 'ontime' : 'delayed';
|
||||||
|
item.delayReason = (item.delayReason !== null) ? item.delayReason : '';
|
||||||
|
item.cancelReason = (item.cancelReason !== null) ? item.cancelReason : 'No reason given 🤷';
|
||||||
|
item.classCancel = (item.isCancelled) ? 'cancelledRow' : '';
|
||||||
|
|
||||||
|
if (item.st === null && (item.et === null || item.et === '')) {
|
||||||
|
item.st = `D ${departureTime}`;
|
||||||
|
item.et = departureStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
|
||||||
|
return callingpoints;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = reducer;
|
File diff suppressed because one or more lines are too long
@ -117,4 +117,73 @@ else
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = { partOfDay, toHour, hourFloor, distance, maybePluralize, minuteFloor, LocalStorage };
|
/**
|
||||||
|
*
|
||||||
|
* @param fn
|
||||||
|
* @param time
|
||||||
|
* @returns {Function}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function debounce(fn, time) {
|
||||||
|
let timeout;
|
||||||
|
|
||||||
|
return function (...args) { // <-- not an arrow function
|
||||||
|
const functionCall = () => fn.apply(this, args);
|
||||||
|
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(functionCall, time);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param callback
|
||||||
|
* @param limit
|
||||||
|
* @returns {Function}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function throttle (callback, limit) {
|
||||||
|
var wait = false;
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
if (!wait) {
|
||||||
|
callback.apply(null, arguments);
|
||||||
|
wait = true;
|
||||||
|
setTimeout(function () {
|
||||||
|
wait = false;
|
||||||
|
}, limit);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param func
|
||||||
|
* @returns {function(): *}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function once(func) {
|
||||||
|
var alreadyCalled = false;
|
||||||
|
var result;
|
||||||
|
|
||||||
|
return function() {
|
||||||
|
if (!alreadyCalled) {
|
||||||
|
result = func.apply(this, arguments);
|
||||||
|
alreadyCalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function isEmpty(obj) {
|
||||||
|
for(const key in obj)
|
||||||
|
if(obj.hasOwnProperty(key)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = { partOfDay, toHour, hourFloor, distance, maybePluralize, minuteFloor, debounce, throttle, once, isEmpty, LocalStorage };
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="mui-container">
|
<div class="container">
|
||||||
<TrainRoute destStation="glq" startStation="dbe"/>
|
<TrainRoute destStation="glq" startStation="dbe"/>
|
||||||
<TrainRoute destStation="dbe" startStation="glq"/>
|
<TrainRoute destStation="dbe" startStation="glq"/>
|
||||||
<TrainRoute destStation="glc" startStation="ptk"/>
|
<TrainRoute destStation="glc" startStation="ptk"/>
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import TrainService from "../components/TrainService.svelte";
|
||||||
|
|
||||||
|
export let params = {};
|
||||||
|
|
||||||
|
let serviceId = params.serviceId;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
* {
|
|
||||||
background: #f55a4e;
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<span>Service</span>
|
<div class="mui--appbar-height"></div>
|
||||||
|
<div class="mui-container">
|
||||||
|
<TrainService {serviceId}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
16
src/pages/Settings.svelte
Normal file
16
src/pages/Settings.svelte
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
import SettingsEditor from "../components/SettingsEditor.svelte";
|
||||||
|
import SettingsList from "../components/SettingsList.svelte";
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<span>Settings</span>
|
||||||
|
|
||||||
|
<SettingsEditor/>
|
||||||
|
<SettingsList/>
|
||||||
|
</div>
|
@ -7,29 +7,20 @@
|
|||||||
|
|
||||||
let fromStationName;
|
let fromStationName;
|
||||||
let destStationName;
|
let destStationName;
|
||||||
let fromStation;
|
let fromStation = params.fromStation;
|
||||||
let destStation;
|
let destStation= params.destStation;
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
|
||||||
console.log('>> Timetable:', params);
|
|
||||||
|
|
||||||
fromStation = params.fromStation;
|
|
||||||
destStation = params.destStation;
|
|
||||||
fromStationName = findStation(fromStation);
|
fromStationName = findStation(fromStation);
|
||||||
destStationName = findStation(destStation);
|
destStationName = findStation(destStation);
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(async () => {
|
|
||||||
console.log('>> onDestroy Timetable')
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
</style>
|
</style>
|
||||||
<div class="mui--appbar-height"></div>
|
|
||||||
<div class="mui-container">
|
<div class="container">
|
||||||
<div>
|
<div>
|
||||||
<div class="mui--text-center mui--text-accent">{fromStationName} TO {destStationName}</div>
|
<div class="mui--text-center mui--text-accent">{fromStationName} TO {destStationName}</div>
|
||||||
<TimetableList {fromStation} {destStation}/>
|
<TimetableList {fromStation} {destStation}/>
|
||||||
|
@ -10,12 +10,14 @@
|
|||||||
import Home from './pages/Home.svelte';
|
import Home from './pages/Home.svelte';
|
||||||
import Service from './pages/Service.svelte';
|
import Service from './pages/Service.svelte';
|
||||||
import Timetable from './pages/Timetable.svelte';
|
import Timetable from './pages/Timetable.svelte';
|
||||||
|
import Settings from './pages/Settings.svelte';
|
||||||
import NotFound from './pages/NotFound.svelte';
|
import NotFound from './pages/NotFound.svelte';
|
||||||
|
|
||||||
const routes = new Map();
|
const routes = new Map();
|
||||||
routes.set('/', Home);
|
routes.set('/', Home);
|
||||||
routes.set('/timetable/:fromStation/:destStation', Timetable);
|
routes.set('/timetable/:fromStation/:destStation', Timetable);
|
||||||
routes.set('/service/:serviceId', Service);
|
routes.set('/service/:serviceId', Service);
|
||||||
|
routes.set('/settings', Settings);
|
||||||
routes.set('*', NotFound);
|
routes.set('*', NotFound);
|
||||||
|
|
||||||
export default routes;
|
export default routes;
|
||||||
|
Loading…
Reference in New Issue
Block a user