document.addEventListener('DOMContentLoaded', function () { const POLLING_INTERVAL = 3000; // 3 seconds const liveRow = document.getElementById('live-crypto-row'); if (!liveRow) { console.error('Live crypto row with ID #live-crypto-row not found.'); return; } // Select cells to update const priceCell = liveRow.querySelector('.price'); const changeCell = liveRow.querySelector('.change'); const symbolCell = liveRow.querySelector('.symbol'); const exchangeCell = liveRow.querySelector('.exchange'); let lastPrice = 0; async function fetchLivePrice() { try { const response = await fetch('api/ticker.php'); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const data = await response.json(); if (data.error) { throw new Error(`API Error: ${data.error}`); } updateRow(data); } catch (error) { console.error('Failed to fetch live price:', error); // Optionally, display an error state in the UI priceCell.textContent = 'Error'; changeCell.textContent = '--'; } } function updateRow(data) { const currentPrice = parseFloat(data.price); const priceChange = currentPrice - lastPrice; // Update text content priceCell.textContent = `$${currentPrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; symbolCell.textContent = data.symbol.replace('_SPBL', ''); // Clean up symbol name exchangeCell.textContent = data.exchange; // Update 24h change const changePercent = parseFloat(data.change_24h_percent); changeCell.textContent = `${changePercent.toFixed(2)}%`; changeCell.classList.toggle('text-success', changePercent >= 0); changeCell.classList.toggle('text-danger', changePercent < 0); // Visual flash on price change if (lastPrice !== 0 && priceChange !== 0) { const flashClass = priceChange > 0 ? 'flash-success' : 'flash-danger'; priceCell.classList.add(flashClass); setTimeout(() => priceCell.classList.remove(flashClass), 750); } lastPrice = currentPrice; } // Initial fetch and start polling fetchLivePrice(); setInterval(fetchLivePrice, POLLING_INTERVAL); });