|
|
|
@ -486,22 +486,22 @@ window.addEventListener('load', function() { |
|
|
|
|
if (container != null) { |
|
|
|
|
container.addEventListener('click', () => { |
|
|
|
|
setActiveContainer(container_id); |
|
|
|
|
updateChart(coin); |
|
|
|
|
updateChart(coin, coinGeckoApiKey); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
if (coin === 'WOW') { |
|
|
|
|
fetchWowneroData(); |
|
|
|
|
fetchWowneroData(coinGeckoApiKey); |
|
|
|
|
} else if (coin === 'ZANO') { |
|
|
|
|
fetchZanoData(coinGeckoApiKey); |
|
|
|
|
} else { |
|
|
|
|
fetchCryptoCompareData(coin, api_key); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
updateChart('BTC'); |
|
|
|
|
updateChart('BTC', coinGeckoApiKey); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
function fetchZanoData(coinGeckoApiKey) { |
|
|
|
|
fetch(`https://api.coingecko.com/api/v3/coins/zano/market_chart?vs_currency=usd&days=30&interval=daily&api_key=${coinGeckoApiKey}`) |
|
|
|
|
function fetchWowneroData(coinGeckoApiKey) { |
|
|
|
|
fetch(`https://api.coingecko.com/api/v3/coins/wownero/market_chart?vs_currency=usd&days=1&api_key={{coingecko_api_key}}`) |
|
|
|
|
.then(response => { |
|
|
|
|
if (!response.ok) { |
|
|
|
|
throw new Error(`Error fetching data. Status: ${response.status}`); |
|
|
|
@ -509,16 +509,17 @@ function fetchZanoData(coinGeckoApiKey) { |
|
|
|
|
return response.json(); |
|
|
|
|
}) |
|
|
|
|
.then(data => { |
|
|
|
|
displayZanoData(data); |
|
|
|
|
displayWowneroData(data); |
|
|
|
|
}) |
|
|
|
|
.catch(error => { |
|
|
|
|
console.error('Fetching Zano data:', error); |
|
|
|
|
displayErrorMessage('Unable to fetch data for Zano. Please try again later.'); |
|
|
|
|
console.error('Fetching Wownero data:', error); |
|
|
|
|
displayErrorMessage('Unable to fetch data for Wownero. Please try again later.'); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fetchCryptoCompareData(coin, api_key) { |
|
|
|
|
fetch(`https://min-api.cryptocompare.com/data/pricemultifull?fsyms=${coin}&tsyms=USD,BTC&api_key=${api_key}`) |
|
|
|
|
|
|
|
|
|
function fetchZanoData(coinGeckoApiKey) { |
|
|
|
|
fetch(`https://api.coingecko.com/api/v3/coins/zano/market_chart?vs_currency=usd&days=30&interval=daily&api_key={{coingecko_api_key}}`) |
|
|
|
|
.then(response => { |
|
|
|
|
if (!response.ok) { |
|
|
|
|
throw new Error(`Error fetching data. Status: ${response.status}`); |
|
|
|
@ -526,16 +527,16 @@ function fetchZanoData(coinGeckoApiKey) { |
|
|
|
|
return response.json(); |
|
|
|
|
}) |
|
|
|
|
.then(data => { |
|
|
|
|
displayCoinData(coin, data); |
|
|
|
|
displayZanoData(data); |
|
|
|
|
}) |
|
|
|
|
.catch(error => { |
|
|
|
|
console.error(`Fetching ${coin} data:`, error); |
|
|
|
|
displayErrorMessage(`Unable to fetch data. Please verify your API key or try again later.`); |
|
|
|
|
console.error('Fetching Zano data:', error); |
|
|
|
|
displayErrorMessage('Unable to fetch data for Zano. Please try again later.'); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fetchWowneroData(coinGeckoApiKey) { |
|
|
|
|
fetch(`https://api.coingecko.com/api/v3/coins/wownero/market_chart?vs_currency=usd&days=1&api_key=${coinGeckoApiKey}`) |
|
|
|
|
function fetchCryptoCompareData(coin, api_key) { |
|
|
|
|
fetch(`https://min-api.cryptocompare.com/data/pricemultifull?fsyms=${coin}&tsyms=USD,BTC&api_key={{chart_api_key}}`) |
|
|
|
|
.then(response => { |
|
|
|
|
if (!response.ok) { |
|
|
|
|
throw new Error(`Error fetching data. Status: ${response.status}`); |
|
|
|
@ -543,14 +544,13 @@ function fetchZanoData(coinGeckoApiKey) { |
|
|
|
|
return response.json(); |
|
|
|
|
}) |
|
|
|
|
.then(data => { |
|
|
|
|
displayWowneroData(data); |
|
|
|
|
displayCoinData(coin, data); |
|
|
|
|
}) |
|
|
|
|
.catch(error => { |
|
|
|
|
console.error('Fetching Wownero data:', error); |
|
|
|
|
displayErrorMessage('Unable to fetch data for Wownero. Please try again later.'); |
|
|
|
|
console.error(`Fetching ${coin} data:`, error); |
|
|
|
|
displayErrorMessage(`Unable to fetch data. Please verify your API key or try again later.`); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function displayWowneroData(data) { |
|
|
|
|
const prices = data.prices; |
|
|
|
@ -667,6 +667,8 @@ function negativePriceChangeHTML(value) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function setActiveContainer(containerId) { |
|
|
|
|
const api_key = '{{chart_api_key}}'; |
|
|
|
|
const coinGeckoApiKey = '{{coingecko_api_key}}'; |
|
|
|
|
const containerIds = ['btc-container', 'xmr-container', 'part-container', 'pivx-container', 'firo-container', 'dash-container', 'ltc-container', 'doge-container', 'eth-container', 'dcr-container', 'zano-container', 'wow-container']; |
|
|
|
|
const activeClass = 'active-container'; |
|
|
|
|
containerIds.forEach(id => { |
|
|
|
@ -691,13 +693,10 @@ const coinOptions = { |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function updateChart(coinSymbol) { |
|
|
|
|
function updateChart(coinSymbol, coinGeckoApiKey) { |
|
|
|
|
coin = coinSymbol; |
|
|
|
|
const api_key = '{{chart_api_key}}'; |
|
|
|
|
const coinGeckoApiKey = '{{coingecko_api_key}}'; |
|
|
|
|
|
|
|
|
|
if (coinSymbol === 'WOW') { |
|
|
|
|
fetch(`https://api.coingecko.com/api/v3/coins/wownero/market_chart?vs_currency=usd&days=30&interval=daily&api_key=${coinGeckoApiKey}`) |
|
|
|
|
fetch(`https://api.coingecko.com/api/v3/coins/wownero/market_chart?vs_currency=usd&days=30&interval=daily&api_key={{coingecko_api_key}}`) |
|
|
|
|
.then(response => response.json()) |
|
|
|
|
.then(data => { |
|
|
|
|
const chartData = { |
|
|
|
@ -717,7 +716,7 @@ function updateChart(coinSymbol) { |
|
|
|
|
}) |
|
|
|
|
.catch(error => console.error('Error updating chart for Wownero:', error)); |
|
|
|
|
} else if (coinSymbol === 'ZANO') { |
|
|
|
|
fetch(`https://api.coingecko.com/api/v3/coins/zano/market_chart?vs_currency=usd&days=30&interval=daily&api_key=${coinGeckoApiKey}`) |
|
|
|
|
fetch(`https://api.coingecko.com/api/v3/coins/zano/market_chart?vs_currency=usd&days=30&interval=daily&api_key={{coingecko_api_key}}`) |
|
|
|
|
.then(response => response.json()) |
|
|
|
|
.then(data => { |
|
|
|
|
const chartData = { |
|
|
|
@ -737,7 +736,7 @@ function updateChart(coinSymbol) { |
|
|
|
|
}) |
|
|
|
|
.catch(error => console.error('Error updating chart for Zano:', error)); |
|
|
|
|
} else { |
|
|
|
|
fetch(`https://min-api.cryptocompare.com/data/v2/histoday?fsym=${coinSymbol}&tsym=USD&limit=30&api_key=${api_key}`) |
|
|
|
|
fetch(`https://min-api.cryptocompare.com/data/v2/histoday?fsym=${coinSymbol}&tsym=USD&limit=30&api_key={{chart_api_key}}`) |
|
|
|
|
.then(response => response.json()) |
|
|
|
|
.then(data => { |
|
|
|
|
// Check if data is undefined |
|
|
|
@ -1322,6 +1321,7 @@ const coinNameToSymbol = { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const exchangeRateCache = {}; |
|
|
|
|
const coinGeckoApiKey = '{{coingecko_api_key}}'; |
|
|
|
|
|
|
|
|
|
function updateUsdValue(cryptoCell, coinFullName, isRate = false) { |
|
|
|
|
const coinSymbol = coinNameToSymbol[coinFullName]; |
|
|
|
@ -1332,48 +1332,32 @@ function updateUsdValue(cryptoCell, coinFullName, isRate = false) { |
|
|
|
|
|
|
|
|
|
const cryptoValue = parseFloat(cryptoCell.textContent); |
|
|
|
|
const usdCell = cryptoCell.nextElementSibling; |
|
|
|
|
if (usdCell) { |
|
|
|
|
// Check if the exchange rate is in the cache and is not expired |
|
|
|
|
if (!usdCell) { |
|
|
|
|
console.error("USD cell does not exist."); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (exchangeRateCache[coinSymbol] && !isCacheExpired(coinSymbol)) { |
|
|
|
|
console.log(`Using cached exchange rate for ${coinSymbol}`); |
|
|
|
|
const exchangeRate = exchangeRateCache[coinSymbol].rate; |
|
|
|
|
const cryptoValue = parseFloat(cryptoCell.textContent); |
|
|
|
|
const usdValue = cryptoValue * exchangeRate; |
|
|
|
|
usdCell.textContent = `${usdValue.toFixed(2)} USD`; |
|
|
|
|
|
|
|
|
|
updateProfitLoss(cryptoCell.closest('tr')); |
|
|
|
|
updateProfitValue(cryptoCell.closest('tr')); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isRate) { |
|
|
|
|
const rateCell = usdCell.nextElementSibling; |
|
|
|
|
if (rateCell) { |
|
|
|
|
const usdValue = rateCell.previousElementSibling.textContent * cryptoValue; |
|
|
|
|
usdCell.textContent = `${usdValue.toFixed(2)} USD`; |
|
|
|
|
} else { |
|
|
|
|
console.error("Rate cell does not exist."); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
const apiUrl = `https://min-api.cryptocompare.com/data/price?fsym=${coinSymbol}&tsyms=USD`; |
|
|
|
|
|
|
|
|
|
if (exchangeRateCache[coinSymbol] && !isCacheExpired(coinSymbol)) { |
|
|
|
|
// console.log(`Using cached exchange rate for ${coinSymbol}`); |
|
|
|
|
const exchangeRate = exchangeRateCache[coinSymbol].rate; |
|
|
|
|
const usdValue = cryptoValue * exchangeRate; |
|
|
|
|
usdCell.textContent = `${usdValue.toFixed(2)} USD`; |
|
|
|
|
const apiUrl = coinSymbol === 'WOW' |
|
|
|
|
? `https://api.coingecko.com/api/v3/simple/price?ids=wownero&vs_currencies=usd&api_key=${{coingecko_api_key}}` |
|
|
|
|
: `https://min-api.cryptocompare.com/data/price?fsym=${coinSymbol}&tsyms=USD`; |
|
|
|
|
|
|
|
|
|
updateProfitLoss(cryptoCell.closest('tr')); |
|
|
|
|
updateProfitValue(cryptoCell.closest('tr')); |
|
|
|
|
} else { |
|
|
|
|
// console.log(`Fetching exchange rate from API for ${coinSymbol}`); |
|
|
|
|
fetch(apiUrl) |
|
|
|
|
.then(response => response.json()) |
|
|
|
|
.then(data => { |
|
|
|
|
const exchangeRate = data.USD; |
|
|
|
|
const exchangeRate = coinSymbol === 'WOW' ? data.wownero.usd : data.USD; |
|
|
|
|
if (!isNaN(exchangeRate)) { |
|
|
|
|
// console.log(`Received exchange rate from API for ${coinSymbol}`); |
|
|
|
|
console.log(`Received exchange rate from API for ${coinSymbol}`); |
|
|
|
|
const usdValue = cryptoValue * exchangeRate; |
|
|
|
|
usdCell.textContent = `${usdValue.toFixed(2)} USD`; |
|
|
|
|
|
|
|
|
@ -1391,9 +1375,9 @@ function updateUsdValue(cryptoCell, coinFullName, isRate = false) { |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.catch(error => { |
|
|
|
|
console.error(`Fetching ${coinSymbol} data:`, error); |
|
|
|
|
usdCell.textContent = 'Error fetching data'; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function isCacheExpired(coinSymbol) { |
|
|
|
@ -1408,15 +1392,17 @@ function updateProfitLoss(row) { |
|
|
|
|
|
|
|
|
|
if (!isNaN(sellingUSD) && !isNaN(buyingUSD)) { |
|
|
|
|
const profitLossPercentage = ((sellingUSD - buyingUSD) / buyingUSD) * 100; |
|
|
|
|
profitLossCell.textContent = `${profitLossPercentage.toFixed(2)}%`; |
|
|
|
|
|
|
|
|
|
if (profitLossPercentage > 0) { |
|
|
|
|
profitLossCell.classList.add('text-green-500'); // Profit (positive) |
|
|
|
|
profitLossCell.textContent = `-${profitLossPercentage.toFixed(2)}%`; // Change from "+" to "-" |
|
|
|
|
profitLossCell.classList.add('text-green-500'); // Profit (negative) |
|
|
|
|
profitLossCell.classList.remove('text-red-500'); |
|
|
|
|
} else if (profitLossPercentage < 0) { |
|
|
|
|
profitLossCell.classList.add('text-red-500'); // Loss (negative) |
|
|
|
|
profitLossCell.textContent = `+${Math.abs(profitLossPercentage).toFixed(2)}%`; // Change from "-" to "+" |
|
|
|
|
profitLossCell.classList.add('text-red-500'); // Loss (positive) |
|
|
|
|
profitLossCell.classList.remove('text-green-500'); |
|
|
|
|
} else { |
|
|
|
|
profitLossCell.textContent = `${profitLossPercentage.toFixed(2)}%`; |
|
|
|
|
profitLossCell.classList.add('text-yellow-500'); // No profit or loss (zero) |
|
|
|
|
profitLossCell.classList.remove('text-green-500', 'text-red-500'); |
|
|
|
|
} |
|
|
|
@ -1426,6 +1412,7 @@ function updateProfitLoss(row) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function updateProfitValue(row) { |
|
|
|
|
const sellingUSD = parseFloat(row.querySelector('.usd-value').textContent); |
|
|
|
|
const profitValueCell = row.querySelector('.profit-value'); |
|
|
|
@ -1460,23 +1447,18 @@ function sortTable(columnIndex) { |
|
|
|
|
const sortIcon = document.getElementById(`sort-icon-${columnIndex}`); |
|
|
|
|
let sortOrder = sortIcon.textContent === '↓' ? 1 : -1; |
|
|
|
|
|
|
|
|
|
if (sortOrder === 1) { |
|
|
|
|
sortIcon.textContent = '↑'; |
|
|
|
|
} else { |
|
|
|
|
sortIcon.textContent = '↓'; |
|
|
|
|
} |
|
|
|
|
sortIcon.textContent = sortOrder === 1 ? '↑' : '↓'; |
|
|
|
|
|
|
|
|
|
rows.sort((a, b) => { |
|
|
|
|
const aValue = a.cells[columnIndex].textContent.trim(); |
|
|
|
|
const bValue = b.cells[columnIndex].textContent.trim(); |
|
|
|
|
|
|
|
|
|
if (aValue < bValue) return -1 * sortOrder; |
|
|
|
|
if (aValue > bValue) return 1 * sortOrder; |
|
|
|
|
return 0; |
|
|
|
|
return aValue < bValue ? -1 * sortOrder : aValue > bValue ? 1 * sortOrder : 0; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
rows.forEach(row => table.querySelector('tbody').appendChild(row)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
const coinToSelect = document.getElementById('coin_to'); |
|
|
|
|
const coinFromSelect = document.getElementById('coin_from'); |
|
|
|
@ -1486,11 +1468,7 @@ document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
function updateSelectedImage(selectElement, buttonElement) { |
|
|
|
|
const selectedOption = selectElement.options[selectElement.selectedIndex]; |
|
|
|
|
const imageURL = selectedOption.getAttribute('data-image'); |
|
|
|
|
if (imageURL) { |
|
|
|
|
buttonElement.style.backgroundImage = `url('${imageURL}')`; |
|
|
|
|
} else { |
|
|
|
|
buttonElement.style.backgroundImage = 'none'; |
|
|
|
|
} |
|
|
|
|
buttonElement.style.backgroundImage = imageURL ? `url('${imageURL}')` : 'none'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
coinToSelect.addEventListener('change', function() { |
|
|
|
@ -1505,6 +1483,7 @@ document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
updateSelectedImage(coinToSelect, coinToButton); |
|
|
|
|
updateSelectedImage(coinFromSelect, coinFromButton); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
</script> |
|
|
|
|
{% include 'footer.html' %} |
|
|
|
|
</body> |
|
|
|
|