diff --git a/basicswap/static/js/offerstable.js b/basicswap/static/js/offerstable.js index db64b3b..e7fad33 100644 --- a/basicswap/static/js/offerstable.js +++ b/basicswap/static/js/offerstable.js @@ -21,6 +21,14 @@ const PRICE_INIT_RETRIES = 3; const PRICE_INIT_RETRY_DELAY = 2000; const isSentOffers = window.offersTableConfig.isSentOffers; +const offersConfig = { + apiEndpoints: { + coinGecko: 'https://api.coingecko.com/api/v3', + cryptoCompare: 'https://min-api.cryptocompare.com/data' + }, + apiKeys: getAPIKeys() +}; + // MAPPING OBJECTS const coinNameToSymbol = { 'Bitcoin': 'bitcoin', @@ -251,7 +259,7 @@ const WebSocketManager = { handleMessage(message) { if (this.messageQueue.length >= this.maxQueueSize) { - console.warn('⚠Message queue full, dropping oldest message'); + console.warn('Message queue full, dropping oldest message'); this.messageQueue.shift(); } @@ -260,7 +268,7 @@ const WebSocketManager = { this.debounceTimeout = setTimeout(() => { this.processMessageQueue(); - }, 250); + }, 200); }, async processMessageQueue() { @@ -1011,6 +1019,7 @@ async function getMarketRate(fromCoin, toCoin) { async function fetchLatestPrices() { const PRICES_CACHE_KEY = 'prices_coingecko'; + const apiKeys = getAPIKeys(); const cachedData = CacheManager.get(PRICES_CACHE_KEY); if (cachedData && cachedData.remainingTime > 60000) { @@ -1019,10 +1028,10 @@ async function fetchLatestPrices() { return cachedData.value; } - const url = `${config.apiEndpoints.coinGecko}/simple/price?ids=bitcoin,bitcoin-cash,dash,dogecoin,decred,litecoin,particl,pivx,monero,zano,wownero,zcoin&vs_currencies=USD,BTC&api_key=${config.apiKeys.coinGecko}`; + const url = `${offersConfig.apiEndpoints.coinGecko}/simple/price?ids=bitcoin,bitcoin-cash,dash,dogecoin,decred,litecoin,particl,pivx,monero,zano,wownero,zcoin&vs_currencies=USD,BTC&api_key=${offersConfig.apiKeys.coinGecko}`; try { - console.log('Fetching fresh price data...'); + console.log('Initiating fresh price data fetch...'); const response = await fetch('/json/readurl', { method: 'POST', headers: { @@ -1039,31 +1048,37 @@ async function fetchLatestPrices() { } const data = await response.json(); + if (data.Error) { + console.error('API Error:', data.Error); throw new Error(data.Error); } if (data && Object.keys(data).length > 0) { - console.log('Fresh price data received'); - + console.log('Processing fresh price data...'); latestPrices = data; - CacheManager.set(PRICES_CACHE_KEY, data, CACHE_DURATION); - + const fallbackLog = {}; Object.entries(data).forEach(([coin, prices]) => { tableRateModule.setFallbackValue(coin, prices.usd); + fallbackLog[coin] = prices.usd; }); - + + //console.log('Fallback Values Set:', fallbackLog); + return data; } else { - //console.warn('Received empty price data'); + console.warn('No price data received'); + return null; } } catch (error) { - //console.error('Error fetching prices:', error); + console.error('Price Fetch Error:', { + message: error.message, + name: error.name, + stack: error.stack + }); throw error; } - - return latestPrices || null; } async function fetchOffers(manualRefresh = false) { @@ -1312,7 +1327,6 @@ function updateClearFiltersButton() { clearButton.classList.toggle('opacity-50', !hasFilters); clearButton.disabled = !hasFilters; - // Update button styles based on state if (hasFilters) { clearButton.classList.add('hover:bg-green-600', 'hover:text-white'); clearButton.classList.remove('cursor-not-allowed'); @@ -1323,6 +1337,19 @@ function updateClearFiltersButton() { } } +function cleanupRow(row) { + const tooltips = row.querySelectorAll('[data-tooltip-target]'); + const count = tooltips.length; + tooltips.forEach(tooltip => { + const tooltipId = tooltip.getAttribute('data-tooltip-target'); + const tooltipElement = document.getElementById(tooltipId); + if (tooltipElement) { + tooltipElement.remove(); + } + }); + //console.log(`Cleaned up ${count} tooltips from row`); +} + function handleNoOffersScenario() { const formData = new FormData(filterForm); const filters = Object.fromEntries(formData); @@ -1332,6 +1359,11 @@ function handleNoOffersScenario() { stopRefreshAnimation(); + const existingRows = offersBody.querySelectorAll('tr'); + existingRows.forEach(row => { + cleanupRow(row); + }); + if (hasActiveFilters) { offersBody.innerHTML = ` @@ -1355,80 +1387,96 @@ function handleNoOffersScenario() { } async function updateOffersTable() { - try { - const PRICES_CACHE_KEY = 'prices_coingecko'; - const cachedPrices = CacheManager.get(PRICES_CACHE_KEY); + try { + const PRICES_CACHE_KEY = 'prices_coingecko'; + const cachedPrices = CacheManager.get(PRICES_CACHE_KEY); - if (!cachedPrices || !cachedPrices.remainingTime || cachedPrices.remainingTime < 60000) { - console.log('Fetching fresh price data...'); - const priceData = await fetchLatestPrices(); - if (priceData) { - latestPrices = priceData; - } - } else { - latestPrices = cachedPrices.value; - } + if (!cachedPrices || !cachedPrices.remainingTime || cachedPrices.remainingTime < 60000) { + console.log('Fetching fresh price data...'); + const priceData = await fetchLatestPrices(); + if (priceData) { + latestPrices = priceData; + } + } else { + latestPrices = cachedPrices.value; + } - const validOffers = getValidOffers(); + const validOffers = getValidOffers(); - const startIndex = (currentPage - 1) * itemsPerPage; - const endIndex = Math.min(startIndex + itemsPerPage, validOffers.length); - const itemsToDisplay = validOffers.slice(startIndex, endIndex); + if (!isSentOffers) { + const networkOffersSpan = document.querySelector('a[href="/offers"] span.inline-flex.justify-center'); + if (networkOffersSpan) { + networkOffersSpan.textContent = validOffers.length; + } + } - const identityPromises = itemsToDisplay.map(offer => - offer.addr_from ? getIdentityData(offer.addr_from) : Promise.resolve(null) - ); + const startIndex = (currentPage - 1) * itemsPerPage; + const endIndex = Math.min(startIndex + itemsPerPage, validOffers.length); + const itemsToDisplay = validOffers.slice(startIndex, endIndex); - const identities = await Promise.all(identityPromises); + const identityPromises = itemsToDisplay.map(offer => + offer.addr_from ? getIdentityData(offer.addr_from) : Promise.resolve(null) + ); - if (validOffers.length === 0) { - handleNoOffersScenario(); - return; - } + const identities = await Promise.all(identityPromises); - const totalPages = Math.max(1, Math.ceil(validOffers.length / itemsPerPage)); - currentPage = Math.min(currentPage, totalPages); + if (validOffers.length === 0) { + const existingRows = offersBody.querySelectorAll('tr'); + existingRows.forEach(row => { + cleanupRow(row); + }); + handleNoOffersScenario(); + return; + } - const fragment = document.createDocumentFragment(); + const totalPages = Math.max(1, Math.ceil(validOffers.length / itemsPerPage)); + currentPage = Math.min(currentPage, totalPages); - itemsToDisplay.forEach((offer, index) => { - const identity = identities[index]; - const row = createTableRow(offer, identity); - if (row) { - fragment.appendChild(row); - } - }); + const fragment = document.createDocumentFragment(); - offersBody.innerHTML = ''; - offersBody.appendChild(fragment); + const existingRows = offersBody.querySelectorAll('tr'); + existingRows.forEach(row => { + cleanupRow(row); + }); - requestAnimationFrame(() => { - initializeFlowbiteTooltips(); - updateRowTimes(); - updatePaginationControls(totalPages); + itemsToDisplay.forEach((offer, index) => { + const identity = identities[index]; + const row = createTableRow(offer, identity); + if (row) { + fragment.appendChild(row); + } + }); - if (tableRateModule?.initializeTable) { - tableRateModule.initializeTable(); - } - }); + offersBody.textContent = ''; + offersBody.appendChild(fragment); - lastRefreshTime = Date.now(); - if (newEntriesCountSpan) { - newEntriesCountSpan.textContent = validOffers.length; - } - if (lastRefreshTimeSpan) { - lastRefreshTimeSpan.textContent = new Date(lastRefreshTime).toLocaleTimeString(); - } + requestAnimationFrame(() => { + initializeFlowbiteTooltips(); + updateRowTimes(); + updatePaginationControls(totalPages); - } catch (error) { - console.error('[Debug] Error in updateOffersTable:', error); - offersBody.innerHTML = ` - - - An error occurred while updating the offers table. Please try again later. - - `; - } + if (tableRateModule?.initializeTable) { + tableRateModule.initializeTable(); + } + }); + + lastRefreshTime = Date.now(); + if (newEntriesCountSpan) { + newEntriesCountSpan.textContent = validOffers.length; + } + if (lastRefreshTimeSpan) { + lastRefreshTimeSpan.textContent = new Date(lastRefreshTime).toLocaleTimeString(); + } + + } catch (error) { + console.error('[Debug] Error in updateOffersTable:', error); + offersBody.innerHTML = ` + + + An error occurred while updating the offers table. Please try again later. + + `; + } } async function getIdentityData(address) { diff --git a/basicswap/static/js/pricechart.js b/basicswap/static/js/pricechart.js index 6657819..d1712d6 100644 --- a/basicswap/static/js/pricechart.js +++ b/basicswap/static/js/pricechart.js @@ -38,13 +38,6 @@ const config = { currentResolution: 'year' }; -function getAPIKeys() { - return { - cryptoCompare: '{{chart_api_key}}', - coinGecko: '{{coingecko_api_key}}' - }; -} - // UTILS const utils = { formatNumber: (number, decimals = 2) => @@ -86,8 +79,9 @@ const logger = { // API const api = { - makePostRequest: (url, headers = {}) => { - return new Promise((resolve, reject) => { + makePostRequest: (url, headers = {}) => { + const apiKeys = getAPIKeys(); + return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('POST', '/json/readurl'); xhr.setRequestHeader('Content-Type', 'application/json'); @@ -147,8 +141,8 @@ const api = { .map(coin => coin.name) .join(','); const url = `${config.apiEndpoints.coinGecko}/simple/price?ids=${coinIds}&vs_currencies=usd,btc&include_24hr_vol=true&include_24hr_change=true&api_key=${config.apiKeys.coinGecko}`; - - console.log(`Fetching data for multiple coins from CoinGecko: ${url}`); + + //console.log(`Fetching data for multiple coins from CoinGecko: ${url}`); try { const data = await api.makePostRequest(url); @@ -675,7 +669,7 @@ const chartModule = { plugins: [chartModule.verticalLinePlugin] }); - console.log('Chart initialized:', chartModule.chart); + //console.log('Chart initialized:', chartModule.chart); }, prepareChartData: (coinSymbol, data) => { diff --git a/basicswap/templates/offers.html b/basicswap/templates/offers.html index 4b663de..65af777 100644 --- a/basicswap/templates/offers.html +++ b/basicswap/templates/offers.html @@ -11,15 +11,15 @@