| | |
| | | const error = urlParams.get('error'); |
| | | |
| | | if (success) { |
| | | this.showNotification(success, 'success'); |
| | | this.showNotification(success, 'success', 5000); |
| | | |
| | | // Clean URL without reloading |
| | | this.cleanURL(); |
| | | |
| | | // Refresh the integration status display |
| | | const forms = document.querySelectorAll('form.integration'); |
| | | forms.forEach(form => { |
| | | // Update UI to show connected state |
| | | this.updateUI(form, 'connected'); |
| | | }); |
| | | |
| | | } else if (error) { |
| | | this.showNotification(error, 'error'); |
| | | this.showNotification(error, 'error', 8000); |
| | | |
| | | // Clean URL without reloading |
| | | this.cleanURL(); |
| | | } |
| | |
| | | /** |
| | | * Show notification message |
| | | */ |
| | | showNotification(message, type = 'info') { |
| | | // If you have a notification system, use it |
| | | showNotification(message, type = 'info', duration = 5000) { |
| | | // Find or create notification container |
| | | let container = document.querySelector('.integration-status-message'); |
| | | |
| | | if (!container) { |
| | | // Create notification container |
| | | container = document.createElement('div'); |
| | | container.className = 'integration-status-message'; |
| | | |
| | | // Insert at top of main content or integrations container |
| | | const target = document.querySelector('.integration-settings') || |
| | | document.querySelector('main') || |
| | | document.body; |
| | | target.insertBefore(container, target.firstChild); |
| | | } |
| | | |
| | | // Update content and type |
| | | container.textContent = message; |
| | | container.className = `integration-status-message ${type}`; |
| | | |
| | | // Clear any existing timeout |
| | | if (this.notificationTimeout) { |
| | | clearTimeout(this.notificationTimeout); |
| | | } |
| | | |
| | | // Auto-hide after duration |
| | | if (duration > 0) { |
| | | this.notificationTimeout = setTimeout(() => { |
| | | container.className = 'integration-status-message'; |
| | | container.textContent = ''; |
| | | }, duration); |
| | | } |
| | | |
| | | // Also use popup if available |
| | | if (this.popup) { |
| | | this.addPopup(message, type === 'error' ? 5000 : 3000); |
| | | } else { |
| | | // Fallback to console or alert |
| | | console.log(`[${type}]`, message); |
| | | |
| | | // Update any status elements on the page |
| | | const statusElements = document.querySelectorAll('.integration-status-message'); |
| | | statusElements.forEach(el => { |
| | | el.textContent = message; |
| | | el.className = `integration-status-message ${type}`; |
| | | |
| | | // Auto-hide after delay |
| | | setTimeout(() => { |
| | | el.textContent = ''; |
| | | el.className = 'integration-status-message'; |
| | | }, 5000); |
| | | }); |
| | | this.addPopup(message, duration); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | clickHandler(e) { |
| | | // // Check for OAuth authorization link |
| | | // if (e.target.classList.contains('jvb-oauth-connect') || |
| | | // e.target.closest('.jvb-oauth-connect')) { |
| | | // e.preventDefault(); |
| | | // const link = e.target.classList.contains('jvb-oauth-connect') |
| | | // ? e.target |
| | | // : e.target.closest('.jvb-oauth-connect'); |
| | | // return this.handleOAuthClick(link); |
| | | // } |
| | | |
| | | // Existing integration form handling |
| | | if (!e.target.closest(this.selectors.form)) { |
| | | return; |
| | | } |
| | | |
| | | console.log('Clicked!'); |
| | | if (e.target.tagName === 'BUTTON' || e.target.closest('button')) { |
| | | e.preventDefault(); |
| | |
| | | return this.forms.get(service)??false; |
| | | } |
| | | |
| | | /** |
| | | * Handle OAuth authorization link clicks |
| | | * Opens OAuth in a popup window with proper handling |
| | | */ |
| | | handleOAuthClick(link) { |
| | | const service = link.dataset.service; |
| | | const href = link.href; |
| | | |
| | | // Calculate center position for popup |
| | | const width = 600; |
| | | const height = 700; |
| | | const left = (screen.width - width) / 2; |
| | | const top = (screen.height - height) / 2; |
| | | |
| | | // Show loading notification |
| | | this.showNotification('Opening authorization window...', 'info'); |
| | | |
| | | // Add loading state to the link |
| | | link.classList.add('loading'); |
| | | link.setAttribute('aria-busy', 'true'); |
| | | |
| | | // Open OAuth in popup |
| | | const popup = window.open( |
| | | href, |
| | | 'oauth_' + service, |
| | | `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no,location=yes,status=yes,resizable=yes` |
| | | ); |
| | | |
| | | if (!popup) { |
| | | // Popup was blocked |
| | | this.showNotification('Popup was blocked. Please allow popups and try again.', 'error'); |
| | | link.classList.remove('loading'); |
| | | link.removeAttribute('aria-busy'); |
| | | return true; // Allow default behavior as fallback |
| | | } |
| | | |
| | | // Focus the popup |
| | | popup.focus(); |
| | | |
| | | // Update notification |
| | | this.showNotification('Waiting for authorization...', 'info'); |
| | | |
| | | // Poll for popup close |
| | | const pollTimer = setInterval(() => { |
| | | try { |
| | | if (popup.closed) { |
| | | clearInterval(pollTimer); |
| | | |
| | | // Remove loading state |
| | | link.classList.remove('loading'); |
| | | link.removeAttribute('aria-busy'); |
| | | |
| | | // Show checking notification |
| | | this.showNotification('Checking authorization status...', 'info'); |
| | | |
| | | // Wait a moment for redirect to complete, then check for messages |
| | | setTimeout(() => { |
| | | this.checkForOAuthMessages(); |
| | | |
| | | // If no messages found, reload to get updated connection status |
| | | setTimeout(() => { |
| | | const urlParams = new URLSearchParams(window.location.search); |
| | | if (!urlParams.has('success') && !urlParams.has('error')) { |
| | | // No messages in URL, reload to check server-side status |
| | | window.location.reload(); |
| | | } |
| | | }, 500); |
| | | }, 500); |
| | | } |
| | | } catch (error) { |
| | | // Ignore cross-origin errors during polling |
| | | } |
| | | }, 500); |
| | | |
| | | // Safety timeout - stop polling after 5 minutes |
| | | setTimeout(() => { |
| | | clearInterval(pollTimer); |
| | | link.classList.remove('loading'); |
| | | link.removeAttribute('aria-busy'); |
| | | }, 300000); |
| | | |
| | | return false; // Prevent default link behavior |
| | | } |
| | | |
| | | async handleAction(input) { |
| | | const form = input.closest('form'); |
| | | const service = form.dataset.service; |