let currentAccount = ''; let refreshInterval; function showError(elementId, message) { const errorElement = document.getElementById(elementId); errorElement.textContent = message; errorElement.style.display = 'block'; errorElement.classList.add('message-fade'); setTimeout(() => { errorElement.style.display = 'none'; errorElement.classList.remove('message-fade'); }, 5000); } function showSuccess(elementId, message) { const successElement = document.getElementById(elementId); successElement.textContent = message; successElement.style.display = 'block'; successElement.classList.add('message-fade'); setTimeout(() => { successElement.style.display = 'none'; successElement.classList.remove('message-fade'); }, 5000); } // Check for existing login on page load window.addEventListener('load', () => { const accountId = document.cookie .split('; ') .find(row => row.startsWith('account_id=')) ?.split('=')[1]; if (accountId) { handleLogin(accountId); } setInterval(refreshPublicStats, 5000); }); async function refreshPublicStats() { const response = await fetch('/'); const text = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(text, 'text/html'); const statsScript = Array.from(doc.scripts) .find(script => script.textContent.includes('window.stats')); if (statsScript) { const statsMatch = statsScript.textContent.match(/window\.stats = (.*?);/); if (statsMatch) { window.stats = JSON.parse(statsMatch[1]); createCharts(); } } } async function register() { const response = await fetch('/register', { method: 'POST' }); const data = await response.json(); await handleLogin(data.account_id); } async function handleLogin(accountId) { currentAccount = accountId; document.getElementById('auth-section').style.display = 'none'; document.getElementById('url-section').style.display = 'block'; document.getElementById('current-account-display').textContent = accountId; loadAnalytics(); refreshInterval = setInterval(loadAnalytics, 5000); } async function login() { const accountId = document.getElementById('account-id').value; const response = await fetch('/login', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({account_id: accountId}) }); if (response.ok) { await handleLogin(accountId); } else { showError('auth-error', 'Invalid account ID'); } } async function logout() { clearInterval(refreshInterval); const response = await fetch('/logout', { method: 'POST' }); if (response.ok) { currentAccount = ''; document.getElementById('auth-section').style.display = 'block'; document.getElementById('url-section').style.display = 'none'; document.getElementById('account-id').value = ''; const resultDiv = document.getElementById('result'); resultDiv.innerHTML = ''; resultDiv.style.display = 'none'; } } function isValidUrl(url) { if (!url || !url.trim()) return false; try { const urlObj = new URL(url); return urlObj.protocol === 'http:' || urlObj.protocol === 'https:'; } catch { return false; } } async function createShortUrl() { const url = document.getElementById('url-input').value; const resultDiv = document.getElementById('result'); if (!isValidUrl(url)) { showError('url-error', 'Please enter a valid URL starting with http:// or https://'); return; } const response = await fetch('/create', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ account_id: currentAccount, url: url }) }); const data = await response.json(); if (response.ok) { const shortUrl = `${window.location.origin}${data.short_url}`; showSuccess('url-success', `URL shortened successfully!`); resultDiv.innerHTML = `

Short URL: ${shortUrl}

`; resultDiv.style.display = 'block'; document.getElementById('url-input').value = ''; loadAnalytics(); } else { showError('url-error', data.error); resultDiv.style.display = 'none'; } } let deleteCallback = null; function showDeleteDialog(shortId) { const dialog = document.getElementById('deleteDialog'); dialog.style.display = 'flex'; const confirmBtn = document.getElementById('confirmDelete'); deleteCallback = async () => { const response = await fetch(`/delete/${shortId}`, { method: 'DELETE' }); if (response.ok) { showSuccess('url-success', 'Link deleted successfully'); loadAnalytics(); } else { const data = await response.json(); showError('url-error', data.error || 'Failed to delete link'); } closeDeleteDialog(); }; confirmBtn.onclick = deleteCallback; } function closeDeleteDialog() { const dialog = document.getElementById('deleteDialog'); dialog.style.display = 'none'; deleteCallback = null; } async function loadAnalytics() { const response = await fetch(`/analytics/${currentAccount}`); const data = await response.json(); const openDetails = Array.from(document.querySelectorAll('details[open]')).map( detail => detail.getAttribute('data-visit-id') ); const analyticsDiv = document.getElementById('analytics'); analyticsDiv.innerHTML = '

Your Analytics

'; data.links.forEach(link => { const linkAnalytics = data.analytics.filter(a => a.link_id === link.short_id); const clicks = linkAnalytics.length; const shortUrl = `${window.location.origin}/l/${link.short_id}`; analyticsDiv.innerHTML += ` `; }); } function createCharts() { if (!window.stats?.chart_data) return; const chartConfigs = { 'ipChart': { data: window.stats.chart_data.ip_versions, title: 'IP Versions' }, 'osChart': { data: window.stats.chart_data.os_stats, title: 'Operating Systems' }, 'countryChart': { data: window.stats.chart_data.country_stats, title: 'Countries' }, 'ispChart': { data: window.stats.chart_data.isp_stats, title: 'ISPs' } }; Object.entries(chartConfigs).forEach(([chartId, config]) => { const ctx = document.getElementById(chartId); if (ctx) { new Chart(ctx, { type: 'pie', data: { labels: config.data.map(item => item._id || 'Unknown'), datasets: [{ data: config.data.map(item => item.count), backgroundColor: [ '#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40', '#4BC0C0', '#9966FF', '#C9CBCF', '#36A2EB' ] }] }, options: { responsive: true, plugins: { legend: { position: 'bottom', labels: { color: '#ffffff' } }, title: { display: true, text: config.title, color: '#ffffff' } } } }); } }); } // Add event listener to close dialog when clicking outside document.addEventListener('DOMContentLoaded', () => { const dialog = document.getElementById('deleteDialog'); dialog.addEventListener('click', (e) => { if (e.target === dialog) { closeDeleteDialog(); } }); });