How to detect when a reaction has occured? - javascript

I currently have a Discord bot which reads information of a API that deals with a game server panel.
In this Bot there is tasks that are to start/restart/stop/kill the server. i want to give the option for the end user to react to a embed posted by a bot with a certain reaction to trigger these tasks.
The Command and embed that are posted by the bot are:
The code which currently checks which reaction has been triggered looks like this:
message.channel.send(embed).then(async (sentEmbed) => {
sentEmbed.react("🟩")
sentEmbed.react("🔁")
sentEmbed.react("🟥")
sentEmbed.react("❌")
const filter = (reaction, user) => {
console.log(reaction.emoji.name)
return reaction.emoji.name === '🟩' && user.id === message.author.id;
};
const collector = sentEmbed.createReactionCollector(filter, {time: 20000});
collector.on('collect', (reaction, user) => {
Client.startServer(args[0]).then((response) => {
const start_embed = new Discord.MessageEmbed()
.setTitle(response)
.setColor(settings.embed.color.default)
.setFooter(settings.embed.footer);
message.channel.send(start_embed);
}).catch((error) => {
message.channel.send(client.embederror(error))
});
});
const filter2 = (reaction, user) => {
return reaction.emoji.name === '🔁' && user.id === message.author.id;
};
const collector2 = sentEmbed.createReactionCollector(filter2, {time: 20000});
collector.on('collect', (reaction, user) => {
Client.restartServer(args[0]).then((response) => {
const restart_embed = new Discord.MessageEmbed()
.setTitle(response)
.setColor(settings.embed.color.default)
.setFooter(settings.embed.footer);
message.channel.send(restart_embed);
}).catch((error) => {
message.channel.send(client.embederror(error))
});
});
const filter3 = (reaction, user) => {
return reaction.emoji.name === '🟥' && user.id === message.author.id;
};
const collector3 = sentEmbed.createReactionCollector(filter3, {time: 30000});
collector.on('collect', (reaction, user) => {
console.log(`User Stopped There Server`);
});
const filter4 = (reaction, user) => {
return reaction.emoji.name === '❌' && user.id === message.author.id;
};
const collector4 = sentEmbed.createReactionCollector(filter4, {time: 30000});
collector.on('collect', (reaction, user) => {
console.log(`User Killed There Server`);
});
})
This code works for detecting the reactions onto the message, however when a user reacts with any reaction it runs all of the trigger code, so the bot posts two embeds which i have defined as what the bot should output when a reaction is triggered.
I just want the user to click one reaction, then the bot does something, then the use can click another and the bot does something else.
Thanks in advance

The issue was you used collector.on("collect") 4 times instead of using collector2, collector3 and collector4
It's best not to have variables like that since like it shows you might get confused
Plus you should not have 4 different filters and collectors, especially since you repeat a lot of the code
const validEmojis = ['🟩', '🔁', '🟥', '❌'];
const filter = (reaction, user) => {
return validEmojis.includes(reaction.emoji.name) && user.id === message.author.id;
};
const collector = sentEmbed.createReactionCollector(filter, { time: 20000, maxEmojis: 1 });
collector.on('collect', (reaction, user) => {
const name = reaction.emoji.name;
//you only use it in two cases but I assume you will use it for all later on
const embed = new Discord.MessageEmbed()
.setColor(settings.embed.color.default)
.setFooter(settings.embed.footer);
if (name === '🟩' || name === '🔁') {
const method = name === '🟩' ? "startServer" : "restartServer";
Client[method](args[0])
.then(response => {
embed.setTitle(response);
message.channel.send(start_embed);
}).catch((error) => {
message.channel.send(client.embederror(error))
});
} else if (name === '🟥') {
console.log(`User Stopped There Server`);
} else if (name === '❌') {
console.log(`User Killed There Server`);
}
});

Related

How do I delete a user's new message

