Change to link-based group management

This commit is contained in:
Antigravity 2026-06-14 01:14:01 -04:00
parent 915a2a004b
commit eee7189867
3 changed files with 89 additions and 99 deletions

View File

@ -114,7 +114,6 @@ async function fetchGroups() {
<td>${g.participants}</td>
<td>
${!isDefault ? `<button class="primary-btn" onclick="setDefaultDestination('${g.id}')" style="margin-right: 8px;">Set Default</button>` : ''}
<button class="secondary-btn" onclick="getInviteLink('${g.id}')">Get Invite Link</button>
</td>
`;
groupsTableBody.appendChild(tr);
@ -143,7 +142,32 @@ async function setDefaultDestination(groupId) {
}
}
document.getElementById('btn-refresh-groups').addEventListener('click', fetchGroups);
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() {
@ -181,59 +205,6 @@ async function fetchApps() {
document.getElementById('btn-refresh-apps').addEventListener('click', fetchApps);
// Create Group
document.getElementById('create-group-form').addEventListener('submit', async (e) => {
e.preventDefault();
const btn = e.target.querySelector('button');
btn.textContent = 'Creating...';
btn.disabled = true;
const title = document.getElementById('new-group-name').value;
const participant = document.getElementById('new-group-participant').value;
try {
const res = await fetch('api/groups/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, initialParticipants: [participant] })
});
const data = await res.json();
if (data.success) {
alert('Group created successfully! ID: ' + data.groupId);
fetchGroups();
e.target.reset();
} else {
alert('Error: ' + data.error);
}
} catch (err) {
alert('Failed to create group.');
} finally {
btn.textContent = 'Create Group';
btn.disabled = false;
}
});
// Invite Link Modal
window.getInviteLink = async (groupId) => {
try {
const res = await fetch('api/groups/invite', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ groupId })
});
const data = await res.json();
if (data.success) {
inviteLinkInput.value = data.inviteLink;
inviteModal.classList.add('active');
} else {
alert('Failed to get invite link: ' + data.error);
}
} catch (err) {
alert('Request failed.');
}
};
document.querySelector('.close-modal').addEventListener('click', () => {
inviteModal.classList.remove('active');
});

View File

@ -53,9 +53,19 @@
<section id="groups" class="tab-pane">
<header>
<h2>Group Management</h2>
<button id="btn-refresh-groups" class="primary-btn">Refresh Groups</button>
</header>
<div class="card mb-4" style="margin-bottom: 20px;">
<h3>Add Group by Invite Link</h3>
<form id="add-group-link-form" class="form-grid" style="display:flex; gap:10px; align-items:flex-end;">
<div class="form-group" style="flex:1;">
<label>WhatsApp Invite Link</label>
<input type="text" id="new-invite-link" placeholder="https://chat.whatsapp.com/..." required>
</div>
<button type="submit" class="primary-btn">Add Group</button>
</form>
</div>
<div class="card">
<table class="data-table">
<thead>
@ -72,21 +82,6 @@
</tbody>
</table>
</div>
<div class="card mt-4">
<h3>Create New Group</h3>
<form id="create-group-form" class="form-grid">
<div class="form-group">
<label>Group Name</label>
<input type="text" id="new-group-name" placeholder="e.g. Alerts Channel" required>
</div>
<div class="form-group">
<label>Initial Participant (JID or Phone)</label>
<input type="text" id="new-group-participant" placeholder="e.g. 14085551234@c.us" required>
</div>
<button type="submit" class="primary-btn">Create Group</button>
</form>
</div>
</section>
<!-- Connected Apps Tab -->

View File

@ -189,47 +189,60 @@ app.post('/api/send-message', handleSendMessage);
// Legacy endpoint
app.post('/send-message', handleSendMessage);
app.get('/api/groups', async (req, res) => {
app.get('/api/groups', (req, res) => {
if (!isReady) return res.status(503).json({ error: 'Not ready' });
try {
const chats = await client.getChats();
const groups = chats.filter(c => c.isGroup);
const groupData = groups.map(g => ({
id: g.id._serialized,
name: g.name,
participants: g.participants ? g.participants.length : 0
}));
res.json({ success: true, groups: groupData });
} catch (err) {
res.status(500).json({ error: err.message });
}
res.json({ success: true, groups: loadConfiguredGroups() });
});
app.post('/api/groups/invite', async (req, res) => {
app.post('/api/groups/add-by-link', async (req, res) => {
if (!isReady) return res.status(503).json({ error: 'Not ready' });
const { groupId } = req.body;
try {
const code = await client.groupGetInviteCode(groupId);
res.json({ success: true, inviteLink: `https://chat.whatsapp.com/${code}` });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
const { link } = req.body;
if (!link) return res.status(400).json({ error: 'Link is required' });
app.post('/api/groups/create', async (req, res) => {
if (!isReady) return res.status(503).json({ error: 'Not ready' });
const { title, initialParticipants = [] } = req.body; // Needs standard WhatsApp JIDs
try {
const result = await client.createGroup(title, initialParticipants);
res.json({ success: true, groupId: result.gid._serialized });
let inviteCode = link;
if (link.includes('chat.whatsapp.com/')) {
inviteCode = link.split('chat.whatsapp.com/')[1].split('?')[0].trim();
}
let groupId, groupName;
try {
// Attempt to accept invite (this will fail if already in the group)
groupId = await client.acceptInvite(inviteCode);
// If acceptInvite returns the ID, we try to get info to get the name
const info = await client.getInviteInfo(inviteCode);
groupName = info.subject || 'Unknown Group';
} catch (e) {
// If it failed, it might be because we're already in it.
// Let's just fetch the info!
const info = await client.getInviteInfo(inviteCode);
groupId = info.id._serialized || info.id;
groupName = info.subject || 'Unknown Group';
}
const newGroup = {
id: groupId,
name: groupName,
participants: 'Unknown' // We don't fetch participant count from invite info to save time
};
const groups = loadConfiguredGroups();
if (!groups.find(g => g.id === groupId)) {
groups.push(newGroup);
saveConfiguredGroups(groups);
}
res.json({ success: true, group: newGroup });
} catch (err) {
res.status(500).json({ error: err.message });
res.status(500).json({ error: err.message || 'Failed to process invite link' });
}
});
// ─── Settings ─────────────────────────────────────────────────────────────
const fs = require('fs');
const SETTINGS_FILE = path.join(__dirname, 'settings.json');
const GROUPS_FILE = path.join(__dirname, 'configured_groups.json');
function loadSettings() {
if (fs.existsSync(SETTINGS_FILE)) {
@ -242,6 +255,17 @@ function saveSettings(settings) {
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2));
}
function loadConfiguredGroups() {
if (fs.existsSync(GROUPS_FILE)) {
return JSON.parse(fs.readFileSync(GROUPS_FILE));
}
return [];
}
function saveConfiguredGroups(groups) {
fs.writeFileSync(GROUPS_FILE, JSON.stringify(groups, null, 2));
}
app.get('/api/settings', (req, res) => {
res.json({ success: true, settings: loadSettings() });
});