class IntegrationsManager {
|
constructor() {
|
this.initElements();
|
this.initListeners();
|
this.init();
|
}
|
|
initElements() {
|
//form.integrations
|
//data-action
|
//state
|
this.selectors = {
|
form: 'form.integration',
|
action: 'data-action',
|
};
|
|
let forms = document.querySelectorAll(this.selectors.form);
|
this.forms = new Map();
|
forms.forEach(form => {
|
this.forms.set(form.dataset.service, form);
|
});
|
}
|
|
initListeners() {
|
this.handleClick = this.clickHandler.bind(this);
|
this.handleChange = this.changeHandler.bind(this);
|
this.handleSubmit = this.submitHandler.bind(this);
|
|
|
// if (this.forms.size > 0) {
|
// for (const form of this.forms.values()) {
|
// form.addEventListener('click', this.handleClick);
|
// form.addEventListener('change', this.handleChange);
|
// form.addEventListener('submit', this.handleSubmit);
|
// }
|
// }
|
document.addEventListener('click', this.handleClick);
|
document.addEventListener('change', this.handleChange);
|
document.addEventListener('submit', this.handleSubmit);
|
}
|
init() {
|
document.addEventListener('DOMContentLoaded', () => {
|
this.checkForOAuthMessages();
|
});
|
}
|
|
/**
|
* Check URL parameters for OAuth success/error messages
|
*/
|
checkForOAuthMessages() {
|
const urlParams = new URLSearchParams(window.location.search);
|
const success = urlParams.get('success');
|
const error = urlParams.get('error');
|
|
if (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', 8000);
|
|
// Clean URL without reloading
|
this.cleanURL();
|
}
|
}
|
|
/**
|
* Remove query parameters from URL without reloading
|
*/
|
cleanURL() {
|
const url = new URL(window.location);
|
url.searchParams.delete('success');
|
url.searchParams.delete('error');
|
window.history.replaceState({}, document.title, url.pathname + url.hash);
|
}
|
|
/**
|
* Show notification message
|
*/
|
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, duration);
|
}
|
}
|
|
addPopup(message, delay = 2000) {
|
if (!this.popup) {
|
// Create popup element if it doesn't exist
|
this.popup = document.querySelector('.integration-popup') ||
|
this.createPopupElement();
|
}
|
|
this.popup.textContent = message;
|
this.popup.classList.add('showing');
|
|
setTimeout(() => {
|
this.popup.classList.remove('showing');
|
}, delay);
|
}
|
|
createPopupElement() {
|
const popup = document.createElement('div');
|
popup.className = 'integration-popup';
|
document.body.appendChild(popup);
|
return popup;
|
}
|
|
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;
|
}
|
|
if (e.target.tagName === 'BUTTON' || e.target.closest('button')) {
|
e.preventDefault();
|
let target = e.target.tagName === 'BUTTON' ? e.target : e.target.closest('button');
|
this.handleAction(target);
|
}
|
}
|
changeHandler(e) {
|
if (!e.target.closest(this.selectors.form)) {
|
return;
|
}
|
if ('action' in e.target.dataset) {
|
this.handleAction(e.target);
|
} else {
|
let form = this.getFormFromTarget(e.target);
|
if (!form) {
|
return;
|
}
|
form.classList.add('hasChanges');
|
form.querySelector('.setup .text').textContent = 'Unsaved Changes';
|
}
|
}
|
submitHandler(e) {
|
if (!e.target.closest(this.selectors.form)) {
|
return;
|
}
|
e.preventDefault();
|
}
|
|
getFormFromTarget(target) {
|
let service = target.closest('form')?.dataset.service;
|
return this.forms.get(service)??false;
|
}
|
|
async handleAction(input) {
|
const form = input.closest('form');
|
const service = form.dataset.service;
|
const action = input.dataset.action;
|
const isButton = input.tagName === 'BUTTON';
|
const isSave = isButton && action === 'save_credentials';
|
|
if ('confirm' in input.dataset && !confirm(input.dataset.confirm)) {
|
return;
|
}
|
|
|
this.updateUI(form, 'syncing');
|
try {
|
this.updateUI(form, 'syncing');
|
const data = {
|
service: service,
|
action: action,
|
user_id: window.auth.getUser(),
|
data: {}
|
};
|
if (!isButton) {
|
data.data[input.name.replace(service+'_', '')] = input.value;
|
}
|
|
if (isSave) {
|
const formData = new FormData(form);
|
for (let [key, value] of formData.entries()) {
|
if (!['service'].includes(key) && !key.includes('nonce')) {
|
data.data[key.replace(service+'_', '')] = value;
|
}
|
}
|
}
|
|
// Make API request
|
const response = await fetch(
|
jvbSettings.api + 'integrations', {
|
method: 'POST',
|
headers: {
|
'Content-Type': 'application/json',
|
'X-WP-Nonce': window.auth.getNonce()
|
},
|
body: JSON.stringify(data)
|
});
|
|
const result = await response.json();
|
|
if (response.ok && result.success) {
|
let status = 'connected';
|
switch (action) {
|
case 'clear_credentials':
|
status = 'disconnected';
|
break;
|
case 'save_credentials':
|
this.showNotification('Settings saved successfully', 'success');
|
break;
|
}
|
this.updateUI(form, status);
|
|
if (result.reload) {
|
setTimeout(() => {
|
window.location.reload();
|
}, 50);
|
}
|
} else {
|
this.updateUI(form, 'error', result.message??'');
|
this.showNotification(result.message || 'Operation failed', 'error');
|
}
|
|
} catch (error) {
|
this.updateUI(form, 'error');
|
this.showNotification('Network error: ' + error.message, 'error');
|
console.error('API Error:', error);
|
}
|
|
}
|
|
updateUI(form, state, message = '')
|
{
|
let allowed = ['connected', 'disconnected', 'hasChanges', 'syncing', 'error'];
|
if (!allowed.includes(state)) {
|
return;
|
}
|
let defaults = {
|
connected: 'Set Up',
|
disconnected: 'Not Set Up',
|
hasChanges: 'Unsaved Changes',
|
syncing: 'Testing changes',
|
error: 'Something went wrong'
|
};
|
message = message === '' ? defaults[state] : message;
|
|
if (state === 'syncing') {
|
form.querySelectorAll('button').forEach(button => {
|
button.disabled = true;
|
});
|
} else {
|
form.querySelectorAll('button[disabled]').forEach(button => {
|
button.disabled = false;
|
});
|
}
|
|
|
form.classList.remove(...allowed);
|
form.classList.add(state, 'flash');
|
let status = form.querySelector('.setup .text');
|
status.textContent = message;
|
// Enable/disable buttons
|
if (state === 'syncing') {
|
form.querySelectorAll('button').forEach(btn => btn.disabled = true);
|
} else {
|
form.querySelectorAll('button:disabled').forEach(btn => btn.disabled = false);
|
}
|
setTimeout(() => form.classList.remove('flash'), 600);
|
}
|
|
}
|
|
window.jvbOAuthPopup = function(url, service) {
|
const width = 600;
|
const height = 700;
|
const left = (window.screen.width - width) / 2;
|
const top = (window.screen.height - height) / 2;
|
|
// Add popup indicator to URL
|
url += (url.indexOf('?') > -1 ? '&' : '?') + 'popup=1';
|
|
|
const popup = window.open(
|
url,
|
service + '-oauth',
|
`width=${width},height=${height},left=${left},top=${top},scrollbars=yes,resizable=yes,toolbar=no,menubar=no`
|
);
|
|
if (!popup) {
|
alert('Please allow popups for this site to complete the authorization process.');
|
return false;
|
}
|
|
// Set up listener for OAuth completion
|
window.jvbOAuthComplete = function(completedService, success, message) {
|
if (completedService === service) {
|
if (success) {
|
// Show success message
|
const statusEl = document.querySelector(`.integration-card[data-service="${service}"] .setup .text`);
|
if (statusEl) {
|
statusEl.textContent = 'Connection successful! Refreshing...';
|
}
|
|
// Refresh the integration card
|
setTimeout(() => {
|
jvbRefreshIntegration(service);
|
}, 1000);
|
} else {
|
// Show error message
|
alert('OAuth authorization failed: ' + (message || 'Unknown error'));
|
|
// Still refresh to update UI state
|
jvbRefreshIntegration(service);
|
}
|
}
|
};
|
|
// Fallback: Check if popup closed manually
|
const checkPopup = setInterval(() => {
|
try {
|
if (popup.closed) {
|
clearInterval(checkPopup);
|
// Refresh anyway in case auth completed
|
setTimeout(() => {
|
jvbRefreshIntegration(service);
|
}, 1000);
|
}
|
} catch (e) {
|
// Cross-origin error, popup is still open
|
}
|
}, 1000);
|
|
return false;
|
};
|
|
// Refresh integration display
|
window.jvbRefreshIntegration = function(service) {
|
|
// Use your REST API to check connection status
|
fetch(jvbSettings.api + 'integrations', {
|
method: 'POST',
|
headers: {
|
'Content-Type': 'application/json',
|
'X-WP-Nonce': window.auth.getNonce()
|
},
|
body: JSON.stringify({
|
service: service,
|
action: 'check_oauth_status'
|
})
|
})
|
.then(response => response.json())
|
.then(data => {
|
console.log('OAuth status check result:', data);
|
|
if (data.success && data.authorized) {
|
// Update UI to show connected state
|
const card = document.querySelector(`.integration-card[data-service="${service}"]`);
|
if (card) {
|
card.classList.remove('disconnected');
|
card.classList.add('connected');
|
|
const statusEl = card.querySelector('.setup .text');
|
if (statusEl) {
|
statusEl.textContent = 'Connected';
|
}
|
|
// Show success message then reload
|
setTimeout(() => {
|
location.reload();
|
}, 1500);
|
}
|
} else {
|
// Just reload to update the UI
|
location.reload();
|
}
|
})
|
.catch(error => {
|
console.error('Error checking OAuth status:', error);
|
// Reload anyway
|
location.reload();
|
});
|
};
|
document.addEventListener('DOMContentLoaded', async function() {
|
window.auth.subscribe((event) => {
|
if (event === 'auth-loaded') {
|
window.integrations = new IntegrationsManager();
|
}
|
});
|
});
|