I'm pretty trash at coding so I need a little bit of help. I'm trying to code my discord bot to delete someone's messages for one minute after they click a react emoji. It sounds simple but for my tiny pea brain, it's not. This is what I have got so far. It deletes all messages from different users and guilds it's in, forever. I want it so it only delete messages in one channel for one minute.
client.once('message', async userMessage => {
if (userMessage.content.startsWith(''))
{
botMessage = await userMessage.channel.send('Who here likes goats?')
await botMessage.react("👍")
await botMessage.react("👎")
const filter = (reaction, user) => {
return (
["👍", "👎"].includes(reaction.emoji.name) && user.id === userMessage.author.id
);
};
botMessage
.awaitReactions(filter, { max: 1, time: 60000, errors: ["time"] })
.then((collected) => {
const reaction = collected.first();
if (reaction.emoji.name === "👎") {
userMessage.channel.send(`${userMessage.author}, how dare you. I guess no on here likes me. Hmmm, because of that I shall now eat all your messages! BAAAAAHAHAHHAHAHA!`)
setTimeout(() => {
client.on("message", async msg => {
if (author.msg.content.startsWith("")) {
userMessage.channel = await msg.delete();
}
});
}, 2000);
} else {
userMessage.reply("Thanks!");
}
})
.catch((_collected) => {
userMessage.channel.send("Hehe")
});
}
});
Btw, the code is in discord.js!
Your problem is this chunk of code
setTimeout(() => {
client.on("message", async msg => {
if (author.msg.content.startsWith("")) {
userMessage.channel = await msg.delete();
}
});
}, 2000);
This is not how you use events.
A) Your message event is nested within another which could cause memory leaks.
B) To get the content you need to use msg.content, author.msg Is not a thing.
C) I assume your intention here: msg.content.startsWith("") is to always fire the if statement, in that case why not do if (true).
Here's how I would do it:
Create a Set in the namespace which will hold id's of users who's messages should be deleted
const toDelete = new Set();
If they react with a 👎 add them to the set.
if (reaction.emoji.name === "👎") {
userMessage.channel.send('Your message here');
if (!toDelete.has(userMessage.author.id)) {
toDelete.add(userMessage.author.id);
}
}
On each message event check if the author of the message has their id in the set, If so delete their message
client.once('message', async userMessage => {
if (toDelete.has(userMessage.author.id)) {
return userMessage.delete()
.catch(console.error);
}
if (userMessage.content.startsWith('')) {
// Rest of your code
I think your problem in understanding how everything works.
I took everything from discord.js documentation.
Type reaction command to see how it works.
const Discord = require("discord.js");
require("dotenv").config();
const TOKEN = process.env.TOKEN||"YOUR TOKEN";
const PREFIX = process.env.PREFIX||"YOUR PREFIX";
const bot = new Discord.Client();
bot.on("ready", async function(e) {
console.log("Loaded!");
})
bot.on("message", async function(message) {
if (message.author.bot) return;
if (!message.content.startsWith(PREFIX)) return;
let args = message.content.slice(PREFIX.length).trim().split(/\s+/);
let command = args.splice(0, 1).toString().toLowerCase();
if (command == "reaction") {
message.delete();
let msg = await message.channel.send("Click on the reaction");
await msg.react("👍");
await msg.react("👎");
let filter = (reaction, user) => {
return ["👍", "👎"].includes(reaction.emoji.name) && user.id == message.author.id;
}
msg.awaitReactions(filter, {max: 1, time: 10000, errors: ["time"]}).then(collected => {
let reaction = collected.first();
if (reaction.emoji.name == "👎") {
return message.channel.send("downvote");
}
return message.channel.send("upvote");
}).catch(e => {
message.channel.send("user didn't vote");
})
}
})
bot.login(TOKEN);

How to move back and forth for help page using awaiting reactions discord.js

This is my sample code:
const Discord = require('discord.js')
module.exports = {
name: 'help',
description: 'help',
execute(message, args) {
const embed = new Discord.MessageEmbed()
.setTitle('Page One')
.setDescription('This is page one')
message.channel.send(embed).then((msg) => {
msg.react('⬅️')
msg.react('➡️')
const filter = (reaction, user) => {
return ['⬅️', '➡️'].includes(reaction.emoji.name) && user.id === message.author.id;
};
msg.awaitReactions(filter, { max: 1, time: 60000, errors: ['time'] })
.then(collected => {
const reaction = collected.first()
if (reaction.emoji.name === '⬅️') {
message.channel.send(embed)
}
else {
const secEmbed = new Discord.MessageEmbed()
.setTitle('Help')
.setDescription('This is help page 2')
msg.edit(secEmbed);
}
})
})
}
}
This is working, but when i try to move it backwards to the previous page after i have moved to the second page, the thing stops working.... I meant, then the embed pages won't move forth or back. Is there anyway to solve this prob? Thank You.
You could simply call msg.awaitReactions() again; wrap it in a function to make it easier to repeat the reaction collection.
Using msg.awaitReactions():
message.channel.send(embed).then((msg) => {
msg.react("⬅️");
msg.react("➡️");
function handleReactions() {
const filter = (reaction, user) => {
return ['⬅️', '➡️'].includes(reaction.emoji.name) && user.id === message.author.id;
};
msg.awaitReactions(filter, {max: 1, time: 60000, errors: ["time"]})
.then((collected) => {
const reaction = collected.first();
const name = reaction.emoji.name;
if (name === "⬅️") {
// edit page a certain way
handleReactions();
} else if (name === "➡️") {
// edit page another way
handleReactions();
}
});
}
handleReactions();
});
Another way would be to listen for reaction events:
message.channel.send(embed).then((msg) => {
msg.react("⬅️");
msg.react("➡️");
// handles reactions
function handleReaction(reaction, user) {
// ignore the reaction if the reaction is on a different message
if (reaction.message.id !== msg.id && user.id === message.author.id) {return;}
const name = reaction.emoji.name;
if (name === "⬅️") {
// move page a certain way
} else if (name === "➡️") {
// move page another way
}
}
// add a listener for message reactions
message.client.on("messageReactionAdd", handleReaction);
// wait a specific amount of time to stop listening
setTimeout(() => {
// remove the listener
message.client.off("messageReactionAdd", handleReaction);
}, 60000); // 60 seconds
/*
You could add functions to reset the timeout after each reaction as well.
*/
});

Creating Discord.js pagination and getting error with 'channel'

so i'm trying to make pagination of embeds (pages) and I'm having a problem.
TypeError: Cannot read property 'channel' of undefined
I'm kinda still new at Discord.js, any help would be apresuated
client.on('message', async (client, message, args, tools) => {
let pages = ['page one', 'second', 'third', 'you can add pages', 'all you need to do is add another item in the array', '**Supports markdown and regular chat description properties**'];
let page = 1;
const embed = new Discord.MessageEmbed()
.setColor('red')
.setFooter(`Page ${page} of ${pages.length}`)
.setDescription(pages[page-1])
message.channel.send(embed).then(msg => {
msg.react('⏮️').then(r => {
msg.react('⏭️')
const backwardsFilter = (reaction, user) => reaction.emoji.name === '⏮️' && user.id === message.author.id;
const forwardsFilter = (reaction, user) => reaction.emoji.name === '⏭️' && user.id === message.author.id;
const backwards = msg.createReactionCollector(backwardsFilter, { time: 60000 });
const forwards = msg.createReactionCollector(forwardsFilter, { time: 60000 });
backwards.on('collect', r => {
if (page ===1) return;
page--;
embed.setDescription(pages[page-1]);
embed.setFooter(`Page ${page} of ${pages.length}`)
msg.edit(embed)
})
forwards.on('collect', r => {
if (page === pages.length) return;
page++;
embed.setDescription(pages[page-1]);
embed.setFooter(`Page ${page} of ${pages.length}`);
msg.edit(embed)
})
})
})
})

Discord.js execute function when replying with emoji

Currently, I am using Discord.js to make a bot.
client.on('message', (message) => {
if (message.content === '$wa') {
message.channel.send({ embed: exampleEmbed }).then((embedMessage) => {
embedMessage.react('❤️');
embedMessage
.awaitReactions(
(filter = (reaction, user) => {
return reaction.emoji.name === '❤️' && user.id === message.author.id;
}),
{ max: 2, time: 60000, errors: ['time'] }
)
.then((collected) => {
const reaction = collected.first();
if (reaction.emoji.name === '❤️') {
message.channel.send(
':sparkling_heart: **Hanno** and **Roronoa Zoro** are now married! :sparkling_heart:'
);
}
});
});
}
});
If I type $wa the bot shows some embed. But the thing is that it automatically adds a heart to the embed. I want that if I click the heart as well (for a total count of 2 hearts) it executes the if statement at the bottom.
I've tried multiple methods but none worked. This is also my first time with Discord.js
You need to account for the bots own reaction. I recommend redoing your filter implementation to something like this.
The key takeaway is that you have to add !user.bot to the filter so that the bot's own reaction is ignored
const filter = (reaction, user) => {
return reaction.emoji.name === "❤️" && user.id === message.author.id && !user.bot
}
embedMessage.awaitReactions(filter, { max: 1, time: 60000, errors: ['time'] })
Please try this:
client.on('message', message => {
if (message.content === '$wa') {
message.channel.send({ embed: exampleEmbed }).then(embedMessage => {
embedMessage.react('❤️');
embedMessage.awaitReactions(filter = (reaction, user) => {
return reaction.emoji.name === '❤️' && user.id === message.author.id;
},
{ max: 1, time: 60000, errors: ['time'] }).then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '❤️') {
message.channel.send(':sparkling_heart: **Hanno** and **Roronoa Zoro** are now married! :sparkling_heart:');
}
}).catch(() => {
// user didn't react with ❤️ in given time (here: 60 secs)
message.channel.send('no reaction in time');
});
});
}
});
I changed the max value to 1 and also added a catch block to catch a UnhandledPromiseRejectionWarning. If you don't do so in the future, it might exit the program with an error. You can of course execute whatever you like when the user didn't react to the embedMessage in time.

