/** * Options Page Logic */ // Tab switching const tabBtns = document.querySelectorAll('.tab-btn'); const tabContents = document.querySelectorAll('.tab-content'); tabBtns.forEach(btn => { btn.addEventListener('click', () => { const targetTab = btn.dataset.tab; // Remove active class from all tabBtns.forEach(b => b.classList.remove('active')); tabContents.forEach(c => c.classList.remove('active')); // Add active class to clicked btn.classList.add('active'); document.getElementById(`tab-${targetTab}`).classList.add('active'); }); }); // Initialize on load document.addEventListener('DOMContentLoaded', async () => { await loadAllSettings(); await loadStats(); await loadDataPreview(); // Set up event listeners document.getElementById('save-api-keys').addEventListener('click', saveAPIKeys); document.getElementById('save-module-config').addEventListener('click', saveModuleConfig); document.getElementById('export-json').addEventListener('click', exportJSON); document.getElementById('export-csv').addEventListener('click', exportCSV); document.getElementById('clear-data').addEventListener('click', clearData); }); /** * Load all settings from storage */ async function loadAllSettings() { try { const config = await chrome.storage.sync.get(['apiKeys', 'modules']); // Load API keys if (config.apiKeys) { document.getElementById('api-capsolver').value = config.apiKeys.capsolver || ''; document.getElementById('api-2captcha').value = config.apiKeys.twocaptcha || ''; document.getElementById('api-nopecha').value = config.apiKeys.nopecha || ''; document.getElementById('api-nocaptchaai').value = config.apiKeys.nocaptchaai || ''; } // Load module configs if (config.modules) { // Captcha Solver const cs = config.modules.captchaSolver?.config; if (cs) { document.getElementById('cs-debug').checked = cs.debug || false; document.getElementById('cs-service').value = cs.apiService || 'capsolver'; document.getElementById('cs-delay').value = cs.solveDelay || 800; } // GOG Payment const gog = config.modules.gogPayment?.config; if (gog) { document.getElementById('gog-bins').value = gog.bins?.join(',') || ''; document.getElementById('gog-rotate').checked = gog.autoRotateBIN || false; } // AutoFill const af = config.modules.autoFill?.config; if (af) { document.getElementById('af-country').value = af.defaultCountry || 'US'; document.getElementById('af-delay').value = af.fillDelay || 300; } } } catch (error) { console.error('[Options] Failed to load settings:', error); } } /** * Save API Keys */ async function saveAPIKeys() { const apiKeys = { capsolver: document.getElementById('api-capsolver').value.trim(), twocaptcha: document.getElementById('api-2captcha').value.trim(), nopecha: document.getElementById('api-nopecha').value.trim(), nocaptchaai: document.getElementById('api-nocaptchaai').value.trim() }; try { await chrome.storage.sync.set({ apiKeys }); showNotification('API keys saved successfully', 'success'); } catch (error) { console.error('[Options] Failed to save API keys:', error); showNotification('Failed to save API keys', 'error'); } } /** * Save Module Configuration */ async function saveModuleConfig() { try { const config = await chrome.storage.sync.get(['modules']); // Update Captcha Solver config config.modules.captchaSolver.config.debug = document.getElementById('cs-debug').checked; config.modules.captchaSolver.config.apiService = document.getElementById('cs-service').value; config.modules.captchaSolver.config.solveDelay = parseInt(document.getElementById('cs-delay').value); // Update GOG Payment config const bins = document.getElementById('gog-bins').value.split(',').map(b => b.trim()).filter(b => b); config.modules.gogPayment.config.bins = bins; config.modules.gogPayment.config.autoRotateBIN = document.getElementById('gog-rotate').checked; // Update AutoFill config config.modules.autoFill.config.defaultCountry = document.getElementById('af-country').value; config.modules.autoFill.config.fillDelay = parseInt(document.getElementById('af-delay').value); await chrome.storage.sync.set(config); showNotification('Module configuration saved successfully', 'success'); } catch (error) { console.error('[Options] Failed to save module config:', error); showNotification('Failed to save configuration', 'error'); } } /** * Load statistics */ async function loadStats() { try { const response = await chrome.runtime.sendMessage({ type: 'GET_STATS' }); if (response && response.success) { const stats = response.stats; document.getElementById('total-captchas').textContent = stats.captchasSolved || 0; document.getElementById('total-forms').textContent = stats.formsFilled || 0; document.getElementById('total-cards').textContent = stats.cardsGenerated || 0; document.getElementById('total-payments').textContent = stats.paymentsCaptured || 0; } } catch (error) { console.error('[Options] Failed to load stats:', error); } } /** * Load data preview */ async function loadDataPreview() { try { const response = await chrome.runtime.sendMessage({ type: 'EXPORT_DATA' }); if (response && response.success) { const data = response.data; const preview = document.getElementById('data-preview-content'); if (data && data.length > 0) { preview.textContent = JSON.stringify(data, null, 2); } else { preview.textContent = 'No data captured yet'; } } } catch (error) { console.error('[Options] Failed to load data preview:', error); } } /** * Export data as JSON */ async function exportJSON() { try { const response = await chrome.runtime.sendMessage({ type: 'EXPORT_DATA' }); if (response && response.success) { const data = response.data; const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); downloadBlob(blob, `payment-automation-data-${Date.now()}.json`); showNotification('Data exported as JSON', 'success'); } } catch (error) { console.error('[Options] Failed to export JSON:', error); showNotification('Export failed', 'error'); } } /** * Export data as CSV */ async function exportCSV() { try { const response = await chrome.runtime.sendMessage({ type: 'EXPORT_DATA' }); if (response && response.success) { const data = response.data; if (!data || data.length === 0) { showNotification('No data to export', 'error'); return; } // Convert to CSV const headers = Object.keys(data[0]); const csv = [ headers.join(','), ...data.map(row => headers.map(h => JSON.stringify(row[h] || '')).join(',')) ].join('\n'); const blob = new Blob([csv], { type: 'text/csv' }); downloadBlob(blob, `payment-automation-data-${Date.now()}.csv`); showNotification('Data exported as CSV', 'success'); } } catch (error) { console.error('[Options] Failed to export CSV:', error); showNotification('Export failed', 'error'); } } /** * Clear all captured data */ async function clearData() { if (!confirm('Are you sure you want to clear all captured data? This cannot be undone.')) { return; } try { await chrome.runtime.sendMessage({ type: 'CLEAR_DATA' }); await loadDataPreview(); await loadStats(); showNotification('All data cleared', 'success'); } catch (error) { console.error('[Options] Failed to clear data:', error); showNotification('Failed to clear data', 'error'); } } /** * Download blob as file */ function downloadBlob(blob, filename) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } /** * Show notification */ function showNotification(message, type) { // Create notification element const notification = document.createElement('div'); notification.textContent = message; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; padding: 16px 24px; background: ${type === 'success' ? '#4CAF50' : '#f44336'}; color: white; border-radius: 6px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 10000; animation: slideIn 0.3s ease-out; `; document.body.appendChild(notification); // Remove after 3 seconds setTimeout(() => { notification.style.animation = 'slideOut 0.3s ease-out'; setTimeout(() => { document.body.removeChild(notification); }, 300); }, 3000); } // Add CSS animations const style = document.createElement('style'); style.textContent = ` @keyframes slideIn { from { transform: translateX(400px); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes slideOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(400px); opacity: 0; } } `; document.head.appendChild(style);