519 lines
25 KiB
PHP
519 lines
25 KiB
PHP
<?php
|
|
/**
|
|
* Spacetraders ship details page.
|
|
*
|
|
* @package SpacetradersAPI
|
|
* @author Keith Solomon <keith@keithsolomon.net>
|
|
* @license MIT License
|
|
* @version GIT: <git_id>
|
|
* @link https://git.keithsolomon.net/keith/Spacetraders
|
|
*/
|
|
|
|
require_once __DIR__ . '/lib/spacetraders-api.php';
|
|
require_once __DIR__ . '/lib/spacetraders-storage.php';
|
|
|
|
$config = require __DIR__ . '/lib/project-config.php';
|
|
|
|
$storage = new SpacetradersStorage( $config['db_path'] );
|
|
$token = $storage->getAgentToken();
|
|
|
|
$statusMessage = '';
|
|
$errorMessage = '';
|
|
$ship = array();
|
|
$shipList = array();
|
|
$shipSymbol = isset( $_GET['ship'] ) ? trim( (string) $_GET['ship'] ) : '';
|
|
|
|
if (! is_string( $token ) || trim( $token ) === '' ) {
|
|
$envToken = getenv( 'SPACETRADERS_TOKEN' );
|
|
|
|
if (is_string( $envToken ) && trim( $envToken ) !== '' ) {
|
|
$token = trim( $envToken );
|
|
$storage->setAgentToken( $token );
|
|
}
|
|
}
|
|
|
|
if (! is_string( $token ) || trim( $token ) === '' ) {
|
|
$tokenError = 'No token found. Set one in config.php or SPACETRADERS_TOKEN.';
|
|
}
|
|
|
|
if (! isset( $tokenError ) ) {
|
|
$client = new SpacetradersApi(
|
|
trim( $token ),
|
|
$config['api_base_url'],
|
|
(int) $config['api_timeout'],
|
|
$storage,
|
|
(int) $config['cache_ttl']
|
|
);
|
|
}
|
|
|
|
try {
|
|
if (! isset( $tokenError ) ) {
|
|
$shipListResponse = $client->listMyShips();
|
|
$shipList = $shipListResponse['data'] ?? array();
|
|
|
|
if ($shipSymbol === '' && ! empty( $shipList ) ) {
|
|
$shipSymbol = (string) ( $shipList[0]['symbol'] ?? '' );
|
|
}
|
|
|
|
if ($shipSymbol !== '' ) {
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_POST['ship_action'] ) ) {
|
|
$action = (string) $_POST['ship_action'];
|
|
switch ($action) {
|
|
case 'orbit':
|
|
$client->orbitShip( $shipSymbol );
|
|
$statusMessage = 'Ship set to orbit.';
|
|
break;
|
|
case 'dock':
|
|
$client->dockShip( $shipSymbol );
|
|
$statusMessage = 'Ship docked.';
|
|
break;
|
|
case 'extract':
|
|
$client->extractResources( $shipSymbol );
|
|
$statusMessage = 'Resource extraction started.';
|
|
break;
|
|
case 'survey':
|
|
$client->surveyWaypoint( $shipSymbol );
|
|
$statusMessage = 'Survey completed.';
|
|
break;
|
|
case 'siphon':
|
|
$client->siphonResources( $shipSymbol );
|
|
$statusMessage = 'Siphon action completed.';
|
|
break;
|
|
case 'refuel':
|
|
$client->refuelShip( $shipSymbol );
|
|
$statusMessage = 'Ship refueled.';
|
|
break;
|
|
case 'sell_all_cargo':
|
|
$shipResponse = $client->getShip( $shipSymbol );
|
|
$shipData = $shipResponse['data'] ?? array();
|
|
$shipStatus = (string) ( $shipData['nav']['status'] ?? '' );
|
|
|
|
if ($shipStatus === 'IN_TRANSIT' ) {
|
|
throw new SpacetradersApiException( 'Ship is in transit and cannot sell cargo right now.' );
|
|
}
|
|
|
|
if ($shipStatus !== 'DOCKED' ) {
|
|
$client->dockShip( $shipSymbol );
|
|
}
|
|
|
|
$inventory = (array) ( $shipData['cargo']['inventory'] ?? array() );
|
|
$soldItems = 0;
|
|
foreach ( $inventory as $item ) {
|
|
$tradeSymbol = (string) ( $item['symbol'] ?? '' );
|
|
$units = (int) ( $item['units'] ?? 0 );
|
|
if ($tradeSymbol === '' || $units <= 0 ) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$client->sellCargo( $shipSymbol, $tradeSymbol, $units );
|
|
$soldItems++;
|
|
} catch (SpacetradersApiException $e) {
|
|
// Continue selling other items.
|
|
}
|
|
}
|
|
|
|
$statusMessage = 'Attempted to sell all cargo item types. Sold: ' . $soldItems . '.';
|
|
break;
|
|
case 'sell_cargo_item':
|
|
$tradeSymbol = trim( (string) ( $_POST['trade_symbol'] ?? '' ) );
|
|
$units = (int) ( $_POST['units'] ?? 0 );
|
|
|
|
if ($tradeSymbol === '' || $units <= 0 ) {
|
|
throw new SpacetradersApiException( 'Trade symbol and units are required to sell cargo.' );
|
|
}
|
|
|
|
$shipResponse = $client->getShip( $shipSymbol );
|
|
$shipData = $shipResponse['data'] ?? array();
|
|
$shipStatus = (string) ( $shipData['nav']['status'] ?? '' );
|
|
|
|
if ($shipStatus === 'IN_TRANSIT' ) {
|
|
throw new SpacetradersApiException( 'Ship is in transit and cannot sell cargo right now.' );
|
|
}
|
|
|
|
if ($shipStatus !== 'DOCKED' ) {
|
|
$client->dockShip( $shipSymbol );
|
|
}
|
|
|
|
$client->sellCargo( $shipSymbol, $tradeSymbol, $units );
|
|
$statusMessage = 'Sold ' . number_format( $units ) . ' units of ' . formatString( $tradeSymbol ) . '.';
|
|
break;
|
|
case 'jettison_all_cargo':
|
|
$shipResponse = $client->getShip( $shipSymbol );
|
|
$shipData = $shipResponse['data'] ?? array();
|
|
$shipStatus = (string) ( $shipData['nav']['status'] ?? '' );
|
|
if ($shipStatus === 'IN_TRANSIT' ) {
|
|
throw new SpacetradersApiException( 'Ship is in transit and cannot jettison cargo right now.' );
|
|
}
|
|
|
|
$inventory = (array) ( $shipData['cargo']['inventory'] ?? array() );
|
|
$jettisonedItems = 0;
|
|
foreach ( $inventory as $item ) {
|
|
$tradeSymbol = (string) ( $item['symbol'] ?? '' );
|
|
$units = (int) ( $item['units'] ?? 0 );
|
|
if ($tradeSymbol === '' || $units <= 0 ) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$client->jettisonCargo( $shipSymbol, $tradeSymbol, $units );
|
|
$jettisonedItems++;
|
|
} catch (SpacetradersApiException $e) {
|
|
// Continue attempting the rest.
|
|
}
|
|
}
|
|
|
|
$statusMessage = 'Attempted to jettison all cargo item types. Jettisoned: ' . $jettisonedItems . '.';
|
|
break;
|
|
case 'jettison_cargo_item':
|
|
$tradeSymbol = trim( (string) ( $_POST['trade_symbol'] ?? '' ) );
|
|
$units = (int) ( $_POST['units'] ?? 0 );
|
|
if ($tradeSymbol === '' || $units <= 0 ) {
|
|
throw new SpacetradersApiException( 'Trade symbol and units are required to jettison cargo.' );
|
|
}
|
|
|
|
$shipResponse = $client->getShip( $shipSymbol );
|
|
$shipData = $shipResponse['data'] ?? array();
|
|
$shipStatus = (string) ( $shipData['nav']['status'] ?? '' );
|
|
if ($shipStatus === 'IN_TRANSIT' ) {
|
|
throw new SpacetradersApiException( 'Ship is in transit and cannot jettison cargo right now.' );
|
|
}
|
|
|
|
$client->jettisonCargo( $shipSymbol, $tradeSymbol, $units );
|
|
$statusMessage = 'Jettisoned ' . number_format( $units ) . ' units of ' . formatString( $tradeSymbol ) . '.';
|
|
break;
|
|
}
|
|
|
|
if ($statusMessage !== '' ) {
|
|
$storage->clearAllCache();
|
|
}
|
|
}
|
|
|
|
$shipResponse = $client->getShip( $shipSymbol );
|
|
$ship = $shipResponse['data'] ?? $shipResponse;
|
|
}
|
|
}
|
|
} catch (SpacetradersApiException $e) {
|
|
$errorMessage = $e->getMessage();
|
|
}
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Spacetraders - Ship Details</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
</head>
|
|
|
|
<body class="container mx-auto px-4 py-8 bg-stone-800 text-gray-200">
|
|
<?php require __DIR__ . '/main-menu.php'; ?>
|
|
|
|
<h1 class="text-3xl font-bold mb-6 underline decoration-gray-300 w-full"><a href="ship-details.php">Spacetraders - Ship Details</a></h1>
|
|
|
|
<?php if (isset( $tokenError ) ) : ?>
|
|
<div class="mb-6 border border-red-500 p-4 rounded text-red-300">
|
|
<?php echo htmlspecialchars( $tokenError ); ?>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
<?php exit; ?>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($errorMessage !== '' ) : ?>
|
|
<div class="mb-6 border border-red-500 p-4 rounded text-red-300">
|
|
<?php echo htmlspecialchars( $errorMessage ); ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($statusMessage !== '' ) : ?>
|
|
<div class="mb-6 border border-green-500 p-4 rounded text-green-300">
|
|
<?php echo htmlspecialchars( $statusMessage ); ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<form method="get" class="mb-6 flex items-end gap-3">
|
|
<div>
|
|
<label for="ship" class="block text-sm mb-1">Choose Ship</label>
|
|
<select id="ship" name="ship" class="px-3 py-2 rounded text-black min-w-64">
|
|
<?php foreach ( $shipList as $listShip ) : ?>
|
|
<?php $listSymbol = (string) ( $listShip['symbol'] ?? '' ); ?>
|
|
<option value="<?php echo htmlspecialchars( $listSymbol ); ?>" <?php echo ( $listSymbol === $shipSymbol ) ? 'selected' : ''; ?>>
|
|
<?php echo htmlspecialchars( formatString( $listSymbol ) ); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<button type="submit" class="px-4 py-2 bg-blue-600 rounded hover:bg-blue-500">View</button>
|
|
</form>
|
|
|
|
<?php if (! empty( $ship ) ) : ?>
|
|
<?php
|
|
$shipRole = strtoupper( (string) ( $ship['registration']['role'] ?? '' ) );
|
|
$shipStatus = (string) ( $ship['nav']['status'] ?? '' );
|
|
$fuelCurrent = (int) ( $ship['fuel']['current'] ?? 0 );
|
|
$fuelCapacity = (int) ( $ship['fuel']['capacity'] ?? 0 );
|
|
$showRefuel = $fuelCapacity > 0 && $fuelCurrent < $fuelCapacity;
|
|
?>
|
|
<div class="mb-6 border border-gray-600 rounded p-4">
|
|
<h2 class="text-xl font-bold mb-3">Ship Controls</h2>
|
|
<form method="post" class="flex flex-wrap gap-2">
|
|
<?php if ($shipStatus === 'DOCKED' ) : ?>
|
|
<button type="submit" name="ship_action" value="orbit" class="px-3 py-1 bg-blue-600 rounded hover:bg-blue-500">Orbit</button>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($shipStatus !== 'DOCKED' && $shipStatus !== 'IN_TRANSIT' ) : ?>
|
|
<button type="submit" name="ship_action" value="dock" class="px-3 py-1 bg-blue-600 rounded hover:bg-blue-500">Dock</button>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($shipRole === 'EXCAVATOR' ) : ?>
|
|
<button type="submit" name="ship_action" value="extract" class="px-3 py-1 bg-emerald-700 rounded hover:bg-emerald-600">Mine (Extract)</button>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($shipRole === 'SURVEYOR' ) : ?>
|
|
<button type="submit" name="ship_action" value="survey" class="px-3 py-1 bg-indigo-700 rounded hover:bg-indigo-600">Survey</button>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($shipRole === 'EXCAVATOR' ) : ?>
|
|
<button type="submit" name="ship_action" value="siphon" class="px-3 py-1 bg-cyan-700 rounded hover:bg-cyan-600">Siphon</button>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($showRefuel ) : ?>
|
|
<button type="submit" name="ship_action" value="refuel" class="px-3 py-1 bg-amber-700 rounded hover:bg-amber-600">Refuel</button>
|
|
<?php endif; ?>
|
|
|
|
<?php if ((int) ( $ship['cargo']['units'] ?? 0 ) > 0) : ?>
|
|
<button type="submit" name="ship_action" value="sell_all_cargo" class="px-3 py-1 bg-rose-700 rounded hover:bg-rose-600">Sell All Cargo</button>
|
|
<button type="submit" name="ship_action" value="jettison_all_cargo" class="px-3 py-1 bg-red-800 rounded hover:bg-red-700">Jettison All Cargo</button>
|
|
<?php endif; ?>
|
|
</form>
|
|
<p class="mt-2 text-sm text-gray-300">
|
|
Role: <?php echo htmlspecialchars( formatString( $shipRole ) ); ?> |
|
|
Status: <?php echo htmlspecialchars( formatString( $shipStatus ) ); ?> |
|
|
Fuel: <?php echo number_format( $fuelCurrent ); ?>/<?php echo number_format( $fuelCapacity ); ?>
|
|
</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div class="border border-gray-600 rounded p-4">
|
|
<h2 class="text-xl font-bold mb-2">Overview</h2>
|
|
<p><span class="font-bold">Symbol:</span> <?php echo htmlspecialchars( (string) ( formatString( $ship['symbol'] ?? '' ) ) ); ?></p>
|
|
<p><span class="font-bold">Name:</span> <?php echo htmlspecialchars( (string) ( formatString( $ship['registration']['name'] ?? '' ) ) ); ?></p>
|
|
<p><span class="font-bold">Role:</span> <?php echo htmlspecialchars( (string) ( formatString( $ship['registration']['role'] ?? '' ) ) ); ?></p>
|
|
<p><span class="font-bold">Faction:</span> <?php echo htmlspecialchars( (string) ( formatString( $ship['registration']['factionSymbol'] ?? '' ) ) ); ?></p>
|
|
</div>
|
|
|
|
<div class="border border-gray-600 rounded p-4">
|
|
<h2 class="text-xl font-bold mb-2">Navigation</h2>
|
|
<p><span class="font-bold">Status:</span> <?php echo htmlspecialchars( (string) ( formatString( $ship['nav']['status'] ?? '' ) ) ); ?></p>
|
|
<p><span class="font-bold">Flight Mode:</span> <?php echo htmlspecialchars( (string) ( formatString( $ship['nav']['flightMode'] ?? '' ) ) ); ?></p>
|
|
<p><span class="font-bold">System:</span> <?php echo htmlspecialchars( (string) ( $ship['nav']['systemSymbol'] ?? '' ) ); ?></p>
|
|
<p><span class="font-bold">Waypoint:</span> <?php echo htmlspecialchars( (string) ( $ship['nav']['waypointSymbol'] ?? '' ) ); ?></p>
|
|
<p>
|
|
<span class="font-bold">Navigation Timer:</span>
|
|
<span
|
|
class="ship-nav-timer"
|
|
data-status="<?php echo htmlspecialchars( (string) ( $ship['nav']['status'] ?? '' ) ); ?>"
|
|
data-arrival="<?php echo htmlspecialchars( (string) ( $ship['nav']['route']['arrival'] ?? '' ) ); ?>"
|
|
></span>
|
|
</p>
|
|
</div>
|
|
|
|
<div class="border border-gray-600 rounded p-4">
|
|
<h2 class="text-xl font-bold mb-2">Frame / Engine / Reactor</h2>
|
|
<p><span class="font-bold">Frame:</span> <?php echo htmlspecialchars( (string) ( $ship['frame']['name'] ?? '' ) ); ?></p>
|
|
<p><span class="font-bold">Engine:</span> <?php echo htmlspecialchars( (string) ( $ship['engine']['name'] ?? '' ) ); ?></p>
|
|
<p><span class="font-bold">Reactor:</span> <?php echo htmlspecialchars( (string) ( $ship['reactor']['name'] ?? '' ) ); ?></p>
|
|
</div>
|
|
|
|
<div class="border border-gray-600 rounded p-4">
|
|
<h2 class="text-xl font-bold mb-2">Cargo / Fuel</h2>
|
|
<p><span class="font-bold">Cargo:</span> <?php echo number_format( (int) ( $ship['cargo']['units'] ?? 0 ) ); ?> / <?php echo number_format( (int) ( $ship['cargo']['capacity'] ?? 0 ) ); ?></p>
|
|
<p><span class="font-bold">Fuel:</span> <?php echo number_format( (int) ( $ship['fuel']['current'] ?? 0 ) ); ?> / <?php echo number_format( (int) ( $ship['fuel']['capacity'] ?? 0 ) ); ?></p>
|
|
<p>
|
|
<span class="font-bold">Cooldown Remaining:</span>
|
|
<span
|
|
class="ship-cooldown"
|
|
data-seconds="<?php echo htmlspecialchars( (string) max( 0, (int) ( $ship['cooldown']['remainingSeconds'] ?? 0 ) ) ); ?>"
|
|
></span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-6 border border-gray-600 rounded p-4">
|
|
<h2 class="text-xl font-bold mb-2">Mounts</h2>
|
|
<?php $mounts = (array) ( $ship['mounts'] ?? array() ); ?>
|
|
<?php if (empty( $mounts ) ) : ?>
|
|
<p class="text-gray-300">No mounts equipped.</p>
|
|
<?php else : ?>
|
|
<ul class="list-disc list-inside">
|
|
<?php foreach ( $mounts as $mount ) : ?>
|
|
<li><?php echo htmlspecialchars( (string) ( $mount['name'] ?? $mount['symbol'] ?? '' ) ); ?></li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="mt-6 border border-gray-600 rounded p-4">
|
|
<h2 class="text-xl font-bold mb-2">Modules</h2>
|
|
<?php $modules = (array) ( $ship['modules'] ?? array() ); ?>
|
|
<?php if (empty( $modules ) ) : ?>
|
|
<p class="text-gray-300">No modules installed.</p>
|
|
<?php else : ?>
|
|
<ul class="list-disc list-inside">
|
|
<?php foreach ( $modules as $module ) : ?>
|
|
<li><?php echo htmlspecialchars( (string) ( $module['name'] ?? $module['symbol'] ?? '' ) ); ?></li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="mt-6 border border-gray-600 rounded p-4">
|
|
<h2 class="text-xl font-bold mb-2">Cargo Inventory</h2>
|
|
<?php $inventory = (array) ( $ship['cargo']['inventory'] ?? array() ); ?>
|
|
<?php if (empty( $inventory ) ) : ?>
|
|
<p class="text-gray-300">Cargo hold is empty.</p>
|
|
<?php else : ?>
|
|
<table class="table-auto border-collapse border border-gray-300 w-full">
|
|
<tr>
|
|
<th class="border border-gray-300 px-3 py-2">Name</th>
|
|
<th class="border border-gray-300 px-3 py-2">Units</th>
|
|
<th class="border border-gray-300 px-3 py-2">Description</th>
|
|
<th class="border border-gray-300 px-3 py-2">Sell</th>
|
|
<th class="border border-gray-300 px-3 py-2">Jettison</th>
|
|
</tr>
|
|
<?php foreach ( $inventory as $item ) : ?>
|
|
<?php $itemUnits = (int) ( $item['units'] ?? 0 ); ?>
|
|
<tr>
|
|
<td class="border border-gray-300 px-3 py-2"><?php echo htmlspecialchars( (string) ( $item['name'] ?? '' ) ); ?></td>
|
|
<td class="border border-gray-300 px-3 py-2"><?php echo number_format( $itemUnits ); ?></td>
|
|
<td class="border border-gray-300 px-3 py-2"><?php echo htmlspecialchars( (string) ( $item['description'] ?? '' ) ); ?></td>
|
|
<td class="border border-gray-300 px-3 py-2">
|
|
<?php if ($itemUnits > 0 ) : ?>
|
|
<form method="post" class="flex items-center gap-2">
|
|
<input type="hidden" name="ship_action" value="sell_cargo_item">
|
|
<input type="hidden" name="trade_symbol" value="<?php echo htmlspecialchars( (string) ( $item['symbol'] ?? '' ) ); ?>">
|
|
<input
|
|
type="number"
|
|
name="units"
|
|
value="<?php echo (int) $itemUnits; ?>"
|
|
min="1"
|
|
max="<?php echo (int) $itemUnits; ?>"
|
|
class="w-24 px-2 py-1 rounded text-black"
|
|
>
|
|
<button type="submit" class="px-3 py-1 bg-rose-700 rounded hover:bg-rose-600">Sell</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="border border-gray-300 px-3 py-2">
|
|
<?php if ($itemUnits > 0 ) : ?>
|
|
<form method="post" class="flex items-center gap-2">
|
|
<input type="hidden" name="ship_action" value="jettison_cargo_item">
|
|
<input type="hidden" name="trade_symbol" value="<?php echo htmlspecialchars( (string) ( $item['symbol'] ?? '' ) ); ?>">
|
|
<input
|
|
type="number"
|
|
name="units"
|
|
value="<?php echo (int) $itemUnits; ?>"
|
|
min="1"
|
|
max="<?php echo (int) $itemUnits; ?>"
|
|
class="w-24 px-2 py-1 rounded text-black"
|
|
>
|
|
<button type="submit" class="px-3 py-1 bg-red-800 rounded hover:bg-red-700">Jettison</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</table>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<script>
|
|
(function() {
|
|
const navTimerNodes = document.querySelectorAll('.ship-nav-timer');
|
|
const cooldownNodes = document.querySelectorAll('.ship-cooldown');
|
|
|
|
function formatNavTimer(seconds) {
|
|
if (seconds <= 0) {
|
|
return 'Arriving';
|
|
}
|
|
|
|
const total = Math.max(0, Math.floor(seconds));
|
|
const hours = Math.floor(total / 3600);
|
|
const minutes = Math.floor((total % 3600) / 60);
|
|
const secs = total % 60;
|
|
|
|
if (hours > 0) {
|
|
return `${hours}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
|
|
}
|
|
|
|
return `${minutes}:${String(secs).padStart(2, '0')}`;
|
|
}
|
|
|
|
function formatCooldown(seconds) {
|
|
if (seconds <= 0) {
|
|
return 'Ready';
|
|
}
|
|
|
|
const total = Math.max(0, Math.floor(seconds));
|
|
const mins = Math.floor(total / 60);
|
|
const secs = total % 60;
|
|
|
|
if (mins > 0) {
|
|
return `${mins}:${String(secs).padStart(2, '0')}`;
|
|
}
|
|
|
|
return `${secs}s`;
|
|
}
|
|
|
|
function renderNavTimers() {
|
|
const nowMs = Date.now();
|
|
|
|
navTimerNodes.forEach((node) => {
|
|
const status = node.dataset.status || '';
|
|
const arrival = node.dataset.arrival || '';
|
|
|
|
if (status !== 'IN_TRANSIT') {
|
|
node.textContent = 'Ready';
|
|
return;
|
|
}
|
|
|
|
const arrivalMs = Date.parse(arrival);
|
|
if (!Number.isFinite(arrivalMs)) {
|
|
node.textContent = 'In transit';
|
|
return;
|
|
}
|
|
|
|
const remainingSeconds = Math.max(0, Math.floor((arrivalMs - nowMs) / 1000));
|
|
node.textContent = formatNavTimer(remainingSeconds);
|
|
});
|
|
}
|
|
|
|
function renderCooldownTimers() {
|
|
cooldownNodes.forEach((node) => {
|
|
const seconds = Number(node.dataset.seconds || '0');
|
|
node.textContent = formatCooldown(seconds);
|
|
});
|
|
}
|
|
|
|
renderNavTimers();
|
|
renderCooldownTimers();
|
|
|
|
if (navTimerNodes.length > 0 || cooldownNodes.length > 0) {
|
|
window.setInterval(() => {
|
|
renderNavTimers();
|
|
|
|
cooldownNodes.forEach((node) => {
|
|
const current = Number(node.dataset.seconds || '0');
|
|
node.dataset.seconds = String(Math.max(0, current - 1));
|
|
});
|
|
renderCooldownTimers();
|
|
}, 1000);
|
|
}
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|