// Monetization Toolkit JavaScript // Initialize the application document.addEventListener('DOMContentLoaded', function() { initializeApp(); setupEventListeners(); initializeCharts(); updateDashboardData(); // Handle hash-based navigation window.addEventListener('hashchange', function() { const section = window.location.hash.substring(1); if (section) { showSection(section); } }); // Initial section based on hash if (window.location.hash) { showSection(window.location.hash.substring(1)); } }); // Global variables let currentSection = 'dashboard'; let charts = {}; let timeRange = '7d'; // Initialize the application function initializeApp() { // Set default section showSection('dashboard'); // Initialize with sample data updateKPIs(); updateCharts(); // Set up periodic updates setInterval(updateKPIs, 30000); // Update every 30 seconds } // Setup event listeners function setupEventListeners() { // Navigation document.getElementById('region-select').addEventListener('change', function() { updateRegionData(this.value); }); // A/B Test Form document.getElementById('ab-test-form').addEventListener('submit', function(e) { e.preventDefault(); createNewTest(); }); // Modal buttons document.getElementById('watch-ad-btn').addEventListener('click', function() { simulateAdWatching(); }); document.getElementById('complete-purchase-btn').addEventListener('click', function() { completePurchase(); }); // Ad modal close on backdrop click document.getElementById('ad-modal').addEventListener('click', function(e) { if (e.target === this) closeAdModal(); }); document.getElementById('purchase-modal').addEventListener('click', function(e) { if (e.target === this) closePurchaseModal(); }); } // Section navigation function showSection(sectionName) { // Hide all sections const sections = document.querySelectorAll('.content-section'); sections.forEach(section => { section.classList.add('hidden'); }); // Show selected section document.getElementById(sectionName).classList.remove('hidden'); // Update navigation const navButtons = document.querySelectorAll('.nav-btn'); navButtons.forEach(btn => { btn.classList.remove('active'); }); event.target.classList.add('active'); currentSection = sectionName; // Update charts if needed if (sectionName === 'analytics') { updateAnalyticsCharts(); } } // Update KPIs function updateKPIs() { const kpis = { 'daily-revenue': generateRandomValue(2500, 3200, '$'), 'active-users': generateRandomValue(14500, 15800, ''), 'conversion-rate': generateRandomValue(2.8, 3.6, '%'), 'arpu': generateRandomValue(0.15, 0.22, '$') }; Object.keys(kpis).forEach(id => { const element = document.getElementById(id); if (element) { animateValue(element, element.textContent, kpis[id]); } }); } // Generate random values for simulation function generateRandomValue(min, max, prefix = '') { const value = (Math.random() * (max - min) + min).toFixed(max < 10 ? 2 : 0); return prefix + value; } // Animate value changes function animateValue(element, start, end) { const startTime = performance.now(); const duration = 1000; function updateValue(currentTime) { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); // Simple interpolation const startNum = parseFloat(start.replace(/[^\d.-]/g, '')) || 0; const endNum = parseFloat(end.replace(/[^\d.-]/g, '')) || 0; const current = startNum + (endNum - startNum) * progress; const prefix = start.match(/^[^\d]*/)?.[0] || ''; const suffix = start.match(/[^\d]*$/)?.[0] || ''; element.textContent = prefix + current.toFixed(start.includes('%') ? 2 : start.includes('$') && startNum < 1 ? 3 : 0) + suffix; if (progress < 1) { requestAnimationFrame(updateValue); } } requestAnimationFrame(updateValue); } // Initialize Charts function initializeCharts() { // Revenue Chart const revenueCtx = document.getElementById('revenue-chart'); if (revenueCtx) { charts.revenue = new Chart(revenueCtx, { type: 'line', data: { labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], datasets: [{ label: 'Revenue', data: generateChartData(7, 2000, 3000), borderColor: '#ec4899', backgroundColor: 'rgba(236, 72, 153, 0.1)', tension: 0.4, fill: true }] }, options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: false, ticks: { callback: function(value) { return '$' + value; } } } } } }); } // User Chart const userCtx = document.getElementById('user-chart'); if (userCtx) { charts.user = new Chart(userCtx, { type: 'bar', data: { labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], datasets: [{ label: 'New Users', data: generateChartData(7, 500, 1000), backgroundColor: '#14b8a6', borderRadius: 4 }] }, options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true } } } }); } // Ads Performance Chart const adsCtx = document.getElementById('ads-performance-chart'); if (adsCtx) { charts.ads = new Chart(adsCtx, { type: 'doughnut', data: { labels: ['Completed', 'Skipped', 'Failed'], datasets: [{ data: [75, 20, 5], backgroundColor: ['#14b8a6', '#ec4899', '#f3f4f6'], borderWidth: 0 }] }, options: { responsive: true, plugins: { legend: { position: 'bottom' } } } }); } // Purchase Chart const purchaseCtx = document.getElementById('purchase-chart'); if (purchaseCtx) { charts.purchase = new Chart(purchaseCtx, { type: 'pie', data: { labels: ['Starter Pack', 'Value Pack', 'Mega Pack'], datasets: [{ data: [25, 45, 30], backgroundColor: ['#ec4899', '#14b8a6', '#f3f4f6'], borderWidth: 0 }] }, options: { responsive: true, plugins: { legend: { position: 'bottom' } } } }); } // Analytics Charts initializeAnalyticsCharts(); } // Initialize Analytics Charts function initializeAnalyticsCharts() { // Revenue Source Chart const revenueSourceCtx = document.getElementById('revenue-source-chart'); if (revenueSourceCtx) { charts.revenueSource = new Chart(revenueSourceCtx, { type: 'bar', data: { labels: ['Rewarded Ads', 'In-App Purchases', 'Subscriptions'], datasets: [{ label: 'Revenue ($)', data: [15000, 25000, 8000], backgroundColor: ['#ec4899', '#14b8a6', '#f3f4f6'], borderRadius: 4 }] }, options: { responsive: true, indexAxis: 'y', plugins: { legend: { display: false } } } }); } // Retention Chart const retentionCtx = document.getElementById('retention-chart'); if (retentionCtx) { charts.retention = new Chart(retentionCtx, { type: 'line', data: { labels: ['Day 1', 'Day 3', 'Day 7', 'Day 14', 'Day 30'], datasets: [{ label: 'Retention Rate', data: [100, 65, 45, 35, 28], borderColor: '#14b8a6', backgroundColor: 'rgba(20, 184, 166, 0.1)', tension: 0.4, fill: true }] }, options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, max: 100, ticks: { callback: function(value) { return value + '%'; } } } } } }); } } // Generate chart data function generateChartData(days, min, max) { const data = []; for (let i = 0; i < days; i++) { data.push(Math.floor(Math.random() * (max - min) + min)); } return data; } // Update charts function updateCharts() { Object.keys(charts).forEach(chartKey => { if (charts[chartKey]) { // Update with new data if (chartKey === 'revenue') { charts[chartKey].data.datasets[0].data = generateChartData(7, 2000, 3000); } else if (chartKey === 'user') { charts[chartKey].data.datasets[0].data = generateChartData(7, 500, 1000); } charts[chartKey].update('none'); } }); } // Update analytics charts function updateAnalyticsCharts() { // Add some animation to charts when section is shown Object.keys(charts).forEach(chartKey => { if (charts[chartKey] && charts[chartKey].canvas.closest('#analytics')) { charts[chartKey].update('active'); } }); } // Time range update function updateTimeRange(range) { timeRange = range; // Update button states const buttons = document.querySelectorAll('.time-range-btn'); buttons.forEach(btn => { btn.classList.remove('bg-pink-500', 'text-white'); btn.classList.add('bg-gray-200', 'text-gray-700'); }); event.target.classList.remove('bg-gray-200', 'text-gray-700'); event.target.classList.add('bg-pink-500', 'text-white'); // Update charts with new time range updateChartsForTimeRange(range); } // Update charts for specific time range function updateChartsForTimeRange(range) { let days, min, max; switch(range) { case '7d': days = 7; min = 2000; max = 3000; break; case '30d': days = 30; min = 1800; max = 3200; break; case '90d': days = 90; min = 1600; max = 3400; break; } if (charts.revenue) { charts.revenue.data.labels = generateTimeLabels(days); charts.revenue.data.datasets[0].data = generateChartData(days, min, max); charts.revenue.update('active'); } } // Generate time labels function generateTimeLabels(days) { const labels = []; const today = new Date(); for (let i = days - 1; i >= 0; i--) { const date = new Date(today); date.setDate(date.getDate() - i); labels.push(date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })); } return labels; } // Create new A/B test function createNewTest() { const form = document.getElementById('ab-test-form'); const formData = new FormData(form); // Simulate test creation showNotification('A/B Test created successfully!', 'success'); form.reset(); // Add to active tests list (simulation) setTimeout(() => { updateActiveTests(); }, 1000); } // Update active tests list function updateActiveTests() { // This would typically fetch from an API console.log('Updating active tests...'); } // Region data update function updateRegionData(region) { // Simulate region-specific data updates showNotification(`Region changed to ${region.toUpperCase()}`, 'info'); // Update KPIs based on region updateKPIsForRegion(region); } // Update KPIs for specific region function updateKPIsForRegion(region) { const regionMultipliers = { 'global': 1.0, 'us': 1.2, 'eu': 1.1, 'asia': 0.8, 'latam': 0.6 }; const multiplier = regionMultipliers[region] || 1.0; // Update with regional data const baseValues = { 'daily-revenue': 2847, 'active-users': 15234, 'conversion-rate': 3.24, 'arpu': 0.187 }; Object.keys(baseValues).forEach(id => { const element = document.getElementById(id); if (element) { const baseValue = baseValues[id]; const newValue = baseValue * multiplier * (0.9 + Math.random() * 0.2); let formattedValue; if (id === 'daily-revenue') { formattedValue = '$' + newValue.toFixed(0); } else if (id === 'active-users') { formattedValue = Math.round(newValue).toLocaleString(); } else if (id === 'conversion-rate') { formattedValue = newValue.toFixed(2) + '%'; } else if (id === 'arpu') { formattedValue = '$' + newValue.toFixed(3); } animateValue(element, element.textContent, formattedValue); } }); } // Simulate ad watching function simulateAdWatching() { const button = document.getElementById('watch-ad-btn'); const originalText = button.textContent; button.disabled = true; button.innerHTML = '
'; // Simulate ad duration setTimeout(() => { button.textContent = 'Ad Complete!'; button.classList.remove('bg-pink-500', 'hover:bg-pink-600'); button.classList.add('bg-green-500', 'hover:bg-green-600'); setTimeout(() => { closeAdModal(); showNotification('Ad watched successfully! +3 extra lives', 'success'); button.textContent = originalText; button.disabled = false; button.classList.remove('bg-green-500', 'hover:bg-green-600'); button.classList.add('bg-pink-500', 'hover:bg-pink-600'); }, 1500); }, 3000); } // Complete purchase function completePurchase() { const button = document.getElementById('complete-purchase-btn'); const originalText = button.textContent; button.disabled = true; button.innerHTML = ''; // Simulate purchase processing setTimeout(() => { button.textContent = 'Purchase Complete!'; button.classList.remove('bg-teal-500', 'hover:bg-teal-600'); button.classList.add('bg-green-500', 'hover:bg-green-600'); setTimeout(() => { closePurchaseModal(); showNotification('Purchase successful! 2,500 coins added to your account', 'success'); button.textContent = originalText; button.disabled = false; button.classList.remove('bg-green-500', 'hover:bg-green-600'); button.classList.add('bg-teal-500', 'hover:bg-teal-600'); }, 1500); }, 2000); } // Modal functions function closeAdModal() { document.getElementById('ad-modal').classList.add('hidden'); } function closePurchaseModal() { document.getElementById('purchase-modal').classList.add('hidden'); } // Show notification function showNotification(message, type = 'info') { // Create notification element const notification = document.createElement('div'); notification.className = `fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg max-w-sm transform transition-all duration-300 translate-x-full`; // Set colors based on type switch(type) { case 'success': notification.classList.add('bg-green-500', 'text-white'); break; case 'error': notification.classList.add('bg-red-500', 'text-white'); break; case 'warning': notification.classList.add('bg-yellow-500', 'text-white'); break; default: notification.classList.add('bg-blue-500', 'text-white'); } notification.innerHTML = `