Modulisation and additions to StaffLDB
This commit is contained in:
parent
cb8aff5788
commit
5a6fe0f3f5
@ -23,7 +23,7 @@
|
|||||||
transform: translateY(-50%) translateX(-50%);
|
transform: translateY(-50%) translateX(-50%);
|
||||||
width: 85%;
|
width: 85%;
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: 75vh;
|
max-height: 85vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
margin: auto;
|
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 station = '';
|
||||||
export let title = 'Loading...';
|
export let title = 'Loading...';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import AlertBar from './alert-bar.svelte';
|
import AlertBar from '../alert-bar.svelte';
|
||||||
import StaffTrainDetail from '$lib/ldb/staff-train-detail.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 Loading from '$lib/navigation/loading.svelte';
|
||||||
import Nav from '$lib/navigation/nav.svelte';
|
import Nav from '$lib/navigation/nav.svelte';
|
||||||
import { uuid } from '$lib/stores/uuid';
|
import { uuid } from '$lib/stores/uuid';
|
||||||
@ -16,7 +18,7 @@
|
|||||||
let dataAge = null;
|
let dataAge = null;
|
||||||
let isLoading = true;
|
let isLoading = true;
|
||||||
let alerts = [];
|
let alerts = [];
|
||||||
let detail = {show: false, rid:'',uid:'', headcode:''}
|
let detail = { show: false, rid: '', uid: '', headcode: '' };
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (jsonData?.GetBoardResult?.generatedAt) {
|
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) {
|
async function generateServiceData(service) {
|
||||||
const timeDetails = await parseTimes(service);
|
const timeDetails = await parseTimes(service);
|
||||||
let serviceData = {
|
let serviceData = {
|
||||||
@ -85,10 +80,12 @@
|
|||||||
isLateDep: timeDetails.delDep,
|
isLateDep: timeDetails.delDep,
|
||||||
isCancelledDep: false,
|
isCancelledDep: false,
|
||||||
isCancelled: Boolean(service?.isCancelled),
|
isCancelled: Boolean(service?.isCancelled),
|
||||||
|
canArr: timeDetails.canArr,
|
||||||
|
canDep: timeDetails.canDep,
|
||||||
isDelayed: service?.arrivalType === 'Delayed',
|
isDelayed: service?.arrivalType === 'Delayed',
|
||||||
isArrDelayed: service?.arrivalType === 'Delayed',
|
isArrDelayed: service?.arrivalType === 'Delayed',
|
||||||
isDepDelayed: service?.departureType === 'Delayed',
|
isDepDelayed: service?.departureType === 'Delayed',
|
||||||
isNonPublic: service?.isPassengerService === "false" ? true : false
|
isNonPublic: service?.isPassengerService === 'false' ? true : false
|
||||||
};
|
};
|
||||||
return serviceData;
|
return serviceData;
|
||||||
}
|
}
|
||||||
@ -104,7 +101,6 @@
|
|||||||
|
|
||||||
async function parseLocation(location) {
|
async function parseLocation(location) {
|
||||||
if (!Array.isArray(location.location)) {
|
if (!Array.isArray(location.location)) {
|
||||||
//console.log(location.location?.tiploc)
|
|
||||||
return location.location?.tiploc;
|
return location.location?.tiploc;
|
||||||
}
|
}
|
||||||
let locations = [];
|
let locations = [];
|
||||||
@ -133,10 +129,12 @@
|
|||||||
let expDep = new Date(service?.etd || service?.atd);
|
let expDep = new Date(service?.etd || service?.atd);
|
||||||
let isEarlyArr = false,
|
let isEarlyArr = false,
|
||||||
isDelayedArr = false,
|
isDelayedArr = false,
|
||||||
isArr = false;
|
isArr = false,
|
||||||
|
canArr = false;
|
||||||
let isEarlyDep = false,
|
let isEarlyDep = false,
|
||||||
isDelayedDep = false,
|
isDelayedDep = false,
|
||||||
isDep = false;
|
isDep = false,
|
||||||
|
canDep = false;
|
||||||
const timeDifferenceThreshold = 60 * 1000; // 60 seconds in milliseconds
|
const timeDifferenceThreshold = 60 * 1000; // 60 seconds in milliseconds
|
||||||
if (expArr - schArr < -timeDifferenceThreshold) {
|
if (expArr - schArr < -timeDifferenceThreshold) {
|
||||||
isEarlyArr = true;
|
isEarlyArr = true;
|
||||||
@ -160,6 +158,9 @@
|
|||||||
} else {
|
} else {
|
||||||
parsedExpArr = parseIndividualTime(expArr);
|
parsedExpArr = parseIndividualTime(expArr);
|
||||||
}
|
}
|
||||||
|
} else if (service.isCancelled === 'true') {
|
||||||
|
parsedExpArr = 'CANC';
|
||||||
|
canArr = true;
|
||||||
} else {
|
} else {
|
||||||
parsedExpArr = '-';
|
parsedExpArr = '-';
|
||||||
}
|
}
|
||||||
@ -171,6 +172,9 @@
|
|||||||
} else {
|
} else {
|
||||||
parsedExpDep = parseIndividualTime(expDep);
|
parsedExpDep = parseIndividualTime(expDep);
|
||||||
}
|
}
|
||||||
|
} else if (service.isCancelled === 'true') {
|
||||||
|
parsedExpDep = 'CANC';
|
||||||
|
canDep = true;
|
||||||
} else {
|
} else {
|
||||||
parsedExpDep = '-';
|
parsedExpDep = '-';
|
||||||
}
|
}
|
||||||
@ -182,7 +186,9 @@
|
|||||||
earArr: isEarlyArr,
|
earArr: isEarlyArr,
|
||||||
delArr: isDelayedArr,
|
delArr: isDelayedArr,
|
||||||
earDep: isEarlyDep,
|
earDep: isEarlyDep,
|
||||||
delDep: isDelayedDep
|
delDep: isDelayedDep,
|
||||||
|
canArr: canArr,
|
||||||
|
canDep: canDep
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,17 +274,29 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{:then serviceStats}
|
{:then serviceStats}
|
||||||
<tr class="{serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}">
|
<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="id id-data data" on:click={showDetails(service.rid, service.uid, service.trainid)} on:keypress={showDetails(service.rid, service.uid, service.trainid)}
|
||||||
<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>
|
>{service.trainid}</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="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="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.schArr}</td>
|
||||||
<td class="time time-data data {serviceStats.isArrDelayed && 'late'} {serviceStats.isEarlyArr && 'early'} {serviceStats.isLateArr && 'late'}"
|
<td
|
||||||
>{serviceStats.isArrDelayed ? 'LATE' : serviceStats.expArr}</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.isCancelled && 'can-dat'}">{serviceStats.schDep}</td>
|
||||||
<td class="time time-data data {serviceStats.isDepDelayed && 'late'} {serviceStats.isEarlyDep && 'early'} {serviceStats.isLateDep && 'late'}"
|
<td
|
||||||
>{serviceStats.isDepDelayed ? 'LATE' : serviceStats.expDep}</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>
|
||||||
<tr class="text-row">
|
<tr class="text-row">
|
||||||
@ -286,21 +304,11 @@
|
|||||||
{service.operator}
|
{service.operator}
|
||||||
{#if serviceStats.length} | {serviceStats.length} carriages{/if}
|
{#if serviceStats.length} | {serviceStats.length} carriages{/if}
|
||||||
<br />
|
<br />
|
||||||
{#if service.isCancelled}
|
{#if service.cancelReason}
|
||||||
{#await getReasonCodeData(service.cancelReason)}
|
<Reason type="cancel" code={service.cancelReason} />
|
||||||
This train has been cancelled
|
|
||||||
{:then reasonCode}
|
|
||||||
{reasonCode[0].cancReason}
|
|
||||||
<br />
|
|
||||||
{/await}
|
|
||||||
{/if}
|
{/if}
|
||||||
{#if service?.delayReason}
|
{#if service?.delayReason && !service.isCancelled}
|
||||||
{#await getReasonCodeData(service.delayReason)}
|
<Reason type="delay" code={service.delayReason} />
|
||||||
This train has been delayed
|
|
||||||
{:then reasonCode}
|
|
||||||
{reasonCode[0].lateReason}
|
|
||||||
<br />
|
|
||||||
{/await}
|
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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 Header from '$lib/navigation/header.svelte';
|
||||||
import Nav from '$lib/navigation/nav-ldb.svelte';
|
import Nav from '$lib/navigation/nav-ldb.svelte';
|
||||||
import PublicLdb from '$lib/ldb/public-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 { uuid } from '$lib/stores/uuid.js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user