owlboard-svelte/src/lib/ldb/public-ldb.svelte

566 lines
15 KiB
Svelte
Raw Normal View History

2023-06-16 22:55:18 +01:00
<script>
2023-07-07 11:27:28 +01:00
export let station = '';
export let title = 'Loading...';
import { onMount } from 'svelte';
2023-06-17 21:48:00 +01:00
import Loading from '$lib/navigation/loading.svelte';
2023-07-07 11:27:28 +01:00
import OverlayIsland from '$lib/islands/overlay-island.svelte';
import AlertBar from './alert-bar.svelte';
2023-06-17 12:04:59 +01:00
let requestedStation;
$: requestedStation = station;
let jsonData = null;
let services = [];
2023-06-19 14:21:17 +01:00
let busServices = [];
let ferryServices = [];
2023-06-17 15:12:30 +01:00
let dataAge = null;
let isLoading = true;
2023-06-19 19:42:41 +01:00
let dataExists = false;
2023-06-28 21:23:29 +01:00
let alerts = [];
2023-06-26 21:56:19 +01:00
let serviceDetail;
2023-06-17 12:04:59 +01:00
$: {
2023-07-07 11:27:28 +01:00
if (jsonData === null && requestedStation) {
fetchData();
}
2023-06-17 12:04:59 +01:00
2023-07-07 11:27:28 +01:00
if (jsonData?.GetStationBoardResult?.generatedAt) {
dataAge = new Date(jsonData.GetStationBoardResult.generatedAt);
}
2023-06-19 14:21:17 +01:00
2023-07-07 11:27:28 +01:00
if (jsonData?.GetStationBoardResult?.trainServices?.service) {
services = jsonData.GetStationBoardResult.trainServices.service;
} else {
services = [];
}
2023-06-17 12:04:59 +01:00
2023-07-07 11:27:28 +01:00
if (jsonData?.GetStationBoardResult?.busServices?.service) {
busServices = jsonData.GetStationBoardResult.busServices.service;
2023-06-17 01:53:08 +01:00
}
2023-06-16 22:55:18 +01:00
2023-07-07 11:27:28 +01:00
if (jsonData?.GetStationBoardResult?.ferryServices?.service) {
ferryServices = jsonData.GetStationBoardResult.ferryServices.service;
}
if (jsonData?.GetStationBoardResult?.locationName) {
title = jsonData.GetStationBoardResult.locationName;
} else {
title = requestedStation.toUpperCase();
}
}
2023-06-17 12:04:59 +01:00
async function fetchData() {
2023-06-19 19:42:41 +01:00
dataExists = true;
2023-06-17 15:12:30 +01:00
isLoading = true; // Set loading state
try {
console.log(`Requested Station: ${requestedStation}`);
2023-07-07 11:27:28 +01:00
const data = await fetch(
`https://owlboard.info/api/v1/ldb/${requestedStation}`
);
2023-06-17 15:12:30 +01:00
jsonData = await data.json();
} catch (error) {
2023-07-07 11:27:28 +01:00
console.error('Error fetching data:', error);
2023-06-19 19:42:41 +01:00
dataExists = false;
2023-07-07 11:27:28 +01:00
title = 'Not Found';
2023-06-17 15:12:30 +01:00
} finally {
isLoading = false; // Clear loading state
}
2023-07-07 11:27:28 +01:00
prepareNrcc();
2023-06-17 15:12:30 +01:00
}
2023-07-07 11:27:28 +01:00
function parseTime(string) {
let output;
let change;
2023-06-17 15:12:30 +01:00
switch (string) {
2023-07-07 11:27:28 +01:00
case 'Delayed':
output = 'LATE';
change = 'changed';
break;
case 'Cancelled':
output = 'CANC';
change = 'cancelled';
break;
case 'On Time':
case 'On time':
output = 'RT';
change = '';
break;
case '':
output = '-';
change = '';
break;
case undefined:
output = '-';
change = '';
break;
case 'No report':
output = '-';
change = '';
break;
case 'undefined':
output = false;
change = '';
break;
default:
output = string;
change = 'changed';
2023-06-17 15:12:30 +01:00
}
2023-07-07 11:27:28 +01:00
return { data: output, changed: change };
2023-06-17 12:04:59 +01:00
}
2023-06-16 22:55:18 +01:00
2023-06-26 21:56:19 +01:00
async function loadService(sid) {
for (const service of services) {
if (service.serviceID == sid) {
2023-07-07 11:27:28 +01:00
serviceDetail = service;
2023-06-26 21:56:19 +01:00
}
}
}
async function loadBusService(sid) {
for (const service of busServices) {
if (service.serviceID == sid) {
2023-07-07 11:27:28 +01:00
serviceDetail = service;
}
}
}
2023-06-26 21:56:19 +01:00
async function closeService() {
serviceDetail = null;
}
2023-06-28 21:23:29 +01:00
async function prepareNrcc() {
if (jsonData?.GetStationBoardResult?.nrccMessages?.message) {
const nrcc = jsonData.GetStationBoardResult.nrccMessages.message;
if (Array.isArray(nrcc)) {
2023-07-07 11:27:28 +01:00
alerts = nrcc;
2023-06-28 21:23:29 +01:00
return;
}
alerts.push(nrcc);
return;
}
}
2023-06-17 12:04:59 +01:00
onMount(() => {
if (requestedStation && jsonData === null) {
fetchData();
}
});
</script>
2023-06-28 21:23:29 +01:00
{#if alerts.length}
2023-07-07 11:27:28 +01:00
<AlertBar {alerts} />
2023-06-28 21:23:29 +01:00
{/if}
2023-06-17 15:12:30 +01:00
{#if isLoading}
2023-06-17 21:48:00 +01:00
<Loading />
2023-07-07 11:27:28 +01:00
{:else if dataAge}
<p id="timestamp">Updated: {dataAge.toLocaleTimeString()}</p>
{#if services.length}
<table class="ldbTable">
<tr>
<th class="from">From</th>
<th class="to">To</th>
<th class="plat">Plat.</th>
<th class="time">Sch Arr.</th>
<th class="time">Exp Arr.</th>
<th class="time">Sch Dep.</th>
<th class="time">Exp Dep.</th>
</tr>
{#each services as service}
2023-06-19 14:21:17 +01:00
<tr>
2023-07-07 11:27:28 +01:00
<td
class="origdest from"
on:click={loadService(service.serviceID)}
on:keypress={loadService(service.serviceID)}
>
{#if Array.isArray(service.origin?.location)}
{service.origin.location[0]['locationName'] +
' & ' +
service.origin.location[1]['locationName']}
{:else}
{service.origin?.location?.locationName || ''}
{/if}
</td>
<td
class="origdest to"
on:click={loadService(service.serviceID)}
on:keypress={loadService(service.serviceID)}
>
{#if Array.isArray(service.destination?.location)}
{service.destination.location[0]['locationName'] +
' & ' +
service.destination.location[0]['locationName']}
{:else}
{service.destination?.location?.locationName || ''}
{/if}
</td>
<td class="plat">{service.platform || '-'}</td>
<td class="time">{parseTime(service.sta).data}</td>
<td class="time {parseTime(service.eta).changed}"
>{parseTime(service.eta).data}</td
>
<td class="time">{parseTime(service.std).data}</td>
<td class="time {parseTime(service.etd).changed}"
>{parseTime(service.etd).data}</td
>
2023-06-19 14:21:17 +01:00
</tr>
2023-07-07 11:27:28 +01:00
<tr
><td colspan="7">
2023-06-19 19:42:41 +01:00
<p class="service-detail">
A {service.operator || 'Unknown'} service
{#if service['length']}
with {service['length'] || 'some'} coaches
{/if}
</p>
{#if service.delayReason}
<p class="service-detail">{service.delayReason}</p>
2023-06-19 14:21:17 +01:00
{/if}
2023-06-19 19:42:41 +01:00
{#if service.cancelReason}
<p class="service-detail">{service.cancelReason}</p>
{/if}
2023-07-07 11:27:28 +01:00
</td></tr
>
{/each}
</table>
{:else}
<p class="table-head-text">No Scheduled Train Services</p>
{/if}
{#if busServices.length}
<br />
<img
class="transport-mode"
src="/images/transport-modes/bus.svg"
alt="Bus services"
/><br />
<span class="table-head-text">Bus Services</span>
<table class="ldbTable">
<tr>
<th class="from">From</th>
<th class="to">To</th>
<th class="time">Sch Arr.</th>
<th class="time">Exp Arr.</th>
<th class="time">Sch Dep.</th>
<th class="time">Exp Dep.</th>
</tr>
{#each busServices as service}
2023-06-19 14:21:17 +01:00
<tr>
2023-07-07 11:27:28 +01:00
<td
class="origdest from"
on:click={loadBusService(service.serviceID)}
on:keypress={loadBusService(service.serviceID)}
>{service.origin?.location?.locationName || ''}</td
>
<td
class="origdest to"
on:click={loadBusService(service.serviceID)}
on:keypress={loadBusService(service.serviceID)}
>{service.destination?.location?.locationName || ''}</td
>
<td class="time">{parseTime(service.sta).data}</td>
<td class="time {parseTime(service.eta).changed}"
>{parseTime(service.eta).data}</td
>
<td class="time">{parseTime(service.std).data}</td>
<td class="time {parseTime(service.etd).changed}"
>{parseTime(service.etd).data}</td
>
2023-06-19 14:21:17 +01:00
</tr>
2023-06-16 22:55:18 +01:00
2023-07-07 11:27:28 +01:00
<tr
><td colspan="7">
2023-06-19 19:42:41 +01:00
<p class="service-detail">
A {service.operator || 'Unknown'} service
</p>
{#if service.delayReason}
<p class="service-detail">{service.delayReason}</p>
{/if}
{#if service.cancelReason}
<p class="service-detail">{service.cancelReason}</p>
{/if}
2023-07-07 11:27:28 +01:00
</td></tr
>
{/each}
</table>
{/if}
{#if ferryServices.length}
<br />
<img
class="transport-mode"
src="/images/transport-modes/ferry.svg"
alt="Bus services"
/><br />
<span class="table-head-text">Ferry Services</span>
<table class="ldbTable">
<tr>
<th class="from">From</th>
<th class="to">To</th>
<th class="time">Sch Arr.</th>
<th class="time">Exp Arr.</th>
<th class="time">Sch Dep.</th>
<th class="time">Exp Dep.</th>
</tr>
{#each ferryServices as service}
2023-06-19 14:21:17 +01:00
<tr>
2023-07-07 11:27:28 +01:00
<td class="origdest from"
>{service.origin?.location?.locationName || ''}</td
>
<td class="origdest to"
>{service.destination?.location?.locationName || ''}</td
>
<td class="time">{parseTime(service.sta).data}</td>
<td class="time {parseTime(service.eta).changed}"
>{parseTime(service.eta).data}</td
>
<td class="time">{parseTime(service.std).data}</td>
<td class="time {parseTime(service.etd).changed}"
>{parseTime(service.etd).data}</td
>
2023-06-19 14:21:17 +01:00
</tr>
2023-07-07 11:27:28 +01:00
<tr
><td colspan="7">
2023-06-19 19:42:41 +01:00
{#if service.delayReason}
<p class="service-detail">{service.delayReason}</p>
{/if}
{#if service.cancelReason}
<p class="service-detail">{service.cancelReason}</p>
{/if}
2023-07-07 11:27:28 +01:00
</td></tr
>
{/each}
</table>
2023-06-19 14:21:17 +01:00
{/if}
2023-07-07 11:27:28 +01:00
{:else}
<p>Unable to find this station</p>
2023-06-17 15:12:30 +01:00
{/if}
2023-06-26 21:56:19 +01:00
{#if serviceDetail}
<OverlayIsland>
2023-07-01 22:06:01 +01:00
<div id="detailBox">
<h6>Service Detail</h6>
<button type="button" id="closeService" on:click={closeService}>X</button>
<table id="detailTable">
<tr>
<th>Location</th>
<th>Sch</th>
<th>Exp</th>
</tr>
{#if serviceDetail?.previousCallingPoints?.callingPointList?.callingPoint}
{#if Array.isArray(serviceDetail?.previousCallingPoints?.callingPointList?.callingPoint)}
{#each serviceDetail.previousCallingPoints.callingPointList.callingPoint as prevPoint}
<tr>
<td>{prevPoint.locationName}</td>
<td>{prevPoint.st}</td>
2023-07-07 11:27:28 +01:00
<td
class="time {parseTime(prevPoint.at || prevPoint.et).changed}"
>{parseTime(prevPoint.at || prevPoint.et).data}</td
>
2023-07-01 22:06:01 +01:00
</tr>
{/each}
{:else}
<tr>
2023-07-07 11:27:28 +01:00
<td
>{serviceDetail.previousCallingPoints.callingPointList
.callingPoint.locationName}</td
>
<td
>{serviceDetail.previousCallingPoints.callingPointList
.callingPoint.st}</td
>
<td
class="time {parseTime(
serviceDetail.previousCallingPoints.callingPointList
.callingPoint.at ||
serviceDetail.previousCallingPoints.callingPointList
.callingPoint.et
).changed}"
>{parseTime(
serviceDetail.previousCallingPoints.callingPointList
.callingPoint.at ||
serviceDetail.previousCallingPoints.callingPointList
.callingPoint.et
).data}</td
>
</tr>
2023-07-01 22:06:01 +01:00
{/if}
{/if}
2023-07-01 22:06:01 +01:00
<tr class="thisStop">
<td>{title}</td>
<td>{serviceDetail.std || serviceDetail.sta}</td>
2023-07-07 11:27:28 +01:00
<td
class="time {parseTime(serviceDetail.etd || serviceDetail.eta)
.changed}"
>{parseTime(serviceDetail.etd || serviceDetail.eta).data}</td
>
2023-07-01 22:06:01 +01:00
</tr>
{#if serviceDetail?.subsequentCallingPoints?.callingPointList?.callingPoint}
{#if Array.isArray(serviceDetail?.subsequentCallingPoints?.callingPointList?.callingPoint)}
{#each serviceDetail.subsequentCallingPoints.callingPointList.callingPoint as nextPoint}
<tr>
<td>{nextPoint.locationName}</td>
<td>{nextPoint.st}</td>
2023-07-07 11:27:28 +01:00
<td class="time {parseTime(nextPoint.et).changed}"
>{parseTime(nextPoint.et).data}</td
>
2023-07-01 22:06:01 +01:00
</tr>
{/each}
{:else}
<tr class="detailRow">
2023-07-07 11:27:28 +01:00
<td
>{serviceDetail.subsequentCallingPoints.callingPointList
.callingPoint.locationName}</td
>
<td
>{serviceDetail.subsequentCallingPoints.callingPointList
.callingPoint.st}</td
>
<td
class="time {parseTime(
serviceDetail.subsequentCallingPoints.callingPointList
.callingPoint.et
).changed}"
>{parseTime(
serviceDetail.subsequentCallingPoints.callingPointList
.callingPoint.et
).data}</td
>
</tr>
2023-07-01 22:06:01 +01:00
{/if}
{/if}
2023-07-01 22:06:01 +01:00
</table>
</div>
2023-06-26 21:56:19 +01:00
</OverlayIsland>
{/if}
2023-06-16 22:55:18 +01:00
<style>
2023-06-17 15:12:30 +01:00
#timestamp {
margin: auto;
text-align: left;
2023-06-19 18:26:18 +01:00
font-size: 14px;
2023-06-17 15:12:30 +01:00
}
2023-07-01 22:06:01 +01:00
.ldbTable {
2023-06-17 12:04:59 +01:00
width: 100%;
2023-07-01 22:06:01 +01:00
min-width: 300px;
2023-06-17 12:04:59 +01:00
margin: auto;
2023-07-01 22:06:01 +01:00
padding-right: 2px;
padding-left: 0px;
2023-06-17 12:04:59 +01:00
color: white;
2023-06-17 15:12:30 +01:00
font-size: 13px;
}
.service-detail {
color: cyan;
text-align: left;
font-size: 12px;
padding: 0;
margin: 0;
2023-06-17 12:04:59 +01:00
}
2023-06-19 18:26:18 +01:00
.transport-mode {
width: 30px;
}
.table-head-text {
color: white;
font-size: 14px;
}
2023-07-07 11:27:28 +01:00
@media (min-width: 800px) {
table {
font-size: 15px;
max-width: 850px;
}
.service-detail {
font-size: 14px;
}
.transport-mode {
width: 50px;
}
#timestamp {
font-size: 16px;
}
}
@media (min-width: 1000px) {
table {
font-size: 17px;
}
.service-detail {
font-size: 16px;
}
.table-head-text {
font-size: 16px;
}
}
@media (min-width: 1600px) {
table {
font-size: 19px;
}
.service-detail {
font-size: 18px;
}
}
2023-06-17 12:04:59 +01:00
.origdest {
color: yellow;
}
.from {
width: 25%;
text-align: left;
2023-06-17 12:04:59 +01:00
}
.to {
width: 25%;
text-align: left;
2023-06-17 12:04:59 +01:00
}
.plat {
2023-07-07 11:27:28 +01:00
width: 10%;
2023-06-17 12:04:59 +01:00
}
.time {
width: 10%;
}
2023-07-07 11:27:28 +01:00
.changed {
2023-06-17 15:12:30 +01:00
animation: pulse-change 1.5s linear infinite;
2023-07-07 11:27:28 +01:00
}
2023-06-17 15:12:30 +01:00
2023-07-07 11:27:28 +01:00
.cancelled {
2023-06-17 15:12:30 +01:00
animation: pulse-cancel 1.5s linear infinite;
2023-07-07 11:27:28 +01:00
}
2023-06-17 15:12:30 +01:00
2023-07-07 11:27:28 +01:00
@keyframes pulse-change {
2023-06-17 15:12:30 +01:00
50% {
2023-07-07 11:27:28 +01:00
color: var(--main-warning-color);
2023-06-17 15:12:30 +01:00
}
2023-07-07 11:27:28 +01:00
}
2023-06-17 15:12:30 +01:00
2023-07-07 11:27:28 +01:00
@keyframes pulse-cancel {
2023-06-17 15:12:30 +01:00
50% {
2023-07-07 11:27:28 +01:00
color: var(--main-alert-color);
2023-06-17 15:12:30 +01:00
}
2023-07-07 11:27:28 +01:00
}
#detailBox {
width: 100%;
}
h6 {
position: absolute;
top: -25px;
left: 20px;
font-size: 18px;
}
#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 {
margin-top: 40px;
color: white;
font-size: 15px;
}
.thisStop {
color: yellow;
}
2023-06-17 12:04:59 +01:00
</style>