Modulisation and additions to StaffLDB
This commit is contained in:
parent
cb8aff5788
commit
5a6fe0f3f5
@ -23,7 +23,7 @@
|
||||
transform: translateY(-50%) translateX(-50%);
|
||||
width: 85%;
|
||||
height: auto;
|
||||
max-height: 75vh;
|
||||
max-height: 85vh;
|
||||
overflow-y: auto;
|
||||
max-width: 400px;
|
||||
margin: auto;
|
||||
|
@ -1,142 +0,0 @@
|
||||
<script>
|
||||
import OverlayIsland from "$lib/islands/overlay-island.svelte";
|
||||
import Loading from "$lib/navigation/loading.svelte";
|
||||
import { uuid } from "$lib/stores/uuid";
|
||||
export let detail = {
|
||||
uid: '',
|
||||
rid: '',
|
||||
headcode: '',
|
||||
show: true,
|
||||
};
|
||||
export let close;
|
||||
|
||||
function handleClick() {
|
||||
close();
|
||||
}
|
||||
|
||||
async function getTrain(rid) {
|
||||
try {
|
||||
console.log(`Requested Station: ${rid}`);
|
||||
const url = `https://owlboard.info/api/v2/live/train/rid/${rid}`;
|
||||
const opt = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
uuid: $uuid
|
||||
}
|
||||
};
|
||||
const data = await fetch(url, opt);
|
||||
return await data.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function parseDelay(location) {
|
||||
let string, state;
|
||||
if (location?.lateness) {
|
||||
try {
|
||||
const result = Math.floor(location.lateness / 60)
|
||||
if (result === 0) {string = "RT", state = ''}
|
||||
else if (result < 0) {string = -result + 'E', state = "early"}
|
||||
else if (result > 0) {string = result + 'L', state = "late"};
|
||||
} catch {
|
||||
string = '-', state = '';
|
||||
}
|
||||
} else if (location.arrivalType === "Delayed") {
|
||||
string = "LATE", state = "late";
|
||||
}
|
||||
return {
|
||||
string: string,
|
||||
state: state
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<OverlayIsland>
|
||||
<div id="detailBox">
|
||||
{#await getTrain(detail.rid)}
|
||||
<h6>{detail.headcode}</h6>
|
||||
<Loading />
|
||||
{:then train}
|
||||
<h6>{train.GetServiceDetailsResult.operatorCode}: {detail.headcode}</h6>
|
||||
<p>Locations in grey are not scheduled stops
|
||||
<br>
|
||||
Some stops may be operational stops, not passenger stops.
|
||||
</p>
|
||||
<button type="button" id="closeService" on:click={handleClick}>X</button>
|
||||
<table id="detailTable">
|
||||
<tr>
|
||||
<th>Location</th>
|
||||
<th>Plat.</th>
|
||||
<th>Sch Arr</th>
|
||||
<th>Sch Dep</th>
|
||||
<th>Delay</th>
|
||||
</tr>
|
||||
{#each train.GetServiceDetailsResult.locations.location as location}
|
||||
<tr>
|
||||
<td class="{location?.isPass === 'true' ? 'pass' : ''}">{location.tiploc}</td>
|
||||
<td class="{location?.isPass === 'true' ? 'pass' : ''}">{location.platform || ''}</td>
|
||||
<td class="{location?.isPass === 'true' ? 'pass' : ''}">AR</td>
|
||||
<td class="{location?.isPass === 'true' ? 'pass' : ''}">DP</td>
|
||||
{#await parseDelay(location)}
|
||||
<td>-</td>
|
||||
{:then delay}
|
||||
<td class="{delay.state}">{delay.string}</td>
|
||||
{/await}
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
{:catch}
|
||||
<h6>Error loading data</h6>
|
||||
{/await}
|
||||
</div>
|
||||
</OverlayIsland>
|
||||
|
||||
<style>
|
||||
#detailBox {
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
h6 {
|
||||
position: absolute;
|
||||
top: -25px;
|
||||
left: 20px;
|
||||
font-size: 18px;
|
||||
}
|
||||
p {
|
||||
margin-top: 45px;
|
||||
}
|
||||
#closeService {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
border: none;
|
||||
border-radius: 60px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
background-color: var(--main-bg-color);
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
}
|
||||
#detailTable {
|
||||
width: 100%;
|
||||
margin-top: 40px;
|
||||
color: white;
|
||||
font-size: 15px;
|
||||
}
|
||||
.thisStop {
|
||||
color: yellow;
|
||||
}
|
||||
.pass {
|
||||
opacity: 0.45
|
||||
}
|
||||
.early {
|
||||
color: blue;
|
||||
}
|
||||
.late {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
158
src/lib/ldb/staff/service-row.svelte
Normal file
158
src/lib/ldb/staff/service-row.svelte
Normal file
@ -0,0 +1,158 @@
|
||||
<script>
|
||||
export let service;
|
||||
|
||||
import Reason from "$lib/raw-fetchers/reason.svelte";
|
||||
|
||||
function parseTimes(service) {
|
||||
const sta = new Date(service.sta),
|
||||
eta = new Date(service.eta),
|
||||
ata = new Date(service.ata);
|
||||
const std = new Date(service.std),
|
||||
etd = new Date(service.etd),
|
||||
atd = new Date(service.atd);
|
||||
let parsedSta = parseTime(sta),
|
||||
parsedEta = parseTime(eta),
|
||||
parsedAta = parseTime(ata);
|
||||
let parsedStd = parseTime(std),
|
||||
parsedEtd = parseTime(etd),
|
||||
parsedAtd = parseTime(atd);
|
||||
if (service.isCancelled) {
|
||||
(parsedEta = 'CANC'), (parsedEtd = 'CANC');
|
||||
}
|
||||
let times = {
|
||||
sta: parsedSta || '-',
|
||||
eata: parsedEta || parsedAta || '-',
|
||||
aEst: parsedEta ? 'estimate' : '',
|
||||
std: parsedStd || '-',
|
||||
eatd: parsedEtd || parsedAtd || '-',
|
||||
dEst: parsedEtd ? 'estimate' : ''
|
||||
};
|
||||
if (service.isCancelled) {
|
||||
(parsedEta = 'CANC'), (parsedEtd = 'CANC');
|
||||
(times.aEst = 'canc'), (times.dEst = 'canc');
|
||||
}
|
||||
return times;
|
||||
}
|
||||
|
||||
async function generateServiceData(service) {
|
||||
const timeDetails = await parseTimes(service);
|
||||
let serviceData = {
|
||||
from: await parseLocation(service.origin),
|
||||
to: await parseLocation(service.destination),
|
||||
length: await getTrainLength(service),
|
||||
platform: await parsePlatform(service?.platform || 'undefined'),
|
||||
platformHidden: service?.platformIsHidden === 'true',
|
||||
schArr: timeDetails.schArr,
|
||||
expArr: timeDetails.expArr,
|
||||
schDep: timeDetails.schDep,
|
||||
expDep: timeDetails.expDep,
|
||||
isEarlyArr: timeDetails.earArr,
|
||||
isLateArr: timeDetails.delArr,
|
||||
isEarlyDep: timeDetails.earDep,
|
||||
isLateDep: timeDetails.delDep,
|
||||
isCancelledDep: false,
|
||||
isCancelled: Boolean(service?.isCancelled),
|
||||
canArr: timeDetails.canArr,
|
||||
canDep: timeDetails.canDep,
|
||||
isDelayed: service?.arrivalType === 'Delayed',
|
||||
isArrDelayed: service?.arrivalType === 'Delayed',
|
||||
isDepDelayed: service?.departureType === 'Delayed',
|
||||
isNonPublic: service?.isPassengerService === 'false' ? true : false
|
||||
};
|
||||
return serviceData;
|
||||
}
|
||||
|
||||
async function getTrainLength(service) {
|
||||
if (service?.length) {
|
||||
return parseInt(service?.length);
|
||||
} else if (service?.formation?.coaches) {
|
||||
return service.formation.coaches.coach.length;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function parseLocation(location) {
|
||||
if (!Array.isArray(location.location)) {
|
||||
return location.location?.tiploc;
|
||||
}
|
||||
let locations = [];
|
||||
for (const singleLocation of location?.location) {
|
||||
locations.push(singleLocation?.tiploc);
|
||||
}
|
||||
return locations.join(' & ');
|
||||
}
|
||||
|
||||
async function parsePlatform(platform) {
|
||||
if (!platform) {
|
||||
return '-';
|
||||
}
|
||||
if (platform === 'TBC' || platform == 'undefined') {
|
||||
return '-';
|
||||
}
|
||||
return {
|
||||
number: platform
|
||||
};
|
||||
}
|
||||
|
||||
function parseIndividualTime(input) {
|
||||
const dt = new Date(input);
|
||||
const output = dt.toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
if (output !== 'Invalid Date') {
|
||||
return output;
|
||||
}
|
||||
return '-';
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await generateServiceData(service)}
|
||||
<tr>
|
||||
<td colspan="8"> Loading... </td>
|
||||
</tr>
|
||||
{:then serviceStats}
|
||||
<tr class="{serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}">
|
||||
<td class="id id-data data" on:click={showDetails(service.rid, service.uid, service.trainid)} on:keypress={showDetails(service.rid, service.uid, service.trainid)}
|
||||
>{service.trainid}</td
|
||||
>
|
||||
<td
|
||||
class="from from-data data {serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}"
|
||||
on:click={showDetails(service.rid, service.uid, service.trainid)}
|
||||
on:keypress={showDetails(service.rid, service.uid, service.trainid)}>{serviceStats.from}</td
|
||||
>
|
||||
<td
|
||||
class="to to-data data {serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}"
|
||||
on:click={showDetails(service.rid, service.uid, service.trainid)}
|
||||
on:keypress={showDetails(service.rid, service.uid, service.trainid)}>{serviceStats.to}</td
|
||||
>
|
||||
<td class="plat plat-data data {serviceStats.platformHidden && 'hidden'}">{serviceStats.platform.number || '-'}</td>
|
||||
<td class="time time-data data">{serviceStats.schArr}</td>
|
||||
<td
|
||||
class="time time-data data {serviceStats.canArr && 'can-time'} {serviceStats.isArrDelayed && 'late'} {serviceStats.isEarlyArr && 'early'} {serviceStats.isLateArr &&
|
||||
'late'}">{serviceStats.isArrDelayed ? 'LATE' : serviceStats.expArr}</td
|
||||
>
|
||||
<td class="time time-data data {serviceStats.isCancelled && 'can-dat'}">{serviceStats.schDep}</td>
|
||||
<td
|
||||
class="time time-data data {serviceStats.canDep && 'can-time'} {serviceStats.isDepDelayed && 'late'} {serviceStats.isEarlyDep && 'early'} {serviceStats.isLateDep &&
|
||||
'late'}">{serviceStats.isDepDelayed ? 'LATE' : serviceStats.expDep}</td
|
||||
>
|
||||
</tr>
|
||||
<tr class="text-row">
|
||||
<td colspan="8" class="text-data">
|
||||
{service.operator}
|
||||
{#if serviceStats.length} | {serviceStats.length} carriages{/if}
|
||||
<br />
|
||||
{#if service.cancelReason}
|
||||
<Reason type="cancel" code={service.cancelReason} />
|
||||
{/if}
|
||||
{#if service?.delayReason && !service.isCancelled}
|
||||
<Reason type="delay" code={service.delayReason} />
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
{:catch}
|
||||
<tr>
|
||||
<td colspan="8">Unable to load service</td>
|
||||
</tr>
|
||||
{/await}
|
@ -2,8 +2,10 @@
|
||||
export let station = '';
|
||||
export let title = 'Loading...';
|
||||
import { onMount } from 'svelte';
|
||||
import AlertBar from './alert-bar.svelte';
|
||||
import StaffTrainDetail from '$lib/ldb/staff-train-detail.svelte';
|
||||
import AlertBar from '../alert-bar.svelte';
|
||||
import ServiceRow from './service-row.svelte';
|
||||
import StaffTrainDetail from '$lib/ldb/staff/train-detail.svelte';
|
||||
import Reason from '$lib/raw-fetchers/reason.svelte';
|
||||
import Loading from '$lib/navigation/loading.svelte';
|
||||
import Nav from '$lib/navigation/nav.svelte';
|
||||
import { uuid } from '$lib/stores/uuid';
|
||||
@ -16,7 +18,7 @@
|
||||
let dataAge = null;
|
||||
let isLoading = true;
|
||||
let alerts = [];
|
||||
let detail = {show: false, rid:'',uid:'', headcode:''}
|
||||
let detail = { show: false, rid: '', uid: '', headcode: '' };
|
||||
|
||||
$: {
|
||||
if (jsonData?.GetBoardResult?.generatedAt) {
|
||||
@ -60,13 +62,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function getReasonCodeData(code) {
|
||||
const url = `https://owlboard.info/api/v2/ref/reasonCode/${code}`;
|
||||
const res = await fetch(url);
|
||||
const json = await res.json();
|
||||
return json;
|
||||
}
|
||||
|
||||
async function generateServiceData(service) {
|
||||
const timeDetails = await parseTimes(service);
|
||||
let serviceData = {
|
||||
@ -85,10 +80,12 @@
|
||||
isLateDep: timeDetails.delDep,
|
||||
isCancelledDep: false,
|
||||
isCancelled: Boolean(service?.isCancelled),
|
||||
canArr: timeDetails.canArr,
|
||||
canDep: timeDetails.canDep,
|
||||
isDelayed: service?.arrivalType === 'Delayed',
|
||||
isArrDelayed: service?.arrivalType === 'Delayed',
|
||||
isDepDelayed: service?.departureType === 'Delayed',
|
||||
isNonPublic: service?.isPassengerService === "false" ? true : false
|
||||
isNonPublic: service?.isPassengerService === 'false' ? true : false
|
||||
};
|
||||
return serviceData;
|
||||
}
|
||||
@ -104,7 +101,6 @@
|
||||
|
||||
async function parseLocation(location) {
|
||||
if (!Array.isArray(location.location)) {
|
||||
//console.log(location.location?.tiploc)
|
||||
return location.location?.tiploc;
|
||||
}
|
||||
let locations = [];
|
||||
@ -133,10 +129,12 @@
|
||||
let expDep = new Date(service?.etd || service?.atd);
|
||||
let isEarlyArr = false,
|
||||
isDelayedArr = false,
|
||||
isArr = false;
|
||||
isArr = false,
|
||||
canArr = false;
|
||||
let isEarlyDep = false,
|
||||
isDelayedDep = false,
|
||||
isDep = false;
|
||||
isDep = false,
|
||||
canDep = false;
|
||||
const timeDifferenceThreshold = 60 * 1000; // 60 seconds in milliseconds
|
||||
if (expArr - schArr < -timeDifferenceThreshold) {
|
||||
isEarlyArr = true;
|
||||
@ -160,6 +158,9 @@
|
||||
} else {
|
||||
parsedExpArr = parseIndividualTime(expArr);
|
||||
}
|
||||
} else if (service.isCancelled === 'true') {
|
||||
parsedExpArr = 'CANC';
|
||||
canArr = true;
|
||||
} else {
|
||||
parsedExpArr = '-';
|
||||
}
|
||||
@ -171,6 +172,9 @@
|
||||
} else {
|
||||
parsedExpDep = parseIndividualTime(expDep);
|
||||
}
|
||||
} else if (service.isCancelled === 'true') {
|
||||
parsedExpDep = 'CANC';
|
||||
canDep = true;
|
||||
} else {
|
||||
parsedExpDep = '-';
|
||||
}
|
||||
@ -182,7 +186,9 @@
|
||||
earArr: isEarlyArr,
|
||||
delArr: isDelayedArr,
|
||||
earDep: isEarlyDep,
|
||||
delDep: isDelayedDep
|
||||
delDep: isDelayedDep,
|
||||
canArr: canArr,
|
||||
canDep: canDep
|
||||
};
|
||||
}
|
||||
|
||||
@ -268,17 +274,29 @@
|
||||
</tr>
|
||||
{:then serviceStats}
|
||||
<tr class="{serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}">
|
||||
<td class="id id-data data" on:click={showDetails(service.rid, service.uid, service.trainid)} on:keypress={showDetails(service.rid, service.uid, service.trainid)}>{service.trainid}</td>
|
||||
<td class="from from-data data {serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}" on:click={showDetails(service.rid, service.uid, service.trainid)} on:keypress={showDetails(service.rid, service.uid, service.trainid)}>{serviceStats.from}</td>
|
||||
<td class="to to-data data {serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}" on:click={showDetails(service.rid, service.uid, service.trainid)} on:keypress={showDetails(service.rid, service.uid, service.trainid)}>{serviceStats.to}</td>
|
||||
<td class="id id-data data" on:click={showDetails(service.rid, service.uid, service.trainid)} on:keypress={showDetails(service.rid, service.uid, service.trainid)}
|
||||
>{service.trainid}</td
|
||||
>
|
||||
<td
|
||||
class="from from-data data {serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}"
|
||||
on:click={showDetails(service.rid, service.uid, service.trainid)}
|
||||
on:keypress={showDetails(service.rid, service.uid, service.trainid)}>{serviceStats.from}</td
|
||||
>
|
||||
<td
|
||||
class="to to-data data {serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}"
|
||||
on:click={showDetails(service.rid, service.uid, service.trainid)}
|
||||
on:keypress={showDetails(service.rid, service.uid, service.trainid)}>{serviceStats.to}</td
|
||||
>
|
||||
<td class="plat plat-data data {serviceStats.platformHidden && 'hidden'}">{serviceStats.platform.number || '-'}</td>
|
||||
<td class="time time-data data">{serviceStats.schArr}</td>
|
||||
<td class="time time-data data {serviceStats.isArrDelayed && 'late'} {serviceStats.isEarlyArr && 'early'} {serviceStats.isLateArr && 'late'}"
|
||||
>{serviceStats.isArrDelayed ? 'LATE' : serviceStats.expArr}</td
|
||||
<td
|
||||
class="time time-data data {serviceStats.canArr && 'can-time'} {serviceStats.isArrDelayed && 'late'} {serviceStats.isEarlyArr && 'early'} {serviceStats.isLateArr &&
|
||||
'late'}">{serviceStats.isArrDelayed ? 'LATE' : serviceStats.expArr}</td
|
||||
>
|
||||
<td class="time time-data data {serviceStats.isCancelled && 'can-dat'}">{serviceStats.schDep}</td>
|
||||
<td class="time time-data data {serviceStats.isDepDelayed && 'late'} {serviceStats.isEarlyDep && 'early'} {serviceStats.isLateDep && 'late'}"
|
||||
>{serviceStats.isDepDelayed ? 'LATE' : serviceStats.expDep}</td
|
||||
<td
|
||||
class="time time-data data {serviceStats.canDep && 'can-time'} {serviceStats.isDepDelayed && 'late'} {serviceStats.isEarlyDep && 'early'} {serviceStats.isLateDep &&
|
||||
'late'}">{serviceStats.isDepDelayed ? 'LATE' : serviceStats.expDep}</td
|
||||
>
|
||||
</tr>
|
||||
<tr class="text-row">
|
||||
@ -286,21 +304,11 @@
|
||||
{service.operator}
|
||||
{#if serviceStats.length} | {serviceStats.length} carriages{/if}
|
||||
<br />
|
||||
{#if service.isCancelled}
|
||||
{#await getReasonCodeData(service.cancelReason)}
|
||||
This train has been cancelled
|
||||
{:then reasonCode}
|
||||
{reasonCode[0].cancReason}
|
||||
<br />
|
||||
{/await}
|
||||
{#if service.cancelReason}
|
||||
<Reason type="cancel" code={service.cancelReason} />
|
||||
{/if}
|
||||
{#if service?.delayReason}
|
||||
{#await getReasonCodeData(service.delayReason)}
|
||||
This train has been delayed
|
||||
{:then reasonCode}
|
||||
{reasonCode[0].lateReason}
|
||||
<br />
|
||||
{/await}
|
||||
{#if service?.delayReason && !service.isCancelled}
|
||||
<Reason type="delay" code={service.delayReason} />
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
251
src/lib/ldb/staff/train-detail.svelte
Normal file
251
src/lib/ldb/staff/train-detail.svelte
Normal file
@ -0,0 +1,251 @@
|
||||
<script>
|
||||
import OverlayIsland from '$lib/islands/overlay-island.svelte';
|
||||
import Loading from '$lib/navigation/loading.svelte';
|
||||
import Reason from '$lib/raw-fetchers/reason.svelte';
|
||||
import { uuid } from '$lib/stores/uuid';
|
||||
export let detail = {
|
||||
uid: '',
|
||||
rid: '',
|
||||
headcode: '',
|
||||
show: true
|
||||
};
|
||||
export let close;
|
||||
|
||||
function handleClick() {
|
||||
close();
|
||||
}
|
||||
|
||||
async function getTrain(rid) {
|
||||
try {
|
||||
console.log(`Requested Station: ${rid}`);
|
||||
const url = `https://owlboard.info/api/v2/live/train/rid/${rid}`;
|
||||
const opt = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
uuid: $uuid
|
||||
}
|
||||
};
|
||||
const data = await fetch(url, opt);
|
||||
return await data.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function parseDelay(location) {
|
||||
let string, state;
|
||||
if (location?.lateness) {
|
||||
try {
|
||||
const result = Math.floor(location.lateness / 60);
|
||||
if (result === 0) {
|
||||
(string = 'RT'), (state = '');
|
||||
} else if (result < 0) {
|
||||
(string = -result + 'E'), (state = 'early');
|
||||
} else if (result > 0) {
|
||||
(string = result + 'L'), (state = 'late');
|
||||
}
|
||||
} catch {
|
||||
(string = ''), (state = '');
|
||||
}
|
||||
} else if (location.arrivalType === 'Delayed') {
|
||||
(string = ''), (state = 'late');
|
||||
} else {
|
||||
(string = ''), (state = 'noreport');
|
||||
}
|
||||
return {
|
||||
string: string,
|
||||
state: state
|
||||
};
|
||||
}
|
||||
|
||||
function parseTime(date) {
|
||||
const parsedTime = date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
return parsedTime !== 'Invalid Date' ? parsedTime : null;
|
||||
}
|
||||
|
||||
function parseTimes(service) {
|
||||
const sta = new Date(service.sta),
|
||||
eta = new Date(service.eta),
|
||||
ata = new Date(service.ata);
|
||||
const std = new Date(service.std),
|
||||
etd = new Date(service.etd),
|
||||
atd = new Date(service.atd);
|
||||
let parsedSta = parseTime(sta),
|
||||
parsedEta = parseTime(eta),
|
||||
parsedAta = parseTime(ata);
|
||||
let parsedStd = parseTime(std),
|
||||
parsedEtd = parseTime(etd),
|
||||
parsedAtd = parseTime(atd);
|
||||
if (service.isCancelled) {
|
||||
(parsedEta = 'CANC'), (parsedEtd = 'CANC');
|
||||
}
|
||||
let times = {
|
||||
sta: parsedSta || '-',
|
||||
eata: parsedEta || parsedAta || '-',
|
||||
aEst: parsedEta ? 'estimate' : '',
|
||||
std: parsedStd || '-',
|
||||
eatd: parsedEtd || parsedAtd || '-',
|
||||
dEst: parsedEtd ? 'estimate' : ''
|
||||
};
|
||||
if (service.isCancelled) {
|
||||
(parsedEta = 'CANC'), (parsedEtd = 'CANC');
|
||||
(times.aEst = 'canc'), (times.dEst = 'canc');
|
||||
}
|
||||
return times;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<OverlayIsland>
|
||||
<div id="detailBox">
|
||||
{#await getTrain(detail.rid)}
|
||||
<h6>{detail.headcode}</h6>
|
||||
<Loading />
|
||||
{:then train}
|
||||
<h6>{train.GetServiceDetailsResult.operatorCode}: {detail.headcode}</h6>
|
||||
<button type="button" id="closeService" on:click={handleClick}>X</button>
|
||||
<p>
|
||||
Locations in grey are not scheduled stops
|
||||
<br />
|
||||
Times in <span class="estimate">yellow</span> are estimated times
|
||||
</p>
|
||||
<table id="detailTable">
|
||||
{#if train.GetServiceDetailsResult.delayReason}
|
||||
<tr><td colspan="7">
|
||||
<Reason type="delay" code={train.GetServiceDetailsResult.delayReason} />
|
||||
</td></tr>
|
||||
{/if}
|
||||
{#if train.GetServiceDetailsResult.cancelReason}
|
||||
<tr><td colspan="7">
|
||||
<Reason type="cancel" code={train.GetServiceDetailsResult.cancelReason} />
|
||||
</td></tr>
|
||||
{/if}
|
||||
<tr>
|
||||
<th colspan="2" />
|
||||
<th colspan="2">Arrival</th>
|
||||
<th colspan="2">Departure</th>
|
||||
<th />
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tableLocation">Location</th>
|
||||
<th class="tablePlatform">Pl.</th>
|
||||
<th class="tableTime">Sch</th>
|
||||
<th class="tableTime">Est/Act</th>
|
||||
<th class="tableTime">Sch</th>
|
||||
<th class="tableTime">Est/Act</th>
|
||||
<th class="tableDelay" />
|
||||
</tr>
|
||||
{#each train.GetServiceDetailsResult.locations.location as location}
|
||||
<tr>
|
||||
<td class={location?.isPass === 'true' ? 'pass' : ''}>{location.tiploc}</td>
|
||||
<td class={location?.isPass === 'true' ? 'pass' : ''}>{location.platform || ''}</td>
|
||||
{#await parseTimes(location)}
|
||||
<td />
|
||||
<td />
|
||||
<td />
|
||||
<td />
|
||||
{:then times}
|
||||
<td class={location?.isPass === 'true' ? 'pass' : ''}>{times.sta}</td>
|
||||
<td class="{location?.isPass === 'true' ? 'pass' : ''} {times.aEst}">{times.eata}</td>
|
||||
<td class={location?.isPass === 'true' ? 'pass' : ''}>{times.std}</td>
|
||||
<td class="{location?.isPass === 'true' ? 'pass' : ''} {times.dEst}">{times.eatd}</td>
|
||||
{/await}
|
||||
{#await parseDelay(location)}
|
||||
<td>-</td>
|
||||
{:then delay}
|
||||
<td class={delay.state}>{delay.string}</td>
|
||||
{/await}
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
{:catch}
|
||||
<h6>Error loading data</h6>
|
||||
{/await}
|
||||
</div>
|
||||
</OverlayIsland>
|
||||
|
||||
<style>
|
||||
#detailBox {
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
h6 {
|
||||
position: absolute;
|
||||
top: -25px;
|
||||
left: 20px;
|
||||
font-size: 18px;
|
||||
}
|
||||
p {
|
||||
margin-top: 45px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
#closeService {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
border: none;
|
||||
border-radius: 60px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
background-color: var(--main-bg-color);
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
}
|
||||
#detailTable {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
}
|
||||
.tableLocation {
|
||||
width: 25%;
|
||||
}
|
||||
.tablePlatform {
|
||||
width: 8%;
|
||||
}
|
||||
.tableTime {
|
||||
width: 15%;
|
||||
}
|
||||
.tableDelay {
|
||||
width: 7%;
|
||||
}
|
||||
.estimate {
|
||||
color: rgb(255, 255, 50);
|
||||
}
|
||||
.pass {
|
||||
opacity: 0.45;
|
||||
font-size: 16px;
|
||||
}
|
||||
.canc {
|
||||
animation: pulse-cancel 1.5s linear infinite;
|
||||
}
|
||||
|
||||
.early {
|
||||
animation: pulse-early 1.5s linear infinite;
|
||||
}
|
||||
|
||||
.late {
|
||||
animation: pulse-late 1.5s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-late {
|
||||
50% {
|
||||
color: var(--main-warning-color);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse-cancel {
|
||||
50% {
|
||||
color: var(--main-alert-color);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse-early {
|
||||
50% {
|
||||
color: rgb(136, 164, 255);
|
||||
}
|
||||
}
|
||||
</style>
|
50
src/lib/raw-fetchers/reason.svelte
Normal file
50
src/lib/raw-fetchers/reason.svelte
Normal file
@ -0,0 +1,50 @@
|
||||
<script>
|
||||
|
||||
import { uuid } from "$lib/stores/uuid";
|
||||
|
||||
export let code = '';
|
||||
export let type = '';
|
||||
|
||||
async function getDelay(code = '') {
|
||||
console.log(`Fetching delay reason ${code}`)
|
||||
const data = await getReason(code);
|
||||
return data[0].lateReason || 'This train has been delayed';
|
||||
}
|
||||
|
||||
async function getCancel(code = '') {
|
||||
console.log(`Fetching cancel reason ${code}`)
|
||||
const data = await getReason(code);
|
||||
return data[0].cancReason || 'This train has been cancelled';
|
||||
}
|
||||
|
||||
async function getReason(code = '') {
|
||||
const url = `https://owlboard.info/api/v2/ref/reasonCode/${code}`;
|
||||
const options = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
uuid: $uuid
|
||||
}
|
||||
};
|
||||
const res = await fetch(url, options);
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{#if type === "cancel"}
|
||||
{#await getCancel(code)}
|
||||
This train has been cancelled
|
||||
{:then reason}
|
||||
{reason}
|
||||
{:catch}
|
||||
This train has been cancelled
|
||||
{/await}
|
||||
{:else if type === "delay"}
|
||||
{#await getDelay(code)}
|
||||
This train has been delayed
|
||||
{:then reason}
|
||||
{reason}
|
||||
{:catch}
|
||||
This train has been delayed
|
||||
{/await}
|
||||
{/if}
|
@ -2,7 +2,7 @@
|
||||
import Header from '$lib/navigation/header.svelte';
|
||||
import Nav from '$lib/navigation/nav-ldb.svelte';
|
||||
import PublicLdb from '$lib/ldb/public-ldb.svelte';
|
||||
import StaffLdb from '$lib/ldb/staff-ldb.svelte';
|
||||
import StaffLdb from '$lib/ldb/staff/staff-ldb.svelte';
|
||||
import { uuid } from '$lib/stores/uuid.js';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user