let currentUser = null; let pluginsData = []; let usageStats = null; let adminUsers = []; let currentPage = 0; const usersPerPage = 3; let selectedUserForRole = null; let countdownInterval = null; let apiStatsCharts = { topEndpoints: null, successFail: null, dailyRequests: null, hourlyTrends: null }; async function loadApiStats() { try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/stats/all', { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { const result = await response.json(); if (result.success) { updateApiStatsUI(result.stats); renderApiStatsCharts(result.stats); } } } catch (error) { console.error('Error loading API stats:', error); } } function updateApiStatsUI(stats) { document.getElementById('globalTotalRequests').textContent = formatNumber(stats.totalRequests); document.getElementById('globalTodayRequests').textContent = formatNumber(stats.todayRequests); document.getElementById('successRate').textContent = stats.successRate + '%'; document.getElementById('failRate').textContent = stats.failRate + '%'; const listContainer = document.getElementById('topEndpointsList'); if (stats.topEndpoints.length > 0) { listContainer.innerHTML = stats.topEndpoints.map((ep, index) => `
#${index + 1} ${ep.endpoint}
${ep.count} total āœ“ ${ep.successCount} āœ— ${ep.failCount}
`).join(''); } else { listContainer.innerHTML = '
No endpoint data available
'; } } function renderApiStatsCharts(stats) { Object.values(apiStatsCharts).forEach(chart => { if (chart) chart.destroy(); }); const topEndpointsCtx = document.getElementById('topEndpointsChart'); if (topEndpointsCtx && stats.topEndpoints.length > 0) { apiStatsCharts.topEndpoints = new Chart(topEndpointsCtx, { type: 'pie', data: { labels: stats.topEndpoints.map(ep => ep.endpoint), datasets: [{ data: stats.topEndpoints.map(ep => ep.count), backgroundColor: [ 'rgba(133, 48, 48, 0.8)', 'rgba(255, 107, 107, 0.8)', 'rgba(255, 168, 168, 0.8)', 'rgba(108, 117, 125, 0.8)', 'rgba(255, 193, 7, 0.8)', 'rgba(40, 167, 69, 0.8)', 'rgba(23, 162, 184, 0.8)', 'rgba(220, 53, 69, 0.8)', 'rgba(138, 43, 226, 0.8)', 'rgba(255, 140, 0, 0.8)' ], borderWidth: 2, borderColor: 'rgba(255, 255, 255, 0.2)' }] }, options: { responsive: true, maintainAspectRatio: true, plugins: { legend: { position: 'bottom', labels: { color: 'rgba(255, 255, 255, 0.8)', padding: 15, font: { size: 11 } } }, tooltip: { backgroundColor: 'rgba(0, 0, 0, 0.8)', padding: 12, titleColor: '#fff', bodyColor: '#fff' } } } }); } const successFailCtx = document.getElementById('successFailChart'); if (successFailCtx) { apiStatsCharts.successFail = new Chart(successFailCtx, { type: 'doughnut', data: { labels: ['Success', 'Failed'], datasets: [{ data: [stats.successCount, stats.failCount], backgroundColor: [ 'rgba(40, 167, 69, 0.8)', 'rgba(220, 53, 69, 0.8)' ], borderWidth: 2, borderColor: 'rgba(255, 255, 255, 0.2)' }] }, options: { responsive: true, maintainAspectRatio: true, plugins: { legend: { position: 'bottom', labels: { color: 'rgba(255, 255, 255, 0.8)', padding: 15, font: { size: 12 } } }, tooltip: { backgroundColor: 'rgba(0, 0, 0, 0.8)', padding: 12, callbacks: { label: function(context) { const label = context.label || ''; const value = context.parsed || 0; const total = stats.totalRequests; const percentage = ((value / total) * 100).toFixed(2); return `${label}: ${value} (${percentage}%)`; } } } } } }); } const dailyRequestsCtx = document.getElementById('dailyRequestsChart'); if (dailyRequestsCtx && stats.dailyRequests.length > 0) { apiStatsCharts.dailyRequests = new Chart(dailyRequestsCtx, { type: 'bar', data: { labels: stats.dailyRequests.map(day => { const date = new Date(day.date); return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); }), datasets: [ { label: 'Success', data: stats.dailyRequests.map(day => day.success), backgroundColor: 'rgba(40, 167, 69, 0.7)', borderColor: 'rgba(40, 167, 69, 1)', borderWidth: 1 }, { label: 'Failed', data: stats.dailyRequests.map(day => day.fail), backgroundColor: 'rgba(220, 53, 69, 0.7)', borderColor: 'rgba(220, 53, 69, 1)', borderWidth: 1 } ] }, options: { responsive: true, maintainAspectRatio: true, scales: { x: { stacked: true, ticks: { color: 'rgba(255, 255, 255, 0.8)' }, grid: { color: 'rgba(255, 255, 255, 0.1)' } }, y: { stacked: true, ticks: { color: 'rgba(255, 255, 255, 0.8)' }, grid: { color: 'rgba(255, 255, 255, 0.1)' } } }, plugins: { legend: { labels: { color: 'rgba(255, 255, 255, 0.8)' } }, tooltip: { backgroundColor: 'rgba(0, 0, 0, 0.8)', padding: 12 } } } }); } const hourlyTrendsCtx = document.getElementById('hourlyTrendsChart'); if (hourlyTrendsCtx && stats.hourlyRequests.length > 0) { apiStatsCharts.hourlyTrends = new Chart(hourlyTrendsCtx, { type: 'line', data: { labels: stats.hourlyRequests.map(hour => { const date = new Date(hour.hour); return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }); }), datasets: [{ label: 'Requests per Hour', data: stats.hourlyRequests.map(hour => hour.count), borderColor: 'rgba(133, 48, 48, 1)', backgroundColor: 'rgba(133, 48, 48, 0.1)', borderWidth: 2, fill: true, tension: 0.4, pointRadius: 4, pointBackgroundColor: 'rgba(133, 48, 48, 1)', pointBorderColor: '#fff', pointBorderWidth: 2 }] }, options: { responsive: true, maintainAspectRatio: true, scales: { x: { ticks: { color: 'rgba(255, 255, 255, 0.8)', maxRotation: 45, minRotation: 45 }, grid: { color: 'rgba(255, 255, 255, 0.1)' } }, y: { ticks: { color: 'rgba(255, 255, 255, 0.8)' }, grid: { color: 'rgba(255, 255, 255, 0.1)' } } }, plugins: { legend: { labels: { color: 'rgba(255, 255, 255, 0.8)' } }, tooltip: { backgroundColor: 'rgba(0, 0, 0, 0.8)', padding: 12 } } } }); } } function formatCountdown(hours, minutes, seconds) { const h = String(hours).padStart(2, '0'); const m = String(minutes).padStart(2, '0'); const s = String(seconds).padStart(2, '0'); return `${h}:${m}:${s}`; } function startCountdownTimer(nextResetTime) { if (countdownInterval) { clearInterval(countdownInterval); } const updateCountdown = () => { const now = new Date(); const resetTime = new Date(nextResetTime); const diff = resetTime - now; if (diff <= 0) { loadUserProfile(); return; } const hours = Math.floor(diff / (1000 * 60 * 60)); const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((diff % (1000 * 60)) / 1000); const countdownElements = document.querySelectorAll('.reset-countdown'); countdownElements.forEach(el => { el.textContent = formatCountdown(hours, minutes, seconds); }); const progressBars = document.querySelectorAll('.reset-progress'); progressBars.forEach(bar => { const totalDay = 24 * 60 * 60 * 1000; const elapsed = totalDay - diff; const percentage = (elapsed / totalDay) * 100; bar.style.width = `${percentage}%`; }); }; updateCountdown(); countdownInterval = setInterval(updateCountdown, 1000); } async function searchUsersForRole(query) { const resultsDiv = document.getElementById('userSearchResults'); if (!query.trim()) { resultsDiv.style.display = 'none'; return; } try { const token = localStorage.getItem('dashx_token'); const response = await fetch(`/api/admin/search-users?query=${encodeURIComponent(query)}`, { headers: { 'Authorization': `Bearer ${token}` } }); const result = await response.json(); if (result.success && result.users.length > 0) { resultsDiv.innerHTML = result.users.map(user => `
${user.username}
${user.email}
Limit: ${user.limit} | ${user.premium ? 'Premium' : 'Free'}
`).join(''); resultsDiv.style.display = 'block'; } else { resultsDiv.innerHTML = '
No users found
'; resultsDiv.style.display = 'block'; } } catch (error) { console.error('Search error:', error); } } function selectUserForRole(userId, username, email) { selectedUserForRole = userId; document.getElementById('selectedUserId').value = userId; document.getElementById('selectedUserDisplay').value = `${username} (${email})`; document.getElementById('userSearchResults').style.display = 'none'; document.getElementById('searchUserInput').value = ''; } async function assignUserRole() { const userId = document.getElementById('selectedUserId').value; const roleName = document.getElementById('assignRoleType').value; const customApiKey = document.getElementById('customApiKey').value.trim(); if (!userId) { Swal.fire({ icon: 'error', title: 'No User Selected', text: 'Please search and select a user first' }); return; } if (!roleName) { Swal.fire({ icon: 'error', title: 'Invalid Role', text: 'Please select a role' }); return; } try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/admin/set-role', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ userId, roleName, customApiKey }) }); const result = await response.json(); if (result.success) { await Swal.fire({ icon: 'success', title: 'Role Assigned!', html: `

Role: ${roleName.toUpperCase()}

New Limit: ${result.newLimit}

Expires: ${new Date(result.expiresAt).toLocaleString()}

${customApiKey ? `

API Key: ${result.apiKey}

` : ''} ` }); document.getElementById('selectedUserId').value = ''; document.getElementById('selectedUserDisplay').value = ''; document.getElementById('customApiKey').value = ''; selectedUserForRole = null; loadAdminUsers(); } else { Swal.fire({ icon: 'error', title: 'Assignment Failed', text: result.error }); } } catch (error) { Swal.fire({ icon: 'error', title: 'Network Error', text: 'Failed to assign role' }); } } async function loadServerStats() { try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/server-stats', { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }); const result = await response.json(); if (!response.ok) { console.error('Server stats error:', result.error); return; } if (result.success) { document.getElementById('totalUsersCount').textContent = result.stats.totalUsers || 0; document.getElementById('regularUsersCount').textContent = result.stats.regularUsers || 0; document.getElementById('premiumUsersCount').textContent = result.stats.premiumUsers || 0; document.getElementById('cheapCount').textContent = result.stats.roleDistribution.cheap || 0; document.getElementById('premiumCount').textContent = result.stats.roleDistribution.premium || 0; document.getElementById('vipCount').textContent = result.stats.roleDistribution.vip || 0; document.getElementById('supremeCount').textContent = result.stats.roleDistribution.supreme || 0; document.getElementById('dbSize').textContent = result.stats.database.size || '0 MB'; document.getElementById('ramUsage').textContent = result.stats.system.ramUsage || '0 MB'; document.getElementById('cpuUsage').textContent = result.stats.system.cpuUsage + '%' || '0%'; document.getElementById('storageUsed').textContent = result.stats.system.storageUsed || '0 GB'; renderRoleChart(result.stats.roleDistribution); } } catch (error) { console.error('Server stats error:', error); } } function renderRoleChart(roleData) { const ctx = document.getElementById('roleChart'); if (!ctx) return; if (window.roleChartInstance) { window.roleChartInstance.destroy(); } window.roleChartInstance = new Chart(ctx, { type: 'pie', data: { labels: ['Regular', 'Cheap', 'Premium', 'VIP', 'Supreme'], datasets: [{ data: [ roleData.regular || 0, roleData.cheap || 0, roleData.premium || 0, roleData.vip || 0, roleData.supreme || 0 ], backgroundColor: [ 'rgba(108, 117, 125, 0.8)', 'rgba(255, 193, 7, 0.8)', 'rgba(133, 48, 48, 0.8)', 'rgba(255, 215, 0, 0.8)', 'rgba(138, 43, 226, 0.8)' ], borderWidth: 2, borderColor: 'rgba(255, 255, 255, 0.2)' }] }, options: { responsive: true, maintainAspectRatio: true, plugins: { legend: { position: 'bottom', labels: { color: 'rgba(255, 255, 255, 0.8)', padding: 15, font: { size: 12 } } }, tooltip: { backgroundColor: 'rgba(0, 0, 0, 0.8)', padding: 12, titleColor: '#fff', bodyColor: '#fff', borderColor: 'rgba(255, 255, 255, 0.2)', borderWidth: 1 } } } }); } document.addEventListener('DOMContentLoaded', function() { if (!checkAuth()) return; loadUserProfile(); loadPlugins(); showSection('overview'); const redeemTypeEl = document.getElementById('redeemType'); if (redeemTypeEl) { redeemTypeEl.addEventListener('change', updateRedeemFormVisibility); updateRedeemFormVisibility(); } setInterval(() => { if (currentUser) { loadUserProfile(); if (currentUser.role === 'admin') { loadAdminStats(); } } }, 5000); setTimeout(setupAutoSave, 1000); }); function checkAuth() { const token = localStorage.getItem('dashx_token'); const user = JSON.parse(localStorage.getItem('dashx_user') || '{}'); if (!token || !user.username) { window.location.href = '/auth'; return false; } currentUser = user; if (user.role === 'admin') { const adminMenu = document.getElementById('adminMenu'); if (adminMenu) { adminMenu.style.display = 'block'; } loadAdminStats(); } loadServerStats(); return true; } async function loadUserProfile() { try { const token = localStorage.getItem('dashx_token'); if (!token) { window.location.href = '/auth'; return; } const response = await fetch('/api/user/profile', { headers: { 'Authorization': `Bearer ${token}` } }); if (response.status === 401) { localStorage.removeItem('dashx_token'); localStorage.removeItem('dashx_user'); window.location.href = '/auth'; return; } if (response.ok) { const result = await response.json(); if (result.success) { const user = result.user; localStorage.setItem('dashx_user', JSON.stringify(user)); currentUser = user; await loadUsageStats(); updateProfileElements(user); if (user.tempBanned) { const banUntil = new Date(user.tempBanUntil); Swal.fire({ icon: 'warning', title: 'Account Temporarily Banned', html: `Your account is temporarily banned until ${banUntil.toLocaleString()}
Reason: ${user.tempBanReason || 'No reason provided'}`, allowOutsideClick: false }); } } } } catch (error) { console.error('Error loading profile:', error); } } async function loadUsageStats() { try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/user/usage-stats', { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { const result = await response.json(); if (result.success) { usageStats = result.stats; updateUsageChart(); } } } catch (error) { console.error('Error loading usage stats:', error); const chartElement = document.querySelector('.usage-overview'); if (chartElement) { chartElement.innerHTML = `

Unable to load usage statistics

`; } } } function updateUsageChart() { const chartElement = document.querySelector('.usage-overview'); if (!chartElement || !usageStats) return; const hasData = usageStats.topEndpoints.length > 0 || usageStats.dailyUsage.length > 0 || usageStats.recentIPs.length > 0; if (!hasData) { chartElement.innerHTML = `

No API usage data yet

Start making API requests to see analytics here
`; return; } chartElement.innerHTML = `

Top API Endpoints

${usageStats.topEndpoints.length > 0 ? usageStats.topEndpoints.slice(0, 5).map(ep => `
${ep.endpoint || 'Unknown'} ${ep.count} requests
`).join('') : '
No endpoints used yet
' }

Daily Usage (Last 7 Days)

${usageStats.dailyUsage.length > 0 ? usageStats.dailyUsage.map(day => `
${new Date(day.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}
${day.limitUsed || 0}
`).join('') : '
No usage data available
' }

Recent IP Addresses

${usageStats.recentIPs.length > 0 ? usageStats.recentIPs.slice(0, 5).map(ip => `
${ip.address}
${ip.timeAgo}
${ip.count} requests
`).join('') : '
No IP data available
' }
`; } function updateProfileElements(user) { const apiKeyElement = document.getElementById('userApiKey'); const requestsElement = document.getElementById('userRequests'); const todayElement = document.getElementById('userRequestsToday'); const limitElement = document.getElementById('userLimit'); const limitTodayElement = document.getElementById('userLimitToday'); if (apiKeyElement) { if (user.role === 'admin' && user.apikey === 'DHX-M3SA') { apiKeyElement.textContent = user.apikey; apiKeyElement.style.fontSize = '0.9rem'; apiKeyElement.style.fontWeight = 'bold'; apiKeyElement.style.color = '#853030'; } else { apiKeyElement.textContent = user.apikey || 'N/A'; } } if (requestsElement && usageStats) { requestsElement.textContent = formatNumber(usageStats.totalRequests || 0); } if (todayElement) { const todayRequests = user.requestsToday || 0; todayElement.textContent = formatNumber(todayRequests); } if (limitElement) { if (user.role === 'admin' && user.limit >= 9999) { limitElement.textContent = 'āˆž'; limitElement.style.fontSize = '2.5rem'; limitElement.style.color = '#853030'; limitElement.style.fontWeight = 'bold'; } else { limitElement.textContent = formatNumber(user.limit || 30); } } if (limitTodayElement) { if (user.role === 'admin' && user.limit >= 9999) { limitTodayElement.textContent = 'āˆž'; limitTodayElement.style.fontSize = '2.5rem'; limitTodayElement.style.color = '#853030'; limitTodayElement.style.fontWeight = 'bold'; } else { const requestsToday = user.requestsToday || 0; const totalLimit = user.limit || 30; const remainingLimit = Math.max(0, totalLimit - requestsToday); limitTodayElement.textContent = formatNumber(remainingLimit); const percentage = (remainingLimit / totalLimit) * 100; if (remainingLimit <= 0) { limitTodayElement.style.color = '#ff6b6b'; } else if (percentage <= 10) { limitTodayElement.style.color = '#ff6b6b'; } else if (percentage <= 30) { limitTodayElement.style.color = '#ffa500'; } else if (percentage <= 50) { limitTodayElement.style.color = '#ffeb3b'; } else { limitTodayElement.style.color = '#4caf50'; } } } if (user.nextResetTime) { startCountdownTimer(user.nextResetTime); } if (user.premium || user.role === 'admin') { const premiumSettings = document.getElementById('premiumSettings'); if (premiumSettings) { premiumSettings.style.display = 'block'; } } } function formatNumber(num) { if (typeof num !== 'number') return '0'; if (num >= 1000000) { return (num / 1000000).toFixed(1) + 'M'; } else if (num >= 1000) { return (num / 1000).toFixed(1) + 'K'; } return num.toString(); } async function loadPlugins() { try { const response = await fetch('/api/plugins'); const result = await response.json(); if (result.success) { pluginsData = result.plugins; renderPluginsByTags(pluginsData); } } catch (error) { console.error('Error loading plugins:', error); const pluginsGrid = document.getElementById('pluginsGrid'); if (pluginsGrid) { pluginsGrid.innerHTML = `
Error loading plugins: ${error.message}
`; } } } function renderPluginsByTags(plugins) { const pluginsGrid = document.getElementById('pluginsGrid'); if (!pluginsGrid) return; if (plugins.length === 0) { pluginsGrid.innerHTML = `

No plugins available at the moment

`; return; } const pluginsByTag = {}; const noTagPlugins = []; plugins.forEach((plugin, index) => { plugin.originalIndex = index; if (plugin.main && Array.isArray(plugin.main) && plugin.main.length > 0) { plugin.main.forEach(tag => { if (!pluginsByTag[tag]) { pluginsByTag[tag] = []; } pluginsByTag[tag].push(plugin); }); } else { noTagPlugins.push(plugin); } }); let html = ''; if (noTagPlugins.length > 0) { html += `
No Tag ${noTagPlugins.length} plugins
${noTagPlugins.map(plugin => createPluginCardHTML(plugin, plugin.originalIndex)).join('')}
`; } Object.keys(pluginsByTag).sort().forEach(tag => { const tagPlugins = pluginsByTag[tag]; const tagId = tag.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase(); html += `
${tag} ${tagPlugins.length} plugins
${tagPlugins.map(plugin => createPluginCardHTML(plugin, plugin.originalIndex)).join('')}
`; }); pluginsGrid.innerHTML = html; } function toggleTagSection(tagId) { const content = document.getElementById(`content-${tagId}`); const expand = document.getElementById(`expand-${tagId}`); if (!content || !expand) return; const isExpanded = content.classList.contains('expanded'); if (isExpanded) { content.classList.remove('expanded'); expand.classList.remove('expanded'); } else { content.classList.add('expanded'); expand.classList.add('expanded'); } } function searchPlugins(query) { if (!query.trim()) { renderPluginsByTags(pluginsData); return; } const filtered = pluginsData.filter(plugin => plugin.name.toLowerCase().includes(query.toLowerCase()) || plugin.description.toLowerCase().includes(query.toLowerCase()) || (plugin.tags && plugin.tags.some(tag => tag.toLowerCase().includes(query.toLowerCase()))) || (plugin.main && plugin.main.some(tag => tag.toLowerCase().includes(query.toLowerCase()))) ); renderPluginsByTags(filtered); } function createPluginCardHTML(plugin, index) { const user = JSON.parse(localStorage.getItem('dashx_user') || '{}'); const userApiKey = user.apikey || 'N/A'; const parametersHTML = (plugin.parameters || []) .filter(param => param !== 'key') .map(param => `
`).join(''); const keyFieldHTML = `
`; return `
${plugin.name}
${plugin.description}
Limit Cost: ${plugin.limit || 1}
${plugin.type}
${(plugin.tags || []).map(tag => `${tag}`).join('')}
${window.location.origin}/${plugin.routes[0] || 'unknown'}
Parameters
${parametersHTML} ${keyFieldHTML}
Response
`; } function getPlaceholder(param) { const placeholders = { 'url': 'https://example.com', 'sitekey': '0x4AAAAAAAdJZmNxW54o-Gvd', 'text': 'Your text here', 'size': '200', 'format': 'png', 'query': 'search term', 'username': 'username', 'type': 'words', 'count': '10', 'length': '12', 'wordType': 'lorem' }; return placeholders[param] || `Enter ${param}`; } function togglePlugin(index) { const content = document.getElementById(`content-${index}`); const expand = document.getElementById(`expand-${index}`); const card = content ? content.parentElement : null; if (!content || !expand) { return; } const isExpanded = content.classList.contains('expanded'); if (isExpanded) { content.classList.remove('expanded'); expand.classList.remove('expanded'); if (card) card.classList.remove('expanded'); } else { content.classList.add('expanded'); expand.classList.add('expanded'); if (card) card.classList.add('expanded'); } } function updatePluginURL(index, route, method) { const form = document.getElementById(`form-${index}`); const urlElement = document.getElementById(`plugin-url-${index}`); if (!form || !urlElement) return; const baseURL = `${window.location.origin}/${route}`; if (!urlElement.getAttribute('data-base-url')) { urlElement.setAttribute('data-base-url', baseURL); } const formData = new FormData(form); const params = {}; for (let [key, value] of formData.entries()) { if (value.trim()) { params[key] = value; } } if (Object.keys(params).length === 0 || (Object.keys(params).length === 1 && params.key)) { urlElement.textContent = baseURL; return; } if (method === 'GET') { const queryString = new URLSearchParams(params).toString(); urlElement.textContent = `${baseURL}?${queryString}`; } else { urlElement.textContent = baseURL; } } function copyPluginURL(index) { const urlElement = document.getElementById(`plugin-url-${index}`); if (!urlElement) return; const url = urlElement.textContent; navigator.clipboard.writeText(url).then(() => { const originalBg = urlElement.style.background; urlElement.style.background = 'rgba(40, 167, 69, 0.2)'; Swal.fire({ title: "Copied!", text: "URL copied to clipboard", icon: "success", timer: 1500, showConfirmButton: false }); setTimeout(() => { urlElement.style.background = originalBg; }, 1000); }).catch(() => { Swal.fire({ icon: "error", title: "Copy Failed", text: "Could not copy URL to clipboard" }); }); } async function executePlugin(event, index, route, method) { event.preventDefault(); const form = document.getElementById(`form-${index}`); const executeBtn = document.getElementById(`execute-${index}`); const responseContainer = document.getElementById(`response-${index}`); const responseBody = document.getElementById(`response-body-${index}`); const statusElement = document.getElementById(`status-${index}`); if (!form || !executeBtn || !responseContainer || !responseBody || !statusElement) { return; } const formData = new FormData(form); const params = Object.fromEntries(formData); executeBtn.disabled = true; executeBtn.innerHTML = '
Executing...'; try { const url = method === 'GET' ? `/${route}?${new URLSearchParams(params).toString()}` : `/${route}`; const options = { method: method, headers: method === 'POST' ? { 'Content-Type': 'application/json' } : {} }; if (method === 'POST') { options.body = JSON.stringify(params); } const response = await fetch(url, options); const result = await response.json(); responseContainer.classList.add('show'); responseBody.textContent = JSON.stringify(result, null, 2); if (response.ok && result.success) { statusElement.textContent = 'Success'; statusElement.className = 'response-status success'; Swal.fire({ title: "Success!", text: "API request executed successfully", icon: "success", timer: 2000, showConfirmButton: false }); await loadUserProfile(); await loadUsageStats(); } else { statusElement.textContent = 'Error'; statusElement.className = 'response-status error'; Swal.fire({ icon: "error", title: "Request Failed", text: result.error || "Unknown error occurred" }); } } catch (error) { responseContainer.classList.add('show'); responseBody.textContent = JSON.stringify({ error: error.message }, null, 2); statusElement.textContent = 'Error'; statusElement.className = 'response-status error'; Swal.fire({ icon: "error", title: "Network Error", text: "Failed to connect to the API" }); } finally { executeBtn.disabled = false; executeBtn.innerHTML = ' Execute'; } } function resetForm(index) { const form = document.getElementById(`form-${index}`); const responseContainer = document.getElementById(`response-${index}`); if (form) { const user = JSON.parse(localStorage.getItem('dashx_user') || '{}'); const userApiKey = user.apikey || 'N/A'; form.reset(); const keyInput = form.querySelector('input[name="key"]'); if (keyInput) { keyInput.value = userApiKey; keyInput.placeholder = userApiKey; } } if (responseContainer) responseContainer.classList.remove('show'); const urlElement = document.getElementById(`plugin-url-${index}`); if (urlElement) { const baseURL = urlElement.getAttribute('data-base-url'); if (baseURL) { urlElement.textContent = baseURL; } } } function copyResponse(index) { const responseBody = document.getElementById(`response-body-${index}`); if (!responseBody) return; const text = responseBody.textContent; navigator.clipboard.writeText(text).then(() => { Swal.fire({ title: "Copied!", text: "Response copied to clipboard", icon: "success", timer: 1500, showConfirmButton: false }); }).catch(() => { Swal.fire({ icon: "error", title: "Copy Failed", text: "Could not copy to clipboard" }); }); } async function loadAdminStats() { try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/stats', { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { const result = await response.json(); if (result.success) { const totalUsersEl = document.getElementById('adminTotalUsers'); const totalRequestsEl = document.getElementById('adminTotalRequests'); const todayRequestsEl = document.getElementById('adminTodayRequests'); if (totalUsersEl) totalUsersEl.textContent = formatNumber(result.stats.totalUsers || 0); if (totalRequestsEl) totalRequestsEl.textContent = formatNumber(result.stats.totalRequests || 0); if (todayRequestsEl) todayRequestsEl.textContent = formatNumber(result.stats.todayRequests || 0); } } } catch (error) { console.error('Error loading admin stats:', error); } } async function loadAdminUsers() { try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/admin/users', { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { const result = await response.json(); if (result.success) { adminUsers = result.users || []; currentPage = 0; renderAdminUsers(); } } } catch (error) { console.error('Error loading admin users:', error); const usersList = document.getElementById('adminUsersList'); if (usersList) { usersList.innerHTML = `

Failed to load users

`; } } } function renderAdminUsers() { const usersList = document.getElementById('adminUsersList'); if (!usersList) return; if (adminUsers.length === 0) { usersList.innerHTML = `

No users found

`; return; } const startIndex = currentPage * usersPerPage; const endIndex = startIndex + usersPerPage; const currentUsers = adminUsers.slice(startIndex, endIndex); const totalPages = Math.ceil(adminUsers.length / usersPerPage); usersList.innerHTML = `
Showing ${startIndex + 1}-${Math.min(endIndex, adminUsers.length)} of ${adminUsers.length} users
${currentUsers.map(user => `
${user.username || 'Unknown User'}
${user.email || 'No email'} ${user.role || 'user'} ${user.premium ? 'Premium' : ''}
Requests: ${user.requests || 0} Today: ${user.requestsToday || 0} Limit: ${user.limit || 30}
${user.tempBanned ? `
Banned until: ${new Date(user.tempBanUntil).toLocaleString()}
Reason: ${user.tempBanReason || 'No reason provided'}
` : ''}
${!user.tempBanned ? ` ` : ` `}
`).join('')} ${totalPages > 1 ? `
Page ${currentPage + 1} of ${totalPages}
` : ''} `; } function changePage(page) { const totalPages = Math.ceil(adminUsers.length / usersPerPage); if (page >= 0 && page < totalPages) { currentPage = page; renderAdminUsers(); } } function showTempBanModal(userId, username) { Swal.fire({ title: `Temporary Ban - ${username}`, html: `
`, showCancelButton: true, confirmButtonText: 'Apply Ban', confirmButtonColor: '#ff6b6b', preConfirm: () => { const banUntil = document.getElementById('banUntil').value; const reason = document.getElementById('banReason').value; if (!banUntil) { Swal.showValidationMessage('Please select ban until date/time'); return false; } return { banUntil, reason }; } }).then((result) => { if (result.isConfirmed) { applyTempBan(userId, result.value.banUntil, result.value.reason); } }); } async function applyTempBan(userId, banUntil, reason) { try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/admin/temp-ban', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ userId, banUntil, reason }) }); const result = await response.json(); if (result.success) { Swal.fire({ icon: 'success', title: 'User Banned', text: result.message }); loadAdminUsers(); } else { Swal.fire({ icon: 'error', title: 'Ban Failed', text: result.error }); } } catch (error) { Swal.fire({ icon: 'error', title: 'Network Error', text: 'Failed to apply ban' }); } } async function removeTempBan(userId, username) { const result = await Swal.fire({ title: `Remove Ban - ${username}`, text: 'Are you sure you want to remove the temporary ban?', icon: 'question', showCancelButton: true, confirmButtonText: 'Remove Ban', confirmButtonColor: '#28a745' }); if (result.isConfirmed) { try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/admin/remove-temp-ban', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ userId }) }); const apiResult = await response.json(); if (apiResult.success) { Swal.fire({ icon: 'success', title: 'Ban Removed', text: apiResult.message }); loadAdminUsers(); } else { Swal.fire({ icon: 'error', title: 'Failed', text: apiResult.error }); } } catch (error) { Swal.fire({ icon: 'error', title: 'Network Error', text: 'Failed to remove ban' }); } } } function showSection(sectionName) { document.querySelectorAll('.section').forEach(section => { section.classList.remove('active'); }); document.querySelectorAll('.menu-item').forEach(item => { item.classList.remove('active'); }); const targetSection = document.getElementById(sectionName); const targetMenuItem = document.querySelector(`[onclick="showSection('${sectionName}')"]`); if (targetSection) { targetSection.classList.add('active'); } if (targetMenuItem) { targetMenuItem.classList.add('active'); } if (window.serverStatsInterval) { clearInterval(window.serverStatsInterval); window.serverStatsInterval = null; } if (sectionName === 'plugins') { loadPlugins(); } else if (sectionName === 'overview') { loadUsageStats(); } else if (sectionName === 'api-stats') { loadApiStats(); }else if (sectionName === 'management' && currentUser && currentUser.role === 'admin') { loadAdminStats(); loadAdminUsers(); } else if (sectionName === 'server-stats') { loadServerStats(); window.serverStatsInterval = setInterval(() => { loadServerStats(); }, 5000); } } async function redeemCode() { const codeInput = document.getElementById('redeemCode'); if (!codeInput) { return; } const code = codeInput.value.trim().toUpperCase(); if (!code) { Swal.fire({ icon: "error", title: "Missing Code", text: "Please enter a redeem code" }); return; } try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/user/redeem', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ code }) }); const result = await response.json(); if (result.success) { Swal.fire({ title: "Code Redeemed Successfully!", text: "Your account has been updated", icon: "success" }); codeInput.value = ''; loadUserProfile(); } else { Swal.fire({ icon: "error", title: "Redeem Failed", text: result.error }); } } catch (error) { Swal.fire({ icon: "error", title: "Network Error", text: "Please try again later" }); } } async function updateProfile() { const usernameInput = document.getElementById('usernameInput'); if (!usernameInput) { return; } const username = usernameInput.value.trim(); if (!username) { Swal.fire({ icon: "error", title: "Missing Username", text: "Please enter a new username" }); return; } try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/user/profile', { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ username }) }); const result = await response.json(); if (result.success) { Swal.fire({ title: "Profile Updated!", text: "Your username has been updated successfully", icon: "success" }); usernameInput.value = ''; const user = JSON.parse(localStorage.getItem('dashx_user')); user.username = username; localStorage.setItem('dashx_user', JSON.stringify(user)); currentUser = user; loadUserProfile(); } else { Swal.fire({ icon: "error", title: "Update Failed", text: result.error }); } } catch (error) { Swal.fire({ icon: "error", title: "Network Error", text: "Please try again later" }); } } async function regenerateApiKey() { const result = await Swal.fire({ title: "Are you sure?", text: "This will generate a new API key and invalidate the current one!", icon: "warning", showCancelButton: true, confirmButtonColor: "#853030", cancelButtonColor: "#292727", confirmButtonText: "Yes, generate new key!", cancelButtonText: "Cancel" }); if (result.isConfirmed) { try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/user/regenerate-key', { method: 'POST', headers: { 'Authorization': `Bearer ${token}` } }); const apiResult = await response.json(); if (apiResult.success) { Swal.fire({ title: "Key Regenerated!", text: `New API Key: ${apiResult.apikey}`, icon: "success" }); const user = JSON.parse(localStorage.getItem('dashx_user')); user.apikey = apiResult.apikey; localStorage.setItem('dashx_user', JSON.stringify(user)); currentUser = user; loadUserProfile(); } else { Swal.fire({ title: "Failed!", text: apiResult.error, icon: "error" }); } } catch (error) { Swal.fire({ title: "Error!", text: "Network error occurred", icon: "error" }); } } } async function deleteAccount() { const result = await Swal.fire({ title: "Are you sure?", text: "You won't be able to revert this action!", icon: "warning", showCancelButton: true, confirmButtonColor: "#ff6b6b", cancelButtonColor: "#853030", confirmButtonText: "Yes, delete my account!", cancelButtonText: "Cancel" }); if (result.isConfirmed) { try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/user/account', { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }); const apiResult = await response.json(); if (apiResult.success) { await Swal.fire({ title: "Account Deleted!", text: "Your account has been permanently deleted.", icon: "success" }); logout(); } else { Swal.fire({ title: "Delete Failed!", text: apiResult.error, icon: "error" }); } } catch (error) { Swal.fire({ title: "Error!", text: "Network error occurred", icon: "error" }); } } } function updateRedeemFormVisibility() { const typeEl = document.getElementById('redeemType'); const limitContainer = document.getElementById('limitContainer'); const codeExpiredContainer = document.getElementById('codeExpiredContainer'); const premiumExpiredContainer = document.getElementById('premiumExpiredContainer'); const limitValueEl = document.getElementById('limitValue'); if (!typeEl) return; const type = typeEl.value; if (limitContainer) limitContainer.style.display = 'none'; if (codeExpiredContainer) codeExpiredContainer.style.display = 'none'; if (premiumExpiredContainer) premiumExpiredContainer.style.display = 'none'; if (type === 'premium') { if (limitContainer) { limitContainer.style.display = 'block'; const label = limitContainer.querySelector('label'); if (label) label.innerHTML = 'Limit Additional (Optional)'; if (limitValueEl) { limitValueEl.required = false; limitValueEl.placeholder = '0 or any value'; limitValueEl.min = '0'; } } if (codeExpiredContainer) codeExpiredContainer.style.display = 'block'; if (premiumExpiredContainer) premiumExpiredContainer.style.display = 'block'; } else if (type === 'limit') { if (limitContainer) { limitContainer.style.display = 'block'; const label = limitContainer.querySelector('label'); if (label) label.innerHTML = 'Limit *'; if (limitValueEl) { limitValueEl.required = true; limitValueEl.placeholder = 'Must be greater than 0'; limitValueEl.min = '1'; } } if (codeExpiredContainer) codeExpiredContainer.style.display = 'block'; } else if (type === 'both') { if (limitContainer) { limitContainer.style.display = 'block'; const label = limitContainer.querySelector('label'); if (label) label.innerHTML = 'Limit *'; if (limitValueEl) { limitValueEl.required = true; limitValueEl.placeholder = 'Must be greater than 0'; limitValueEl.min = '1'; } } if (codeExpiredContainer) codeExpiredContainer.style.display = 'block'; if (premiumExpiredContainer) premiumExpiredContainer.style.display = 'block'; } } async function createRedeemCode() { const typeEl = document.getElementById('redeemType'); const limitValueEl = document.getElementById('limitValue'); const codeExpiredEl = document.getElementById('codeExpired'); const premiumExpiredEl = document.getElementById('premiumExpired'); if (!typeEl || !codeExpiredEl) return; const type = typeEl.value; const codeExpired = codeExpiredEl.value; if (!type || !codeExpired) { Swal.fire({ icon: "error", title: "Invalid Input", text: "Please fill all required fields" }); return; } const codeExpiredDate = new Date(codeExpired); if (codeExpiredDate <= new Date()) { Swal.fire({ icon: "error", title: "Invalid Date", text: "Code expiration date must be in the future" }); return; } let limitValue = 0; let premiumExpired = null; if (type === 'premium') { if (!limitValueEl || !premiumExpiredEl) return; limitValue = parseInt(limitValueEl.value) || 0; premiumExpired = premiumExpiredEl.value; if (!premiumExpired) { Swal.fire({ icon: "error", title: "Missing Premium Expiry", text: "Premium expiration date is required for Premium Only type" }); return; } const premiumExpiredDate = new Date(premiumExpired); if (premiumExpiredDate <= new Date()) { Swal.fire({ icon: "error", title: "Invalid Date", text: "Premium expiration date must be in the future" }); return; } } else if (type === 'limit') { if (!limitValueEl) return; limitValue = parseInt(limitValueEl.value) || 0; if (limitValue <= 0) { Swal.fire({ icon: "error", title: "Invalid Limit", text: "Limit value must be greater than 0 for Limit Only type" }); return; } } else if (type === 'both') { if (!limitValueEl || !premiumExpiredEl) return; limitValue = parseInt(limitValueEl.value) || 0; premiumExpired = premiumExpiredEl.value; if (limitValue <= 0) { Swal.fire({ icon: "error", title: "Invalid Limit", text: "Limit value must be greater than 0 for Both type" }); return; } if (!premiumExpired) { Swal.fire({ icon: "error", title: "Missing Premium Expiry", text: "Premium expiration date is required for Both type" }); return; } const premiumExpiredDate = new Date(premiumExpired); if (premiumExpiredDate <= new Date()) { Swal.fire({ icon: "error", title: "Invalid Date", text: "Premium expiration date must be in the future" }); return; } } try { const token = localStorage.getItem('dashx_token'); const response = await fetch('/api/admin/redeem-code', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ type, limitValue, codeExpired, premiumExpired }) }); const result = await response.json(); if (result.success) { let benefitsHtml = `

Type: ${type}

`; if (limitValue > 0) { benefitsHtml += `

Limit Value: +${limitValue}

`; } benefitsHtml += `

Code Valid Until: ${new Date(codeExpired).toLocaleString()}

`; if (premiumExpired) { benefitsHtml += `

Premium Valid Until: ${new Date(premiumExpired).toLocaleString()}

`; } await Swal.fire({ title: "Redeem Code Created!", html: `
${result.code}
${benefitsHtml} `, icon: "success" }); if (limitValueEl) limitValueEl.value = ''; if (codeExpiredEl) codeExpiredEl.value = ''; if (premiumExpiredEl) premiumExpiredEl.value = ''; typeEl.selectedIndex = 0; updateRedeemFormVisibility(); } else { Swal.fire({ icon: "error", title: "Creation Failed", text: result.error }); } } catch (error) { Swal.fire({ icon: "error", title: "Network Error", text: "Please try again later" }); } } function logout() { localStorage.removeItem('dashx_token'); localStorage.removeItem('dashx_user'); currentUser = null; if (countdownInterval) { clearInterval(countdownInterval); } if (window.serverStatsInterval) { clearInterval(window.serverStatsInterval); } window.location.href = '/'; } function goToProfile() { window.location.href = '/profile'; } function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } function setupAutoSave() { const forms = document.querySelectorAll('form'); forms.forEach(form => { const inputs = form.querySelectorAll('input, select, textarea'); inputs.forEach(input => { input.addEventListener('input', debounce(() => { const formData = new FormData(form); const data = Object.fromEntries(formData); localStorage.setItem(`form_${form.id}`, JSON.stringify(data)); }, 1000)); }); }); } window.addEventListener('error', (event) => { console.error('Uncaught error:', event.error); }); window.addEventListener('online', () => { if (currentUser) { loadUserProfile(); loadUsageStats(); } }); window.addEventListener('offline', () => { Swal.fire({ icon: 'warning', title: 'Connection Lost', text: 'You are currently offline. Some features may not work.', toast: true, position: 'top-end', showConfirmButton: false, timer: 3000 }); }); window.addEventListener('beforeunload', () => { if (countdownInterval) { clearInterval(countdownInterval); } if (window.serverStatsInterval) { clearInterval(window.serverStatsInterval); } }); window.addEventListener('visibilitychange', () => { if (document.hidden) { if (window.serverStatsInterval) { clearInterval(window.serverStatsInterval); window.serverStatsInterval = null; } } else { const activeSection = document.querySelector('.section.active'); if (activeSection && activeSection.id === 'server-stats') { loadServerStats(); window.serverStatsInterval = setInterval(() => { loadServerStats(); }, 5000); } } }); if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js').catch(() => {}); }); } document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { document.querySelectorAll('.plugin-content.expanded').forEach(content => { content.classList.remove('expanded'); const index = content.id.replace('content-', ''); const expand = document.getElementById(`expand-${index}`); if (expand) expand.classList.remove('expanded'); }); document.querySelectorAll('.tag-content.expanded').forEach(content => { content.classList.remove('expanded'); const tagId = content.id.replace('content-', ''); const expand = document.getElementById(`expand-${tagId}`); if (expand) expand.classList.remove('expanded'); }); } }); let touchStartY = 0; let touchEndY = 0; document.addEventListener('touchstart', (e) => { touchStartY = e.changedTouches[0].screenY; }, false); document.addEventListener('touchend', (e) => { touchEndY = e.changedTouches[0].screenY; handleSwipe(); }, false); function handleSwipe() { const swipeThreshold = 100; const swipeDistance = touchStartY - touchEndY; if (Math.abs(swipeDistance) > swipeThreshold) { if (swipeDistance > 0) { console.log('Swiped up'); } else { console.log('Swiped down'); } } } const observerOptions = { root: null, rootMargin: '0px', threshold: 0.1 }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('fade-in'); } }); }, observerOptions); document.querySelectorAll('.stat-card, .admin-card, .plugin-card').forEach(card => { observer.observe(card); }); function validateEmail(email) { const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return re.test(email); } function validateUsername(username) { const re = /^[a-zA-Z0-9_-]{3,20}$/; return re.test(username); } function sanitizeInput(input) { const div = document.createElement('div'); div.textContent = input; return div.innerHTML; } function formatDate(date) { const options = { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }; return new Date(date).toLocaleDateString('en-US', options); } function formatBytes(bytes, decimals = 2) { if (bytes === 0) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } function getTimeAgo(timestamp) { const now = new Date(); const past = new Date(timestamp); const diffMs = now - past; const diffSecs = Math.floor(diffMs / 1000); const diffMins = Math.floor(diffSecs / 60); const diffHours = Math.floor(diffMins / 60); const diffDays = Math.floor(diffHours / 24); if (diffSecs < 60) return 'Just now'; if (diffMins < 60) return `${diffMins} minute${diffMins > 1 ? 's' : ''} ago`; if (diffHours < 24) return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`; if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`; return formatDate(timestamp); } function copyToClipboard(text) { return navigator.clipboard.writeText(text).then(() => { return true; }).catch(() => { const textArea = document.createElement('textarea'); textArea.value = text; textArea.style.position = 'fixed'; textArea.style.left = '-999999px'; document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { const successful = document.execCommand('copy'); document.body.removeChild(textArea); return successful; } catch (err) { document.body.removeChild(textArea); return false; } }); } function throttle(func, limit) { let inThrottle; return function() { const args = arguments; const context = this; if (!inThrottle) { func.apply(context, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } const scrollHandler = throttle(() => { const scrollTop = window.pageYOffset || document.documentElement.scrollTop; const navbar = document.querySelector('.navbar'); if (navbar) { if (scrollTop > 100) { navbar.style.boxShadow = '0 4px 30px rgba(0, 0, 0, 0.3)'; } else { navbar.style.boxShadow = '0 2px 20px rgba(0, 0, 0, 0.2)'; } } }, 100); window.addEventListener('scroll', scrollHandler); function showNotification(title, message, type = 'info') { const icon = type === 'success' ? 'success' : type === 'error' ? 'error' : type === 'warning' ? 'warning' : 'info'; Swal.fire({ toast: true, position: 'top-end', icon: icon, title: title, text: message, showConfirmButton: false, timer: 3000, timerProgressBar: true }); } function detectDeviceType() { const ua = navigator.userAgent; if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) { return 'tablet'; } if (/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(ua)) { return 'mobile'; } return 'desktop'; } const deviceType = detectDeviceType(); document.body.classList.add(`device-${deviceType}`); function preloadImages(urls) { urls.forEach(url => { const img = new Image(); img.src = url; }); } preloadImages([ 'https://files.catbox.moe/8l6hhm', 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/svgs/solid/key.svg', 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/svgs/solid/chart-pie.svg' ]); if ('Notification' in window && Notification.permission === 'default') { Notification.requestPermission(); } function sendBrowserNotification(title, body) { if ('Notification' in window && Notification.permission === 'granted') { new Notification(title, { body: body, icon: '/icon.webp', badge: '/icon.webp' }); } } const performanceObserver = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (entry.duration > 1000) { console.warn(`Slow operation detected: ${entry.name} took ${entry.duration}ms`); } } }); try { performanceObserver.observe({ entryTypes: ['measure', 'navigation'] }); } catch (e) { console.log('Performance observer not supported'); } function measurePerformance(name, fn) { performance.mark(`${name}-start`); const result = fn(); performance.mark(`${name}-end`); performance.measure(name, `${name}-start`, `${name}-end`); return result; } const isDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDarkMode) { document.body.classList.add('dark-mode'); } window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { if (e.matches) { document.body.classList.add('dark-mode'); } else { document.body.classList.remove('dark-mode'); } }); document.addEventListener('DOMContentLoaded', () => { const lazyImages = document.querySelectorAll('img[data-src]'); const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.removeAttribute('data-src'); observer.unobserve(img); } }); }); lazyImages.forEach(img => imageObserver.observe(img)); }); const networkStatus = { isOnline: navigator.onLine, lastCheck: Date.now() }; window.addEventListener('online', () => { networkStatus.isOnline = true; networkStatus.lastCheck = Date.now(); showNotification('Connection Restored', 'You are back online', 'success'); }); window.addEventListener('offline', () => { networkStatus.isOnline = false; networkStatus.lastCheck = Date.now(); showNotification('Connection Lost', 'You are currently offline', 'warning'); }); async function checkNetworkQuality() { if (!networkStatus.isOnline) return 'offline'; const startTime = Date.now(); try { await fetch('/api/stats', { method: 'HEAD' }); const latency = Date.now() - startTime; if (latency < 100) return 'excellent'; if (latency < 300) return 'good'; if (latency < 600) return 'fair'; return 'poor'; } catch { return 'offline'; } } function handleError(error, context = 'Unknown') { console.error(`Error in ${context}:`, error); if (error.message.includes('Failed to fetch')) { showNotification('Network Error', 'Unable to connect to server', 'error'); } else if (error.message.includes('401')) { showNotification('Session Expired', 'Please login again', 'warning'); setTimeout(() => logout(), 2000); } else { showNotification('Error', error.message || 'An unexpected error occurred', 'error'); } } window.addEventListener('unhandledrejection', (event) => { handleError(event.reason, 'Unhandled Promise Rejection'); }); const memoryMonitor = setInterval(() => { if (performance.memory) { const usedMemory = performance.memory.usedJSHeapSize; const totalMemory = performance.memory.totalJSHeapSize; const memoryPercentage = (usedMemory / totalMemory) * 100; if (memoryPercentage > 90) { console.warn('High memory usage detected:', memoryPercentage.toFixed(2) + '%'); } } }, 30000); function cleanupResources() { if (window.roleChartInstance) { window.roleChartInstance.destroy(); window.roleChartInstance = null; } if (countdownInterval) { clearInterval(countdownInterval); countdownInterval = null; } if (window.serverStatsInterval) { clearInterval(window.serverStatsInterval); window.serverStatsInterval = null; } } window.addEventListener('beforeunload', cleanupResources); console.log('%cšŸš€ DashX Dashboard Loaded', 'color: #853030; font-size: 20px; font-weight: bold;'); console.log('%cVersion: 1.0.0', 'color: #666; font-size: 12px;'); console.log('%cāš ļø Warning: Do not paste any code here unless you know what you are doing!', 'color: #ff6b6b; font-size: 14px; font-weight: bold;');