How to use awaitReactions in guildMemberAdd

I send messages to users when they connect to my server, and I want to continue authorization by clicking on reactions.
How can I create this? I'm using the following code:
robot.on("guildMemberAdd", (gMembAdd) =>
{
gMembAdd.send(`Hi ${gMembAdd.toString()} welcome to the server Test`).then(msg => {
msg.react('✅')
.then(() => msg.react('❎'));
//--------------------Developmend-------------------------------------
let filter = (reaction, user) => reaction.emoji.name === '✅' || reaction.emoji.name === '❎';
let col = msg.createReactionCollector(filter);
col.on('collect', r =>
{
if (r.users.last().id !== msg.author.id)
{
gMembAdd.addRole(gMembAdd.guild.roles.find("name", "Autorize")).catch(console.error)
r.remove(r.users.last().id);
console.log(` ${gMembAdd.user.id} и ${gMembAdd.user.username} and ${r.emoji}`);
}
});
//--------------------------------------------------------------------
});
I need a reaction check and role assignment if the response is positive and kick if not. I don't understand how to continue.
Will this code be used correctly?
To check the reaction you can use MesssageReaction.emoji.name, as you did above.
For the other thing, you can use GuildMember.addRole() & GuildMember.kick().
Here's a sample you can check out:
robot.on('guildMemberAdd', async member => {
let msg = await member.send(`Hi ${member} welcome to the server Test`);
await msg.react('✅');
await msg.react('❎');
msg.createReactionCollection(r => ['✅', '❎'].includes(r.emoji.name))
.on('collect', r => {
if (r.emoji.name == '✅')
member.addRole(member.guild.roles.find("name", "Authorize"))
.then(() => { console.log(`Added ${member.user.username} (${member.id}).`); })
.catch(console.error);
else if (r.emoji.name == '❎') member.kick("You got rejected.");
r.remove(r.users.last());
});
});
You can also use Message.awaitReactions(), which is better because it doesn't go on after the reaction is added:
robot.on('guildMemberAdd', async member => {
let msg = await member.send(`Hi ${member} welcome to the server Test`);
await msg.react('✅');
await msg.react('❎');
msg.awaitReactions(r => ['✅', '❎'].includes(r.emoji.name), {max: 1})
.then(collected => {
let r = collected.first();
if (r.emoji.name == '✅')
member.addRole(member.guild.roles.find("name", "Authorize"))
.then(() => { console.log(`Added ${member.user.username} (${member.id}).`); })
.catch(console.error);
else if (r.emoji.name == '❎') member.kick("You got rejected.");
r.remove(r.users.last())
});
});

Categories

Resources