PNG  IHDRxsBIT|d pHYs+tEXtSoftwarewww.inkscape.org<,tEXtComment File Manager

File Manager

Path: /home/u264723324/domains/cloproglobal.com/public_html/en/account/dash/

Viewing File: script.js

document.addEventListener('DOMContentLoaded', function () {

    // --- Helper: XSS Sanitization ---
    // Prevents malicious scripts stored in the database from executing in the browser
    function escapeHTML(str) {
        if (str === null || str === undefined) return '';
        return String(str).replace(/[&<>'"]/g, match => {
            const escape = { '&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#39;', '"': '&quot;' };
            return escape[match];
        });
    }

    // --- Helper: Get CSRF Token ---
    // Retrieves the CSRF token from the meta tag to secure POST requests
    function getCsrfToken() {
        const tokenElement = document.querySelector('meta[name="csrf-token"]');
        return tokenElement ? tokenElement.getAttribute('content') : '';
    }

    // --- Mobile Sidebar Logic (for all pages) ---
    const hamburger = document.getElementById('hamburger-menu');
    const sidebar = document.getElementById('sidebar');
    const closeMenuBtn = document.getElementById('close-menu-btn');

    if (hamburger && sidebar && closeMenuBtn) {
        hamburger.addEventListener('click', (event) => {
            event.stopPropagation();
            sidebar.classList.add('open');
        });
        closeMenuBtn.addEventListener('click', () => {
            sidebar.classList.remove('open');
        });
        document.addEventListener('click', (event) => {
            if (sidebar.classList.contains('open') && !sidebar.contains(event.target) && !hamburger.contains(event.target)) {
                sidebar.classList.remove('open');
            }
        });
    }

    // --- Accordion Logic (for specific pages) ---
    const accordionHeaders = document.querySelectorAll('.accordion-header');
    if (accordionHeaders.length > 0) {
        accordionHeaders.forEach(header => {
            header.addEventListener('click', () => {
                const accordionItem = header.parentElement;
                if (accordionItem) {
                    accordionItem.classList.toggle('active');
                }
            });
        });
    }

    // --- Balance Selector Dropdown Logic ---
    const balanceSelectorBtn = document.getElementById('balance-selector-btn');
    const balanceDropdown = document.getElementById('balance-dropdown-menu');

    if (balanceSelectorBtn && balanceDropdown) {
        balanceSelectorBtn.addEventListener('click', (event) => {
            event.stopPropagation();
            balanceDropdown.classList.toggle('open');
        });
        document.addEventListener('click', (event) => {
            if (
                balanceDropdown.classList.contains('open') &&
                !balanceDropdown.contains(event.target) &&
                !balanceSelectorBtn.contains(event.target)
            ) {
                balanceDropdown.classList.remove('open');
            }
        });
    }
    
    // --- Notifications Panel Logic ---
    const openNotificationsBtn = document.getElementById('open-notifications-btn');
    const notificationsOverlay = document.getElementById('notifications-overlay');
    const notificationsBackdrop = document.getElementById('notifications-backdrop');
    const closeNotificationsBtns = document.querySelectorAll('.js-close-notifications');

    if (openNotificationsBtn && notificationsOverlay && notificationsBackdrop && closeNotificationsBtns.length > 0) {
        const openPanel = () => notificationsOverlay.classList.add('open');
        const closePanel = () => notificationsOverlay.classList.remove('open');

        openNotificationsBtn.addEventListener('click', openPanel);
        closeNotificationsBtns.forEach(btn => btn.addEventListener('click', closePanel));
        notificationsBackdrop.addEventListener('click', closePanel);
    }
    
    // --- User Menu / Account Panel Logic ---
    const userMenuBtn = document.getElementById('user-menu-btn');
    const userAccountPanel = document.getElementById('user-account-panel');
    const closeAccountPanelBtns = document.querySelectorAll('.js-close-account-panel');

    if (userMenuBtn && userAccountPanel) {
        userMenuBtn.addEventListener('click', (event) => {
            event.stopPropagation();
            if (balanceDropdown && balanceDropdown.classList.contains('open')) {
                balanceDropdown.classList.remove('open');
            }
            if (document.getElementById('language-dropdown-menu')?.classList.contains('open')) {
                document.getElementById('language-dropdown-menu').classList.remove('open');
            }
            userAccountPanel.classList.toggle('open');
        });

        closeAccountPanelBtns.forEach(btn => {
            btn.addEventListener('click', () => {
                userAccountPanel.classList.remove('open');
            });
        });

        document.addEventListener('click', (event) => {
            if (
                userAccountPanel.classList.contains('open') &&
                !userAccountPanel.contains(event.target) &&
                !userMenuBtn.contains(event.target)
            ) {
                userAccountPanel.classList.remove('open');
            }
        });
    }

    // --- TradingView Widget ---
    if (document.getElementById('tradingview_f24de')) {
        new TradingView.widget({
            "autosize": true,
            "symbol": "CRYPTOCAP:BTC",
            "interval": "D",
            "timezone": "Etc/UTC",
            "theme": "dark",
            "style": "1",
            "locale": "en",
            "enable_publishing": false,
            "hide_top_toolbar": true,
            "withdateranges": true,
            "backgroundColor": "rgba(5, 8, 11, 1)",
            "gridColor": "rgba(255, 255, 255, 0.045)",
            "container_id": "tradingview_f24de"
        });
    }

    // --- Language Dropdown & GTranslate UI Logic ---
    const langSelectorBtn = document.getElementById('language-selector-btn');
    const langDropdownMenu = document.getElementById('language-dropdown-menu');
    const langSearchInput = document.getElementById('language-search-input');
    const langListItems = document.querySelectorAll('.language-list-item');

    if (langSelectorBtn && langDropdownMenu) {
        langSelectorBtn.addEventListener('click', (event) => {
            event.stopPropagation();
            langDropdownMenu.classList.toggle('open');
        });
        document.addEventListener('click', (event) => {
            if (langDropdownMenu.classList.contains('open') && !langDropdownMenu.contains(event.target) && !langSelectorBtn.contains(event.target)) {
                langDropdownMenu.classList.remove('open');
            }
        });
        if (langSearchInput) {
            langSearchInput.addEventListener('input', function() {
                const searchTerm = this.value.toLowerCase();
                langListItems.forEach(item => {
                    const languageName = item.textContent.toLowerCase();
                    if (languageName.includes(searchTerm)) {
                        item.style.display = 'block';
                    } else {
                        item.style.display = 'none';
                    }
                });
            });
        }
        if (langListItems.length > 0) {
            langListItems.forEach(item => {
                item.addEventListener('click', function() {
                    const currentActive = document.querySelector('.language-list-item.active');
                    if (currentActive) {
                        currentActive.classList.remove('active');
                    }
                    this.classList.add('active');
                    langDropdownMenu.classList.remove('open');
                });
            });
        }
    }
    
    // --- Move Money Hover Dropdown Logic ---
    const moveMoneyContainer = document.getElementById('move-money-container');
    const moveMoneyDropdown = document.getElementById('move-money-dropdown-menu');

    if (moveMoneyContainer && moveMoneyDropdown) {
        moveMoneyContainer.addEventListener('mouseenter', () => {
            moveMoneyDropdown.classList.add('open');
            moveMoneyContainer.classList.add('open');
        });
        moveMoneyContainer.addEventListener('mouseleave', () => {
            moveMoneyDropdown.classList.remove('open');
            moveMoneyContainer.classList.remove('open');
        });
    }

    // --- Overview Card View Toggle Logic ---
    const overviewCard = document.getElementById('overview-card');
    const assetsViewBtn = document.getElementById('toggle-assets-view-btn');
    const overviewViewBtn = document.getElementById('toggle-overview-view-btn');
    const assetsViewBtnDetails = document.getElementById('toggle-assets-view-btn-details');
    const overviewViewBtnDetails = document.getElementById('toggle-overview-view-btn-details');

    if (overviewCard && assetsViewBtn && overviewViewBtn && assetsViewBtnDetails && overviewViewBtnDetails) {
        const showAssetsView = () => overviewCard.classList.remove('show-details');
        const showDetailsView = () => overviewCard.classList.add('show-details');
        
        assetsViewBtn.addEventListener('click', showAssetsView);
        assetsViewBtnDetails.addEventListener('click', showAssetsView);
        
        overviewViewBtn.addEventListener('click', showDetailsView);
        overviewViewBtnDetails.addEventListener('click', showDetailsView);
    }
    
    // --- Fetch Live Asset Prices ---
    async function fetchAssetPrices() {
        const assetIds = ['bitcoin', 'ethereum', 'ripple', 'cardano'];
        const idsString = assetIds.join(',');
        const apiUrl = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=${idsString}`;
        
        const overviewAssetList = document.getElementById('overview-asset-list');
        const mobileAssetList = document.querySelector('.mobile-tab-content .asset-list');

        try {
            const response = await fetch(apiUrl);
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            const assets = await response.json();

            let assetsHtml = '';
            assets.forEach(asset => {
                const price = asset.current_price;
                const change = asset.price_change_percentage_24h;
                const changeClass = change >= 0 ? 'positive' : 'negative';
                const formattedPrice = price.toLocaleString('en-US', { style: 'currency', currency: 'USD' });

                // Sanitized injection
                assetsHtml += `
                    <div class="asset-item">
                        <a href="trade.php?asset=${escapeHTML(asset.symbol)}">
                            <div class="asset-icon">
                                <img src="${escapeHTML(asset.image)}" alt="${escapeHTML(asset.name)} logo">
                            </div>
                            <div class="asset-info">
                                <div class="asset-name">${escapeHTML(asset.name)}</div>
                                <div class="asset-symbol">${escapeHTML(asset.symbol)}</div>
                            </div>
                            <div class="asset-price">
                                <div class="asset-value">${escapeHTML(formattedPrice)}</div>
                                <div class="asset-change ${changeClass}">${change.toFixed(2)}%</div>
                            </div>
                        </a>
                    </div>
                `;
            });

            if (overviewAssetList) overviewAssetList.innerHTML = assetsHtml;
            if (mobileAssetList) mobileAssetList.innerHTML = assetsHtml;

        } catch (error) {
            console.error("Could not fetch asset prices:", error);
            if (overviewAssetList) overviewAssetList.innerHTML = '<p class="error-message">Could not load asset data.</p>';
            if (mobileAssetList) mobileAssetList.innerHTML = '<p class="error-message">Could not load asset data.</p>';
        }
    }

    fetchAssetPrices();

// --- ASSETS PAGE: Fetch and display all assets ---
const assetsTableContainer = document.getElementById('assets-table-container');

if (assetsTableContainer) {
    let allFetchedAssets = [];

    async function fetchAllAssets() {
        const apiUrl = 'https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=false';
        try {
            const response = await fetch(apiUrl);
            if (!response.ok) {
                throw new Error(`API error! status: ${response.status}`);
            }
            allFetchedAssets = await response.json();
            displayAssets(allFetchedAssets);
        } catch (error) {
            console.error("Could not fetch assets for the table:", error);
            assetsTableContainer.innerHTML = '<p style="text-align: center; padding: 20px;">Could not load asset data. Please try again later.</p>';
        }
    }

    function displayAssets(assetsToDisplay) {
        let tableHtml = '<div class="assets-table">';
        
        tableHtml += `
            <div class="table-header">
                <span>Asset</span>
                <span>Type</span>
                <span>Current price (USD)</span>
                <span>In your wallet</span>
                <span>Actions</span>
            </div>
        `;
        
        if (assetsToDisplay.length === 0) {
            assetsTableContainer.innerHTML = '<p style="text-align: center; padding: 20px;">No assets found.</p>';
            return;
        }

        assetsToDisplay.forEach(asset => {
            const price = asset.current_price;
            const formattedPrice = price ? price.toLocaleString('en-US', { style: 'currency', currency: 'USD' }) : 'N/A';
            const change24h = asset.price_change_percentage_24h || 0;
            const changeClass = change24h >= 0 ? 'positive' : 'negative';

            // Sanitized rendering
            tableHtml += `
                <div class="table-row">
                    <div>
                        <div class="asset-icon">
                            <img src="${escapeHTML(asset.image)}" alt="${escapeHTML(asset.name)} logo">
                        </div>
                        <div>
                            <div class="asset-name">${escapeHTML(asset.name)}</div>
                            <div class="asset-symbol">${escapeHTML(asset.symbol)}</div>
                        </div>
                    </div>
                    <div>Cryptocurrency</div>
                    <div class="asset-price">
                        <div>
                            <div class="asset-value">${escapeHTML(formattedPrice)}</div>
                            <div class="asset-change ${changeClass}">${change24h.toFixed(2)}%</div>
                        </div>
                    </div>
                    <div data-label="Wallet:">$0.00</div>
                    <div class="actions-cell">
                        <a href="#" class="btn-action-small">Deposit</a>
                        <a href="trade.php?asset=${escapeHTML(asset.symbol)}" class="btn-action-small">Trade</a>
                    </div>
                </div>
            `;
        });

        tableHtml += '</div>';
        assetsTableContainer.innerHTML = tableHtml;
    }
    
    const searchInput = document.getElementById('asset-search-input');
    if (searchInput) {
        searchInput.addEventListener('input', (e) => {
            const searchTerm = e.target.value.toLowerCase();
            const filteredAssets = allFetchedAssets.filter(asset => 
                asset.name.toLowerCase().includes(searchTerm) || 
                asset.symbol.toLowerCase().includes(searchTerm)
            );
            displayAssets(filteredAssets);
        });
    }

    fetchAllAssets();
}

// --- PAGE-SPECIFIC LOGIC (TRADING FORM) ---
const tradeForm = document.getElementById('trade-form');
const tradingViewContainerId = 'tradingview_f24de';

if (tradeForm && document.getElementById(tradingViewContainerId)) {
    
    const marketAssets = [
        // === CRYPTOCURRENCIES ===
        { group: 'Cryptocurrencies', name: 'Bitcoin / USD', value: 'BTCUSD', provider: 'BITSTAMP' },
        { group: 'Cryptocurrencies', name: 'Ethereum / USD', value: 'ETHUSD', provider: 'BITSTAMP' },
        { group: 'Cryptocurrencies', name: 'Solana / USD', value: 'SOLUSD', provider: 'COINBASE' },
        { group: 'Cryptocurrencies', name: 'Ripple / USD', value: 'XRPUSD', provider: 'BITSTAMP' },
        
        // === FOREX PAIRS ===
        { group: 'Forex Pairs', name: 'EUR / USD', value: 'EURUSD', provider: 'FX' },
        { group: 'Forex Pairs', name: 'GBP / USD', value: 'GBPUSD', provider: 'FX' },
        { group: 'Forex Pairs', name: 'USD / JPY', value: 'USDJPY', provider: 'FX' },
        
        // === INDICES & STOCKS ===
        { group: 'Indices & Stocks', name: 'S&P 500', value: 'SPX500', provider: 'TVC' },
        { group: 'Indices & Stocks', name: 'NASDAQ 100', value: 'NSX100', provider: 'TVC' },
        { group: 'Indices & Stocks', name: 'Apple Inc.', value: 'AAPL', provider: 'NASDAQ' },
        
        // === METALS ===
        { group: 'Metals', name: 'Gold', value: 'XAUUSD', provider: 'OANDA' },
        { group: 'Metals', name: 'Silver', value: 'XAGUSD', provider: 'OANDA' },
        
        // === COMMODITIES ===
        { group: 'Commodities', name: 'Crude Oil (WTI)', value: 'WTI', provider: 'TVC' },
        { group: 'Commodities', name: 'Natural Gas', value: 'NATURALGAS', provider: 'TVC' }
    ];

    const marketSelect = document.getElementById('market-select');
    const formInputs = tradeForm.querySelectorAll('input[required], select[required]');
    const submitButton = document.getElementById('trade-submit-btn');
    
    function createOrUpdateWidget(symbol, provider) {
        const widgetContainer = document.getElementById(tradingViewContainerId);
        if (!widgetContainer) return;
        
        widgetContainer.innerHTML = ''; 
        
        new TradingView.widget({
            "autosize": true,
            "symbol": `${provider}:${symbol}`,
            "interval": "D",
            "timezone": "Etc/UTC",
            "theme": "dark",
            "style": "1",
            "locale": "en",
            "enable_publishing": false,
            "hide_top_toolbar": true,
            "withdateranges": true,
            "backgroundColor": "rgba(5, 8, 11, 1)",
            "gridColor": "rgba(255, 255, 255, 0.045)",
            "container_id": tradingViewContainerId
        });
    }

    const groupedAssets = marketAssets.reduce((acc, asset) => {
        (acc[asset.group] = acc[asset.group] || []).push(asset);
        return acc;
    }, {});

    for (const groupName in groupedAssets) {
        const optgroup = document.createElement('optgroup');
        optgroup.label = groupName;
        groupedAssets[groupName].forEach(asset => {
            const option = document.createElement('option');
            option.value = `${asset.provider}:${asset.value}`;
            option.textContent = asset.name;
            optgroup.appendChild(option);
        });
        marketSelect.appendChild(optgroup);
    }
    
    marketSelect.addEventListener('change', (event) => {
        const [provider, symbol] = event.target.value.split(':');
        createOrUpdateWidget(symbol, provider);
    });

    function checkFormValidity() {
        let allValid = true;
        formInputs.forEach(input => {
            if (!input.value) {
                allValid = false;
            }
        });
        
        if (allValid) {
            submitButton.removeAttribute('disabled');
        } else {
            submitButton.setAttribute('disabled', 'true');
        }
    }

    formInputs.forEach(input => {
        input.addEventListener('input', checkFormValidity);
        input.addEventListener('change', checkFormValidity);
    });

    tradeForm.addEventListener('submit', (e) => {
        e.preventDefault(); 

        const submitButton = document.getElementById('trade-submit-btn');
        const submitText = submitButton.querySelector('.submit-text');
        
        submitButton.setAttribute('disabled', 'true');
        submitButton.classList.add('loading');
        submitText.textContent = 'Placing...';

        const formData = new FormData(tradeForm);
        formData.append('csrf_token', getCsrfToken()); // Added CSRF Protection

        fetch('process_trade.php', {
            method: 'POST',
            body: formData
        })
        .then(response => response.json())
        .then(data => {
            if (data.status === 'success') {
                Swal.fire({
                    icon: 'success',
                    title: 'Success!',
                    text: data.message,
                    confirmButtonColor: '#4CAF50'
                });
                tradeForm.reset();      
                checkFormValidity();
                
                const balanceElement = document.getElementById('user-balance-display');
                if (balanceElement && typeof data.new_balance !== 'undefined') {
                    const formattedBalance = parseFloat(data.new_balance).toLocaleString('en-US', {
                        minimumFractionDigits: 2,
                        maximumFractionDigits: 2
                    });
                    balanceElement.textContent = formattedBalance;
                }
                loadUserTrades();
            } else {
                Swal.fire({
                    icon: 'error',
                    title: 'Oops...',
                    text: escapeHTML(data.message), // Sanitized response message
                    confirmButtonColor: '#f44336'
                });
            }
        })
        .catch(error => {
            console.error('Error:', error);
            Swal.fire({
                icon: 'error',
                title: 'Connection Error',
                text: 'An error occurred while connecting to the server. Please try again.'
            });
        })
        .finally(() => {
            submitButton.classList.remove('loading');
            submitText.textContent = 'Place Trade';
            checkFormValidity(); 
        });
    });

    if (marketAssets.length > 0) {
        const firstAsset = marketAssets[0];
        createOrUpdateWidget(firstAsset.value, firstAsset.provider);
    }
}

}); // End DOMContentLoaded

document.addEventListener('DOMContentLoaded', () => {
    loadUserTrades(); 
});

// Adjusted Polling: Increased to 15 seconds AND checks if tab is visible to prevent server overload
setInterval(() => {
    if (navigator.onLine && document.visibilityState === 'visible') {
        loadUserTrades(); 
    }
}, 15000); 

async function loadUserTrades() {
    const openTradesBody = document.getElementById('open-trades-body');
    const closedTradesBody = document.getElementById('closed-trades-body');
    const openTradesCount = document.getElementById('open-trades-count');
    const closedTradesCount = document.getElementById('closed-trades-count');

    try {
        const response = await fetch('fetch_trades.php');
        const data = await response.json();

        if (data.status !== 'success') {
            console.error('Error loading trades:', data.message);
            openTradesBody.innerHTML = '<div class="no-trades-message">Error loading trades.</div>';
            return;
        }

        if (typeof data.current_balance !== 'undefined') {
            const formattedBalance = parseFloat(data.current_balance).toLocaleString('en-US', {
                minimumFractionDigits: 2,
                maximumFractionDigits: 2
            });

            const headerBalance = document.getElementById('user-balance-display');
            const mainBalance = document.getElementById('main-balance-display');
            const mobileBalance = document.getElementById('mobile-balance-display');
            const detailsBalance = document.getElementById('details-balance-display');

            if (headerBalance) headerBalance.textContent = formattedBalance;
            if (mainBalance) mainBalance.textContent = formattedBalance;
            if (mobileBalance) mobileBalance.textContent = formattedBalance;
            if (detailsBalance) detailsBalance.textContent = formattedBalance;
        }

        openTradesBody.innerHTML = ''; 
        openTradesCount.textContent = `(${escapeHTML(data.open_trades.length)})`;

        if (data.open_trades.length === 0) {
            openTradesBody.innerHTML = '<div class="no-trades-message">You have no open trades.</div>';
        } else {
            data.open_trades.forEach(trade => {
                const tradeRowHtml = createTradeRow(trade, true);
                openTradesBody.innerHTML += tradeRowHtml;
            });
        }

        closedTradesBody.innerHTML = ''; 
        closedTradesCount.textContent = `(${escapeHTML(data.closed_trades.length)})`;

        if (data.closed_trades.length === 0) {
            closedTradesBody.innerHTML = '<div class="no-trades-message">You have no closed trades.</div>';
        } else {
            data.closed_trades.forEach(trade => {
                const tradeRowHtml = createTradeRow(trade, false); 
                closedTradesBody.innerHTML += tradeRowHtml;
            });
        }
        
        startPnlAnimation();

    } catch (error) {
        console.error('Failed to fetch trades:', error);
        openTradesBody.innerHTML = '<div class="no-trades-message">Could not connect to the server.</div>';
    }
}

// XSS Mitigation included in string generation
function createTradeRow(trade, isOpen) {
    const tradeDate = escapeHTML(new Date(trade.created_at).toLocaleDateString());
    const tradeAmount = parseFloat(trade.trade_amount); 
    
    if (isNaN(tradeAmount)) {
        console.error('Invalid trade_amount received from server:', trade.trade_amount, 'for trade ID:', trade.id);
        return `<div class="trades-table-row error-row"><div data-label="Error">Error: Invalid data.</div></div>`;
    }
    
    const directionClass = trade.trade_type === 'BUY' ? 'positive' : 'negative';

    let pnlHtml;
    let actionHtml; 

    if (isOpen) {
        // OPEN trades
        pnlHtml = `<span class="pnl-animating" data-trade-id="${escapeHTML(trade.id)}" data-trade-amount="${tradeAmount.toFixed(2)}">0.00</span>`;
        actionHtml = `<button class="btn-close-trade" data-trade-id="${escapeHTML(trade.id)}">Close</button>`;
    } else {
        // CLOSED trades
        const finalPnl = parseFloat(trade.pnl || 0).toFixed(4);
        const pnlClass = finalPnl > 0 ? 'positive' : (finalPnl < 0 ? 'negative' : 'neutral');
        pnlHtml = `<span class="${pnlClass}">${escapeHTML(finalPnl)}</span>`;
        actionHtml = `<span>${escapeHTML(trade.status)}</span>`;
    }

    return `
        <div class="trades-table-row">
            <div data-label="Date">${tradeDate}</div>
            <div data-label="Trade">${escapeHTML(trade.commodity)}</div>
            <div data-label="Direction" class="${directionClass}">${escapeHTML(trade.trade_type)}</div>
            <div data-label="Amount">${tradeAmount.toFixed(2)}</div>
            <div data-label="Profit" class="pnl-value">${pnlHtml}</div>
            <div data-label="Action">${actionHtml}</div>
        </div>
    `;
}

function startPnlAnimation() {
    const pnlElements = document.querySelectorAll('.pnl-animating');
    // Ensure userSignalStrength is defined, fallback to 50 if missing globally
    const signalStrengthValue = typeof userSignalStrength !== 'undefined' ? parseFloat(userSignalStrength) : 50;
    
    pnlElements.forEach(el => {
        const maxLoss = parseFloat(el.dataset.tradeAmount);
        
        if (isNaN(maxLoss)) {
            el.textContent = "Error";
            console.error("Stopping animation because maxLoss is NaN.", el);
            return;
        }

        let currentPnl = 0.00;

        const updatePnl = () => {
            const maxVolatilityPercentage = 0.20; 
            const signalMultiplier = signalStrengthValue / 100;
            const maxTickChange = maxLoss * maxVolatilityPercentage * signalMultiplier;
            
            // Visual math only!
            const change = (Math.random() - 0.5) * 2 * maxTickChange;
            currentPnl += change;

            if (currentPnl < -maxLoss) {
                currentPnl = -maxLoss;
            }

            el.textContent = currentPnl.toFixed(2);
            
            const parentContainer = el.parentElement;
            if (currentPnl >= 0) {
                parentContainer.className = 'pnl-value positive';
            } else {
                parentContainer.className = 'pnl-value negative';
            }

            if (!navigator.onLine) {
                return; 
            }

            const randomDelay = Math.random() * (2500 - 400) + 400; 
            setTimeout(updatePnl, randomDelay);
        };
        
        updatePnl();
    });
}

document.addEventListener('click', function(e) {
    if (e.target.classList.contains('btn-close-trade')) {
        const button = e.target;
        const tradeId = button.dataset.tradeId;

        // CRITICAL FIX: The user should only confirm intent. Server calculates actual price.
        Swal.fire({
            title: 'Close Trade?',
            text: `You are about to close this trade at the current live market price. The server will calculate your final Profit/Loss.`,
            icon: 'warning',
            showCancelButton: true,
            confirmButtonColor: '#3085d6',
            cancelButtonColor: '#d33',
            confirmButtonText: 'Yes, close it!'
        }).then((result) => {
            if (result.isConfirmed) {
                closeTrade(tradeId); // Note: finalPnl has been removed!
            }
        });
    }
});

// CRITICAL FIX: Only send Trade ID. Removed forged Client PNL from payload.
async function closeTrade(tradeId) {
    const formData = new FormData();
    formData.append('trade_id', tradeId);
    
    // Add CSRF token for security
    const csrfToken = document.querySelector('meta[name="csrf-token"]');
    if (csrfToken) {
        formData.append('csrf_token', csrfToken.getAttribute('content'));
    }

    try {
        const response = await fetch('close_trade.php', {
            method: 'POST',
            body: formData
        });
        const data = await response.json();

        if (data.status === 'success') {
            Swal.fire('Closed!', data.message, 'success');
            loadUserTrades(); 
        } else {
            Swal.fire('Error!', escapeHTML(data.message), 'error');
        }
    } catch (error) {
        Swal.fire('Connection Error', 'Could not connect to the server.', 'error');
    }
}

window.addEventListener('offline', () => {
    console.log('Network connection lost. PNL animations paused.');
    Swal.fire({
        toast: true,
        position: 'top-end',
        icon: 'warning',
        title: 'Connection lost. Live data is paused.',
        showConfirmButton: false,
        timer: 5000 
    });
});

window.addEventListener('online', () => {
    console.log('Network connection restored. Resuming live data...');
    Swal.fire({
        toast: true,
        position: 'top-end',
        icon: 'success',
        title: 'Connection restored. Resuming live data...',
        showConfirmButton: false,
        timer: 3000 
    });
    
    loadUserTrades();
});
b IDATxytVսϓ22 A@IR :hCiZ[v*E:WũZA ^dQeQ @ !jZ'>gsV仿$|?g)&x-EIENT ;@xT.i%-X}SvS5.r/UHz^_$-W"w)Ɗ/@Z &IoX P$K}JzX:;` &, ŋui,e6mX ԵrKb1ԗ)DADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADA݀!I*]R;I2$eZ#ORZSrr6mteffu*((Pu'v{DIߔ4^pIm'77WEEE;vƎ4-$]'RI{\I&G :IHJ DWBB=\WR޽m o$K(V9ABB.}jѢv`^?IOȅ} ڶmG}T#FJ`56$-ھ}FI&v;0(h;Б38CӧOWf!;A i:F_m9s&|q%=#wZprrrla A &P\\СC[A#! {olF} `E2}MK/vV)i{4BffV\|ۭX`b@kɶ@%i$K z5zhmX[IXZ` 'b%$r5M4º/l ԃߖxhʔ)[@=} K6IM}^5k㏷݆z ΗÿO:gdGBmyT/@+Vɶ纽z񕏵l.y޴it뭷zV0[Y^>Wsqs}\/@$(T7f.InݺiR$푔n.~?H))\ZRW'Mo~v Ov6oԃxz! S,&xm/yɞԟ?'uaSѽb,8GלKboi&3t7Y,)JJ c[nzӳdE&KsZLӄ I?@&%ӟ۶mSMMњ0iؐSZ,|J+N ~,0A0!5%Q-YQQa3}$_vVrf9f?S8`zDADADADADADADADADAdqP,تmMmg1V?rSI꒟]u|l RCyEf٢9 jURbztѰ!m5~tGj2DhG*{H9)꒟ר3:(+3\?/;TUݭʴ~S6lڧUJ*i$d(#=Yݺd{,p|3B))q:vN0Y.jkק6;SɶVzHJJЀ-utѹսk>QUU\޲~]fFnK?&ߡ5b=z9)^|u_k-[y%ZNU6 7Mi:]ۦtk[n X(e6Bb."8cۭ|~teuuw|ήI-5"~Uk;ZicEmN/:]M> cQ^uiƞ??Ңpc#TUU3UakNwA`:Y_V-8.KKfRitv޲* 9S6ֿj,ՃNOMߤ]z^fOh|<>@Å5 _/Iu?{SY4hK/2]4%it5q]GGe2%iR| W&f*^]??vq[LgE_3f}Fxu~}qd-ږFxu~I N>\;͗O֊:̗WJ@BhW=y|GgwܷH_NY?)Tdi'?խwhlmQi !SUUsw4kӺe4rfxu-[nHtMFj}H_u~w>)oV}(T'ebʒv3_[+vn@Ȭ\S}ot}w=kHFnxg S 0eޢm~l}uqZfFoZuuEg `zt~? b;t%>WTkķh[2eG8LIWx,^\thrl^Ϊ{=dž<}qV@ ⠨Wy^LF_>0UkDuʫuCs$)Iv:IK;6ֲ4{^6եm+l3>݆uM 9u?>Zc }g~qhKwڭeFMM~pМuqǿz6Tb@8@Y|jx](^]gf}M"tG -w.@vOqh~/HII`S[l.6nØXL9vUcOoB\xoǤ'T&IǍQw_wpv[kmO{w~>#=P1Pɞa-we:iǏlHo׈꒟f9SzH?+shk%Fs:qVhqY`jvO'ρ?PyX3lх]˾uV{ݞ]1,MzYNW~̈́ joYn}ȚF߾׮mS]F z+EDxm/d{F{-W-4wY듏:??_gPf ^3ecg ҵs8R2מz@TANGj)}CNi/R~}c:5{!ZHӋӾ6}T]G]7W6^n 9*,YqOZj:P?Q DFL|?-^.Ɵ7}fFh׶xe2Pscz1&5\cn[=Vn[ĶE鎀uˌd3GII k;lNmشOuuRVfBE]ۣeӶu :X-[(er4~LHi6:Ѻ@ԅrST0trk%$Č0ez" *z"T/X9|8.C5Feg}CQ%͞ˣJvL/?j^h&9xF`њZ(&yF&Iݻfg#W;3^{Wo^4'vV[[K';+mӍִ]AC@W?1^{එyh +^]fm~iԵ]AB@WTk̏t uR?l.OIHiYyԶ]Aˀ7c:q}ힽaf6Z~қm(+sK4{^6}T*UUu]n.:kx{:2 _m=sAߤU@?Z-Vކеz왍Nэ{|5 pڶn b p-@sPg]0G7fy-M{GCF'%{4`=$-Ge\ eU:m+Zt'WjO!OAF@ik&t݆ϥ_ e}=]"Wz_.͜E3leWFih|t-wZۍ-uw=6YN{6|} |*={Ѽn.S.z1zjۻTH]흾 DuDvmvK.`V]yY~sI@t?/ϓ. m&["+P?MzovVЫG3-GRR[(!!\_,^%?v@ҵő m`Y)tem8GMx.))A]Y i`ViW`?^~!S#^+ѽGZj?Vģ0.))A꨷lzL*]OXrY`DBBLOj{-MH'ii-ϰ ok7^ )쭡b]UXSְmռY|5*cֽk0B7镹%ڽP#8nȎq}mJr23_>lE5$iwui+ H~F`IjƵ@q \ @#qG0".0" l`„.0! ,AQHN6qzkKJ#o;`Xv2>,tێJJ7Z/*A .@fفjMzkg @TvZH3Zxu6Ra'%O?/dQ5xYkU]Rֽkق@DaS^RSּ5|BeHNN͘p HvcYcC5:y #`οb;z2.!kr}gUWkyZn=f Pvsn3p~;4p˚=ē~NmI] ¾ 0lH[_L hsh_ғߤc_њec)g7VIZ5yrgk̞W#IjӪv>՞y睝M8[|]\շ8M6%|@PZڨI-m>=k='aiRo-x?>Q.}`Ȏ:Wsmu u > .@,&;+!!˱tﭧDQwRW\vF\~Q7>spYw$%A~;~}6¾ g&if_=j,v+UL1(tWake:@Ș>j$Gq2t7S?vL|]u/ .(0E6Mk6hiۺzښOrifޱxm/Gx> Lal%%~{lBsR4*}{0Z/tNIɚpV^#Lf:u@k#RSu =S^ZyuR/.@n&΃z~B=0eg뺆#,Þ[B/?H uUf7y Wy}Bwegל`Wh(||`l`.;Ws?V@"c:iɍL֯PGv6zctM̠':wuW;d=;EveD}9J@B(0iհ bvP1{\P&G7D޴Iy_$-Qjm~Yrr&]CDv%bh|Yzni_ˆR;kg}nJOIIwyuL}{ЌNj}:+3Y?:WJ/N+Rzd=hb;dj͒suݔ@NKMԄ jqzC5@y°hL m;*5ezᕏ=ep XL n?מ:r`۵tŤZ|1v`V뽧_csج'ߤ%oTuumk%%%h)uy]Nk[n 'b2 l.=͜E%gf$[c;s:V-͞WߤWh-j7]4=F-X]>ZLSi[Y*We;Zan(ӇW|e(HNNP5[= r4tP &0<pc#`vTNV GFqvTi*Tyam$ߏWyE*VJKMTfFw>'$-ؽ.Ho.8c"@DADADADADADADADADA~j*֘,N;Pi3599h=goضLgiJ5փy~}&Zd9p֚ e:|hL``b/d9p? fgg+%%hMgXosج, ΩOl0Zh=xdjLmhݻoO[g_l,8a]٭+ӧ0$I]c]:粹:Teꢢ"5a^Kgh,&= =՟^߶“ߢE ܹS J}I%:8 IDAT~,9/ʃPW'Mo}zNƍ쨓zPbNZ~^z=4mswg;5 Y~SVMRXUյڱRf?s:w ;6H:ºi5-maM&O3;1IKeamZh͛7+##v+c ~u~ca]GnF'ټL~PPPbn voC4R,ӟgg %hq}@#M4IÇ Oy^xMZx ) yOw@HkN˖-Sǎmb]X@n+i͖!++K3gd\$mt$^YfJ\8PRF)77Wא!Cl$i:@@_oG I{$# 8磌ŋ91A (Im7֭>}ߴJq7ޗt^ -[ԩSj*}%]&' -ɓ'ꫯVzzvB#;a 7@GxI{j޼ƌ.LÇWBB7`O"I$/@R @eee@۷>}0,ɒ2$53Xs|cS~rpTYYY} kHc %&k.], @ADADADADADADADADA@lT<%''*Lo^={رc5h %$+CnܸQ3fҥK}vUVVs9G R,_{xˇ3o߾;TTTd}馛]uuuG~iԩ@4bnvmvfϞ /Peeeq}}za I~,誫{UWW뮻}_~YƍSMMMYχ֝waw\ďcxꩧtEƍկ_?۷5@u?1kNׯWzz/wy>}zj3 k(ٺuq_Zvf̘:~ ABQ&r|!%KҥKgԞ={<_X-z !CyFUUz~ ABQIIIjݺW$UXXDٳZ~ ABQƍecW$<(~<RSSvZujjjԧOZQu@4 8m&&&jԩg$ď1h ͟?_{768@g =@`)))5o6m3)ѣƌJ;wҿUTT /KZR{~a=@0o<*狔iFɶ[ˎ;T]]OX@?K.ۈxN pppppppppppppppppPfl߾] ,{ァk۶mڿo5BTӦMӴiӴ|r DB2e|An!Dy'tkΝ[A $***t5' "!駟oaDnΝ:t֭[gDШQ06qD;@ x M6v(PiizmZ4ew"@̴ixf [~-Fٱc&IZ2|n!?$@{[HTɏ#@hȎI# _m(F /6Z3z'\r,r!;w2Z3j=~GY7"I$iI.p_"?pN`y DD?: _  Gÿab7J !Bx@0 Bo cG@`1C[@0G @`0C_u V1 aCX>W ` | `!<S `"<. `#c`?cAC4 ?c p#~@0?:08&_MQ1J h#?/`7;I  q 7a wQ A 1 Hp !#<8/#@1Ul7=S=K.4Z?E_$i@!1!E4?`P_  @Bă10#: "aU,xbFY1 [n|n #'vEH:`xb #vD4Y hi.i&EΖv#O H4IŶ}:Ikh @tZRF#(tXҙzZ ?I3l7q@õ|ۍ1,GpuY Ꮿ@hJv#xxk$ v#9 5 }_$c S#=+"K{F*m7`#%H:NRSp6I?sIՖ{Ap$I$I:QRv2$Z @UJ*$]<FO4IENDB`