diff --git a/client/app.js b/client/app.js index e745a18..516a4e6 100644 --- a/client/app.js +++ b/client/app.js @@ -570,6 +570,8 @@ function showSettingsModal() { // Reset forms document.getElementById('emailTab').querySelector('form').reset(); document.getElementById('passwordTab').querySelector('form').reset(); + // Load connected accounts + loadConnectedAccounts(); // Show email tab by default switchSettingsTab('email'); showModal('settingsModal'); @@ -643,6 +645,150 @@ function updatePassword(event) { .catch(err => showNotification('Error updating password', 'error')); } +// Connected Accounts Management +let availableSites = []; + +async function loadConnectedAccounts() { + try { + const response = await fetch(`${API_BASE}/credentials/my-accounts`, { + headers: { 'Authorization': `Bearer ${authToken}` } + }); + const data = await response.json(); + + availableSites = data.sites || []; + + // Populate site selector + const siteSelect = document.getElementById('accountSiteSelect'); + siteSelect.innerHTML = '' + + availableSites.map(site => ``).join(''); + + // Display connected accounts + const accountsList = document.getElementById('connectedAccountsList'); + if (data.accounts && data.accounts.length > 0) { + accountsList.innerHTML = data.accounts.map(account => { + const statusColor = account.is_connected ? '#00ae42' : '#dc3545'; + const statusText = account.is_connected ? '✓ Connected' : '✗ Disconnected'; + return ` +
Username: ${account.username}
++ ${statusText} +
+No connected accounts yet
'; + } + } catch (error) { + console.error('Error loading connected accounts:', error); + showNotification('Failed to load connected accounts', 'error'); + } +} + +function updateAccountForm() { + const siteSelect = document.getElementById('accountSiteSelect').value; + const formFields = document.getElementById('accountFormFields'); + + if (siteSelect) { + formFields.style.display = 'block'; + // Clear fields + document.getElementById('accountUsername').value = ''; + document.getElementById('accountPassword').value = ''; + document.getElementById('accountApiKey').value = ''; + document.getElementById('accountAccessToken').value = ''; + } else { + formFields.style.display = 'none'; + } +} + +async function addConnectedAccount() { + const siteName = document.getElementById('accountSiteSelect').value; + const username = document.getElementById('accountUsername').value; + const password = document.getElementById('accountPassword').value; + const apiKey = document.getElementById('accountApiKey').value; + const accessToken = document.getElementById('accountAccessToken').value; + + if (!siteName || (!username && !apiKey && !accessToken)) { + showNotification('Please provide at least a username or API key', 'error'); + return; + } + + try { + const response = await fetch(`${API_BASE}/credentials/connect`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${authToken}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ siteName, username, password, apiKey, accessToken }) + }); + + const data = await response.json(); + + if (response.ok) { + showNotification(data.message, 'success'); + await loadConnectedAccounts(); + } else { + showNotification(data.error || 'Failed to add account', 'error'); + } + } catch (error) { + showNotification('Error adding account: ' + error.message, 'error'); + } +} + +async function removeConnectedAccount(siteName) { + if (!confirm(`Remove ${siteName} account?`)) return; + + try { + const response = await fetch(`${API_BASE}/credentials/disconnect/${siteName}`, { + method: 'DELETE', + headers: { 'Authorization': `Bearer ${authToken}` } + }); + + const data = await response.json(); + + if (response.ok) { + showNotification(data.message, 'success'); + await loadConnectedAccounts(); + } else { + showNotification(data.error || 'Failed to remove account', 'error'); + } + } catch (error) { + showNotification('Error removing account: ' + error.message, 'error'); + } +} + +async function testAccountConnection() { + const siteName = document.getElementById('accountSiteSelect').value; + + if (!siteName) { + showNotification('Please select a website', 'error'); + return; + } + + try { + const response = await fetch(`${API_BASE}/credentials/test-connection/${siteName}`, { + method: 'POST', + headers: { 'Authorization': `Bearer ${authToken}` } + }); + + const data = await response.json(); + + if (response.ok) { + showNotification(data.message, 'success'); + } else { + showNotification(data.error || 'Connection test failed', 'error'); + } + } catch (error) { + showNotification('Error testing connection: ' + error.message, 'error'); + } +} + // Close modals when clicking outside window.onclick = function(event) { if (event.target.classList.contains('modal')) { diff --git a/client/index.html b/client/index.html index 8d550fe..a87b4c0 100644 --- a/client/index.html +++ b/client/index.html @@ -654,6 +654,7 @@Connect your accounts from 3D model websites to automatically download models from URLs.
+ +