// management/static/js/main.js // -*- coding: utf-8 -*- // VAPID_PUBLIC_KEY will be passed from the Django template. // This is a placeholder; it will be filled with the correct value in the HTML file. const VAPID_PUBLIC_KEY_PLACEHOLDER = "{{ vapid_public_key }}"; /** * Converts a base64 string to a Uint8Array. * @param {string} base64String * @returns {Uint8Array} */ function urlBase64ToUint8Array(base64String) { const padding = '='.repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding) .replace(/\-/g, '+') .replace(/_/g, '/'); const rawData = window.atob(base64); const outputArray = new Uint8Array(rawData.length); for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; } /** * Registers the service worker for the PWA. * @returns {Promise} */ async function registerServiceWorker() { if ('serviceWorker' in navigator) { try { const registration = await navigator.serviceWorker.register('/service-worker.js'); console.log('Service worker registered successfully.'); return registration; } catch (error) { console.error('Service worker registration failed:', error); return null; } } console.error('Service workers are not supported in this browser.'); return null; } /** * Subscribes the user to push notifications. * @param {ServiceWorkerRegistration} registration */ async function subscribeUserToPush(registration) { if (!('PushManager' in window)) { console.error('Push notifications are not supported.'); return; } if (!VAPID_PUBLIC_KEY_PLACEHOLDER || VAPID_PUBLIC_KEY_PLACEHOLDER === "YOUR_VAPID_PUBLIC_KEY_HERE") { console.error("VAPID public key not configured."); return; } try { const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY_PLACEHOLDER) }); console.log('User is subscribed to push.'); const response = await fetch('/api/push/subscribe/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value }, body: JSON.stringify(subscription) }); if (!response.ok) { console.error('Failed to save push subscription on server.'); } } catch (error) { console.error('Push subscription failed:', error); } } /** * Fetches and displays user dashboard data from the API. */ async function fetchDashboardData() { try { const response = await fetch('/api/dashboard/'); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); document.getElementById('username-display').textContent = data.username; document.getElementById('service-status').textContent = data.service_status; document.getElementById('used-traffic').textContent = (data.used_traffic / (1024 ** 3)).toFixed(2) + ' GB'; document.getElementById('total-traffic').textContent = (data.total_traffic / (1024 ** 3)).toFixed(2) + ' GB'; const configsList = document.getElementById('configs-list'); configsList.innerHTML = ''; // Clear previous content data.configs.forEach(config => { const listItem = document.createElement('li'); listItem.className = 'bg-gray-50 rounded-md p-3 border border-gray-200'; listItem.innerHTML = `
${config.remark}
${config.link}
`; configsList.appendChild(listItem); }); } catch (error) { console.error('Error fetching dashboard data:', error); document.body.innerHTML = '

خطا در بارگذاری اطلاعات داشبورد.

'; } } /** * Handles the generation of the Telegram security token. */ async function handleTelegramTokenGeneration() { const generateTokenBtn = document.getElementById('generate-token-btn'); const tokenDisplayArea = document.getElementById('token-display-area'); const telegramTokenCode = document.getElementById('telegram-token'); if (!generateTokenBtn) return; generateTokenBtn.addEventListener('click', async () => { const response = await fetch('/api/telegram/generate-token/', { method: 'POST', headers: { 'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value } }); if (response.ok) { const data = await response.json(); telegramTokenCode.textContent = data.token; tokenDisplayArea.classList.remove('hidden'); } else { // Using a custom modal or message box instead of alert() console.error('Failed to generate token.'); alert('خطا در تولید توکن.'); } }); } document.addEventListener('DOMContentLoaded', async () => { // Fetch and render dashboard data await fetchDashboardData(); // PWA and Push Notification logic const registration = await registerServiceWorker(); if (registration) { if (Notification.permission === 'granted') { console.log('Push permission already granted.'); } else if (Notification.permission === 'denied') { console.log('Push permission denied by user.'); } else { // Prompt the user for permission // This is a browser feature, so we don't need a custom modal Notification.requestPermission().then(permission => { if (permission === 'granted') { subscribeUserToPush(registration); } else { console.log('User denied push notification permission.'); } }); } } // Telegram token generation handleTelegramTokenGeneration(); });