// CryptoVista Dashboard Pro - Enhanced JavaScript
// API Configuration with fallbacks
const COINGECKO_API = 'https://api.coingecko.com/api/v3';
const CRYPTO_NEWS_API = 'https://min-api.cryptocompare.com/data/v2/news/';
const ALTERNATIVE_API = 'https://api.coincap.io/v2/assets?limit=5';
// Global State with enhanced monitoring
let cryptoData = {
marketData: null,
topGainers: [],
news: [],
userPreferences: {
currency: 'usd',
theme: 'dark',
refreshInterval: 30000,
notifications: true
},
performance: {
lastUpdate: null,
apiLatency: {},
errors: []
}
};
let selectedCurrency = localStorage.getItem('preferredCurrency') || 'usd';
let theme = localStorage.getItem('theme') || 'dark';
let isInitialized = false;
// Performance monitoring
const perfMonitor = {
start: (label) => {
if (window.performance) {
perfMonitor[label] = performance.now();
}
},
end: (label) => {
if (window.performance && perfMonitor[label]) {
const duration = performance.now() - perfMonitor[label];
console.log(`⏱️ ${label}: ${duration.toFixed(2)}ms`);
return duration;
}
return 0;
}
};
// Initialize Dashboard with enhanced UX
async function initializeDashboard() {
if (isInitialized) {
console.warn('Dashboard already initialized');
return;
}
perfMonitor.start('init');
try {
console.log('🚀 Initializing CryptoVista Dashboard Pro...');
// Set initial theme
applyTheme(theme);
// Show loading state
showLoadingState();
// Load critical data first
await Promise.allSettled([
loadTopGainers(),
loadNews(),
loadMarketData()
]);
// Setup enhanced auto-refresh
setupAutoRefresh();
// Setup enhanced event listeners
setupEventListeners();
// Initialize UI components
initializeUIComponents();
// Mark as initialized
isInitialized = true;
// Hide loading state
hideLoadingState();
perfMonitor.end('init');
// Show welcome message
setTimeout(() => {
showToast('Dashboard loaded successfully!', 'success');
}, 500);
console.log('✅ Dashboard initialized successfully');
} catch (error) {
console.error('❌ Dashboard initialization failed:', error);
showError('global', 'Failed to initialize dashboard. Please refresh.');
hideLoadingState();
}
}
// Load Top Gainers from CoinGecko API
async function loadTopGainers() {
try {
const response = await fetch(`${COINGECKO_API}/coins/markets?vs_currency=${selectedCurrency}&order=market_cap_desc&per_page=5&sparkline=false&price_change_percentage=24h`);
const gainers = await response.json();
const container = document.getElementById('topGainers');
container.innerHTML = '';
gainers.forEach((coin, index) => {
const isPositive = coin.price_change_percentage_24h > 0;
const changeClass = isPositive ? 'positive' : 'negative';
const coinElement = `
News feed temporarily unavailable
Check back soon for updates
`;
feather.replace();
}
}
// Load Market Overview Data
async function loadMarketData() {
try {
const response = await fetch(`${COINGECKO_API}/global`);
const data = await response.json();
cryptoData.marketData = data.data;
// Update market stats
updateMarketStats(data.data);
} catch (error) {
console.error('Error loading market data:', error);
}
}
// Update Market Stats Display
function updateMarketStats(marketData) {
const elements = {
totalMarketCap: document.querySelector('[data-market-cap]'),
totalVolume: document.querySelector('[data-volume]'),
btcDominance: document.querySelector('[data-btc-dominance]'),
activeCryptos: document.querySelector('[data-active-cryptos]')
};
if (marketData && marketData.total_market_cap) {
Object.keys(elements).forEach(key => {
if (elements[key] && marketData[key]) {
const value = marketData[key];
let formattedValue;
switch(key) {
case 'total_market_cap':
case 'total_volume':
formattedValue = `$${(value.usd / 1e12).toFixed(2)}T`;
break;
case 'btc_dominance':
formattedValue = `${value.toFixed(2)}%`;
break;
case 'active_cryptocurrencies':
formattedValue = value.toLocaleString();
break;
default:
formattedValue = value;
}
elements[key].textContent = formattedValue;
}
});
}
}
// Setup Auto Refresh
function setupAutoRefresh() {
// Refresh specific components at different intervals
setInterval(() => {
loadTopGainers();
console.log('🔄 Refreshed top gainers');
}, 30000); // 30 seconds
setInterval(() => {
loadMarketData();
console.log('📊 Refreshed market data');
}, 60000); // 1 minute
setInterval(() => {
loadNews();
console.log('📰 Refreshed news feed');
}, 120000); // 2 minutes
}
// Setup Event Listeners
function setupEventListeners() {
// Currency selector
const currencyButtons = document.querySelectorAll('[data-currency]');
currencyButtons.forEach(button => {
button.addEventListener('click', () => {
selectedCurrency = button.dataset.currency;
currencyButtons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
loadTopGainers();
});
});
// Theme toggle
const themeToggle = document.getElementById('themeToggle');
if (themeToggle) {
themeToggle.addEventListener('click', toggleTheme);
}
// Search functionality
const searchInput = document.getElementById('cryptoSearch');
if (searchInput) {
searchInput.addEventListener('input', debounce(handleSearch, 300));
}
// Time range buttons
const timeRangeButtons = document.querySelectorAll('[data-time-range]');
timeRangeButtons.forEach(button => {
button.addEventListener('click', () => {
timeRangeButtons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
// In production, update chart time range here
});
});
// Mobile menu toggle
const mobileMenuButton = document.getElementById('mobileMenuButton');
const mobileMenu = document.getElementById('mobileMenu');
if (mobileMenuButton && mobileMenu) {
mobileMenuButton.addEventListener('click', () => {
mobileMenu.classList.toggle('hidden');
});
}
}
// Handle Search Functionality
async function handleSearch(event) {
const query = event.target.value.toLowerCase().trim();
if (query.length < 2) {
hideSearchResults();
return;
}
try {
const response = await fetch(`${COINGECKO_API}/search?query=${query}`);
const data = await response.json();
displaySearchResults(data.coins || []);
} catch (error) {
console.error('Search error:', error);
}
}
// Display Search Results
function displaySearchResults(coins) {
const container = document.getElementById('searchResults');
if (!container) return;
container.innerHTML = coins.slice(0, 5).map(coin => `