277 lines
9.6 KiB
JavaScript
277 lines
9.6 KiB
JavaScript
const socket = io({ path: '/proxy/whatsapp/socket.io' });
|
|
|
|
// UI Elements
|
|
const statusBadge = document.getElementById('status-badge');
|
|
const qrContainer = document.getElementById('qr-container');
|
|
const activityLog = document.getElementById('activity-log');
|
|
const groupsTableBody = document.getElementById('groups-table-body');
|
|
const appsTableBody = document.getElementById('apps-table-body');
|
|
const inviteModal = document.getElementById('invite-modal');
|
|
const inviteLinkInput = document.getElementById('invite-link-input');
|
|
const logoutBtn = document.getElementById('logout-btn');
|
|
|
|
if (logoutBtn) {
|
|
logoutBtn.addEventListener('click', async () => {
|
|
const confirmLogout = confirm('Are you sure you want to log out and change your WhatsApp account? This will disconnect the current session and restart the gateway.');
|
|
if (!confirmLogout) return;
|
|
|
|
logoutBtn.disabled = true;
|
|
logoutBtn.textContent = 'Logging out...';
|
|
|
|
try {
|
|
await fetch('api/whatsapp/logout', { method: 'POST' });
|
|
alert('Logout initiated! The WhatsApp Gateway is restarting. Please wait 5-10 seconds and then hard-refresh the page to scan a new QR code.');
|
|
} catch (err) {
|
|
console.error('Logout error:', err);
|
|
alert('Failed to log out cleanly, but restarting anyway. Please refresh.');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Tab Switching
|
|
document.querySelectorAll('.nav-btn').forEach(btn => {
|
|
btn.addEventListener('click', (e) => {
|
|
document.querySelectorAll('.nav-btn').forEach(b => b.classList.remove('active'));
|
|
document.querySelectorAll('.tab-pane').forEach(p => p.classList.remove('active'));
|
|
|
|
e.target.classList.add('active');
|
|
document.getElementById(e.target.dataset.tab).classList.add('active');
|
|
|
|
if (e.target.dataset.tab === 'groups') {
|
|
fetchGroups();
|
|
}
|
|
if (e.target.dataset.tab === 'apps') {
|
|
fetchApps();
|
|
}
|
|
});
|
|
});
|
|
|
|
// Logging
|
|
function logActivity(msg, type = 'info') {
|
|
const entry = document.createElement('p');
|
|
entry.className = `log-entry ${type}`;
|
|
const time = new Date().toLocaleTimeString();
|
|
entry.textContent = `[${time}] ${msg}`;
|
|
activityLog.prepend(entry);
|
|
}
|
|
|
|
// Socket Events
|
|
socket.on('status', (data) => {
|
|
updateStatus(data.ready);
|
|
if (data.ready) {
|
|
qrContainer.innerHTML = '<h3>✅ Connected</h3><p>Session is active and authenticated.</p>';
|
|
} else if (data.qr) {
|
|
renderQR(data.qr);
|
|
}
|
|
});
|
|
|
|
socket.on('qr', (qr) => {
|
|
renderQR(qr);
|
|
logActivity('New QR code generated', 'system');
|
|
});
|
|
|
|
socket.on('ready', () => {
|
|
updateStatus(true);
|
|
qrContainer.innerHTML = '<h3>✅ Connected</h3><p>Session is active and authenticated.</p>';
|
|
logActivity('Client successfully authenticated and ready', 'success');
|
|
});
|
|
|
|
socket.on('disconnected', (reason) => {
|
|
updateStatus(false);
|
|
logActivity(`Disconnected: ${reason}`, 'error');
|
|
});
|
|
|
|
socket.on('incoming_message', (msg) => {
|
|
logActivity(`Msg from ${msg.from}: ${msg.body.substring(0, 50)}...`, 'info');
|
|
});
|
|
|
|
function updateStatus(isReady) {
|
|
if (isReady) {
|
|
statusBadge.textContent = 'Connected';
|
|
statusBadge.className = 'badge success';
|
|
if (logoutBtn) logoutBtn.style.display = 'block';
|
|
} else {
|
|
statusBadge.textContent = 'Disconnected';
|
|
statusBadge.className = 'badge error';
|
|
if (logoutBtn) logoutBtn.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
function renderQR(qrText) {
|
|
qrContainer.innerHTML = '';
|
|
const qr = qrcode(0, 'L');
|
|
qr.addData(qrText);
|
|
qr.make();
|
|
qrContainer.innerHTML = qr.createImgTag(5);
|
|
}
|
|
|
|
// Groups Tab functionality
|
|
async function fetchGroups() {
|
|
groupsTableBody.innerHTML = '<tr><td colspan="3" class="text-center">Loading...</td></tr>';
|
|
try {
|
|
const res = await fetch('api/groups');
|
|
const data = await res.json();
|
|
|
|
if (!data.success) {
|
|
groupsTableBody.innerHTML = `<tr><td colspan="3" class="text-center">Error: ${data.error || 'Not connected'}</td></tr>`;
|
|
return;
|
|
}
|
|
|
|
if (data.groups.length === 0) {
|
|
groupsTableBody.innerHTML = '<tr><td colspan="3" class="text-center">No groups found.</td></tr>';
|
|
return;
|
|
}
|
|
|
|
const settingsRes = await fetch('api/settings');
|
|
const settingsData = await settingsRes.json();
|
|
const defaultDest = settingsData.settings?.defaultDestination || '';
|
|
|
|
groupsTableBody.innerHTML = '';
|
|
data.groups.forEach(g => {
|
|
const isDefault = g.id === defaultDest;
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `
|
|
<td>
|
|
<strong>${g.name}</strong>
|
|
${isDefault ? '<span class="badge success" style="margin-left:8px;font-size:10px;">Default</span>' : ''}
|
|
<br><small style="color:var(--text-muted)">${g.id}</small>
|
|
</td>
|
|
<td>${g.participants}</td>
|
|
<td>
|
|
${!isDefault ? `<button class="primary-btn" onclick="setDefaultDestination('${g.id}')" style="margin-right: 8px;">Set Default</button>` : ''}
|
|
</td>
|
|
`;
|
|
groupsTableBody.appendChild(tr);
|
|
});
|
|
|
|
} catch (e) {
|
|
groupsTableBody.innerHTML = `<tr><td colspan="3" class="text-center">Fetch failed.</td></tr>`;
|
|
}
|
|
}
|
|
|
|
async function setDefaultDestination(groupId) {
|
|
try {
|
|
const res = await fetch('api/settings/default-destination', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ destinationId: groupId })
|
|
});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
fetchGroups();
|
|
} else {
|
|
alert('Error setting default: ' + data.error);
|
|
}
|
|
} catch (e) {
|
|
alert('Failed to set default destination.');
|
|
}
|
|
}
|
|
|
|
document.getElementById('add-group-link-form').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const btn = e.target.querySelector('button');
|
|
const input = document.getElementById('new-invite-link');
|
|
btn.disabled = true;
|
|
btn.textContent = 'Adding...';
|
|
|
|
try {
|
|
const res = await fetch('api/groups/add-by-link', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ link: input.value })
|
|
});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
input.value = '';
|
|
fetchGroups();
|
|
} else {
|
|
alert('Error adding group: ' + data.error);
|
|
}
|
|
} catch (err) {
|
|
alert('Failed to add group');
|
|
}
|
|
btn.disabled = false;
|
|
btn.textContent = 'Add Group';
|
|
});
|
|
|
|
// Connected Apps functionality
|
|
async function fetchApps() {
|
|
appsTableBody.innerHTML = '<tr><td colspan="4" class="text-center">Loading...</td></tr>';
|
|
try {
|
|
const res = await fetch('api/apps');
|
|
const data = await res.json();
|
|
|
|
if (!data.success) {
|
|
appsTableBody.innerHTML = `<tr><td colspan="4" class="text-center">Error fetching apps</td></tr>`;
|
|
return;
|
|
}
|
|
|
|
if (data.apps.length === 0) {
|
|
appsTableBody.innerHTML = '<tr><td colspan="4" class="text-center">No apps connected yet. Send a message to see an app appear here!</td></tr>';
|
|
return;
|
|
}
|
|
|
|
appsTableBody.innerHTML = '';
|
|
data.apps.sort((a, b) => new Date(b.lastSeen) - new Date(a.lastSeen)).forEach(app => {
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `
|
|
<td><strong>${app.name}</strong></td>
|
|
<td>${app.messageCount}</td>
|
|
<td>${new Date(app.lastSeen).toLocaleString()}</td>
|
|
<td><small style="color:var(--text-muted)">${app.lastIp}</small></td>
|
|
`;
|
|
appsTableBody.appendChild(tr);
|
|
});
|
|
|
|
} catch (e) {
|
|
appsTableBody.innerHTML = `<tr><td colspan="4" class="text-center">Fetch failed.</td></tr>`;
|
|
}
|
|
}
|
|
|
|
document.getElementById('btn-refresh-apps').addEventListener('click', fetchApps);
|
|
|
|
document.querySelector('.close-modal').addEventListener('click', () => {
|
|
inviteModal.classList.remove('active');
|
|
});
|
|
|
|
document.getElementById('btn-copy-link').addEventListener('click', () => {
|
|
inviteLinkInput.select();
|
|
document.execCommand('copy');
|
|
alert('Copied to clipboard!');
|
|
});
|
|
|
|
// Test Message
|
|
document.getElementById('test-msg-form').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const btn = e.target.querySelector('button');
|
|
const resultDiv = document.getElementById('test-result');
|
|
|
|
btn.textContent = 'Sending...';
|
|
btn.disabled = true;
|
|
resultDiv.textContent = '';
|
|
|
|
const to = document.getElementById('test-to').value;
|
|
const message = document.getElementById('test-body').value;
|
|
|
|
try {
|
|
const res = await fetch('api/send-message', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ to, message })
|
|
});
|
|
const data = await res.json();
|
|
|
|
if (data.success) {
|
|
resultDiv.innerHTML = `<span style="color:var(--success)">✅ Sent successfully (ID: ${data.messageId})</span>`;
|
|
document.getElementById('test-body').value = '';
|
|
} else {
|
|
resultDiv.innerHTML = `<span style="color:var(--error)">❌ ${data.error}</span>`;
|
|
}
|
|
} catch (err) {
|
|
resultDiv.innerHTML = `<span style="color:var(--error)">❌ Request failed.</span>`;
|
|
} finally {
|
|
btn.textContent = 'Send Message';
|
|
btn.disabled = false;
|
|
}
|
|
});
|