Change to link-based group management
This commit is contained in:
parent
915a2a004b
commit
eee7189867
|
|
@ -114,7 +114,6 @@ async function fetchGroups() {
|
||||||
<td>${g.participants}</td>
|
<td>${g.participants}</td>
|
||||||
<td>
|
<td>
|
||||||
${!isDefault ? `<button class="primary-btn" onclick="setDefaultDestination('${g.id}')" style="margin-right: 8px;">Set Default</button>` : ''}
|
${!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>
|
</td>
|
||||||
`;
|
`;
|
||||||
groupsTableBody.appendChild(tr);
|
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
|
// Connected Apps functionality
|
||||||
async function fetchApps() {
|
async function fetchApps() {
|
||||||
|
|
@ -181,59 +205,6 @@ async function fetchApps() {
|
||||||
|
|
||||||
document.getElementById('btn-refresh-apps').addEventListener('click', 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', () => {
|
document.querySelector('.close-modal').addEventListener('click', () => {
|
||||||
inviteModal.classList.remove('active');
|
inviteModal.classList.remove('active');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,19 @@
|
||||||
<section id="groups" class="tab-pane">
|
<section id="groups" class="tab-pane">
|
||||||
<header>
|
<header>
|
||||||
<h2>Group Management</h2>
|
<h2>Group Management</h2>
|
||||||
<button id="btn-refresh-groups" class="primary-btn">Refresh Groups</button>
|
|
||||||
</header>
|
</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">
|
<div class="card">
|
||||||
<table class="data-table">
|
<table class="data-table">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -72,21 +82,6 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</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>
|
</section>
|
||||||
|
|
||||||
<!-- Connected Apps Tab -->
|
<!-- Connected Apps Tab -->
|
||||||
|
|
|
||||||
|
|
@ -189,47 +189,60 @@ app.post('/api/send-message', handleSendMessage);
|
||||||
// Legacy endpoint
|
// Legacy endpoint
|
||||||
app.post('/send-message', handleSendMessage);
|
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' });
|
if (!isReady) return res.status(503).json({ error: 'Not ready' });
|
||||||
try {
|
res.json({ success: true, groups: loadConfiguredGroups() });
|
||||||
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 });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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' });
|
if (!isReady) return res.status(503).json({ error: 'Not ready' });
|
||||||
const { groupId } = req.body;
|
const { link } = req.body;
|
||||||
try {
|
if (!link) return res.status(400).json({ error: 'Link is required' });
|
||||||
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 });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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 {
|
try {
|
||||||
const result = await client.createGroup(title, initialParticipants);
|
let inviteCode = link;
|
||||||
res.json({ success: true, groupId: result.gid._serialized });
|
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) {
|
} catch (err) {
|
||||||
res.status(500).json({ error: err.message });
|
res.status(500).json({ error: err.message || 'Failed to process invite link' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ─── Settings ─────────────────────────────────────────────────────────────
|
// ─── Settings ─────────────────────────────────────────────────────────────
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const SETTINGS_FILE = path.join(__dirname, 'settings.json');
|
const SETTINGS_FILE = path.join(__dirname, 'settings.json');
|
||||||
|
const GROUPS_FILE = path.join(__dirname, 'configured_groups.json');
|
||||||
|
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
if (fs.existsSync(SETTINGS_FILE)) {
|
if (fs.existsSync(SETTINGS_FILE)) {
|
||||||
|
|
@ -242,6 +255,17 @@ function saveSettings(settings) {
|
||||||
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2));
|
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) => {
|
app.get('/api/settings', (req, res) => {
|
||||||
res.json({ success: true, settings: loadSettings() });
|
res.json({ success: true, settings: loadSettings() });
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue