Cannot get reaction owner - javascript

I wanted to make a command that sends a message when someone reacts on a message with their name, I can't make it get the name of the person that reacted.
if (reaction.emoji.name === firstEmoji) {
await reaction.message.channel.send(`${reaction.message.author.username} reacted!`);
}
This will just say the bot's name and reacted!

Firstly you should provide full code for an accurate answer
Now, once the message is sent and if the bot is reacting to it before the user of course the bot would return itself.
Also for a better approach you can try using reaction collectors
const filter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
const collector = message.createReactionCollector(filter, { time: 15000 });
collector.on('collect', (reaction, user) => {
reaction.channel.send(`Collected ${reaction.emoji.name} from ${user.tag}`);
});

Related

I need get how much reactions has a message in discord.js

I was thinking of code like this to get the number of reactions a message has received after a set time:
if (message.content == "test") {
message.channel.send("Hi").then(msg => {
msg.react('🏠').then(r => {
const react = (reaction, user) => reaction.emoji.name === '🏠'
const collector = msg.createReactionCollector(react)
collector.on('collect', (r, u) => {
setTimeout(() => u.send(r.length), 60000 * 5);
})
})
})
}
});
But rightly .lenght is not the correct method to obtain the number of reactions, consequently the error is that the "r.length" message is empty and the bot cannot send it.
The goal is to send a message, as soon as you react to that message, a setTimeOut starts and at the end of the time it returns (in this case in private) the number of reactions that that message has received.
collected.size is the right way of getting the number of collected reactions a message has.
You can read about reaction collectors here
Here is a basic reaction collector that uses collected.size:
const filter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
const collector = message.createReactionCollector(filter, { time: 15000 });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});

Bot confirmation after user reacts not displaying in Discord.js

I want the user to answer a "yes or no" question using reactions. However, there is a bug in which when the tagged user reacts to the question, the bot is not sending a message on whether or not the tagged user wants to negotiate. Here is my code below.
const yesEmoji = '✅';
const noEmoji = '❌';
client.on('message', (negotiate) => {
const listen = negotiate.content;
const userID = negotiate.author.id;
var prefix = '!';
var negotiating = false;
let mention = negotiate.mentions.users.first();
if(listen.toUpperCase().startsWith(prefix + 'negotiate with '.toUpperCase()) && (mention)) {
negotiate.channel.send(`<#${mention.id}>, do you want to negotiate with ` + `<#${userID}>`)
.then(async (m) => {
await m.react(yesEmoji);
await m.react(noEmoji);
//get an answer from the mentioned user
const filter = (reaction, user) => user.id === mention.id;
const collector = negotiate.createReactionCollector(filter);
collector.on('collect', (reaction) => {
if (reaction.emoji.name === yesEmoji) {
negotiate.channel.send('The mentioned user is okay to negotiate with you!');
}
else {
negotiate.channel.send('The mentioned user is not okay to negotiate with you...')
}
})
})
negotiating = true;
}
})
So far, the code displays the reaction but it does not make the bot send a message whether the tagged user is ok or not ok to negotiate with the user that tagged them.
UPDATE:
I managed to get the bot to send a message whether the tagged user is ok or not ok to negotiate with the user that tagged them. Now there is an error in which is shown after 10 seconds (specified time). Here is the updated code below:
const yesEmoji = '✅';
const noEmoji = '❌';
client.on("message", async negotiate => {
const listen = negotiate.content;
let mention = negotiate.mentions.users.first();
if(listen.toUpperCase().startsWith(prefix + 'negotiate with '.toUpperCase()) && (mention)) {
let mention = negotiate.mentions.users.first();
let msg = await negotiate.channel.send(`${mention} do you want to negotiate with ${negotiate.author}`);
var negotiating = false;
await msg.react(yesEmoji);
await msg.react(noEmoji);
const filter = (reaction, member) => {
return reaction.emoji.name === yesEmoji || reaction.emoji.name === noEmoji && member.id === mention.id;
};
msg.awaitReactions(filter, { max: 1, time: 10000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === yesEmoji) {
negotiating = true;
negotiate.reply('The mentioned user agreed to negotiate with you!');
}
else return negotiate.reply('The mentioned user did not agree to negotiate with you.')
})
}
})
I have a much easier solution to your problem:
const yesEmoji = '✅';
const noEmoji = '❌';
let mention = negotiate.mentions.users.first();
if(mention.id === negotiate.author.id) return message.channel.send("You cannot tag yourself!");
let msg = await negotiate.channel.send(`${mention} do you want to negotiate with ${negotiate.author}`);
var negotiating = false;
await msg.react(yesEmoji);
await msg.react(noEmoji);
const filter = (reaction, member) => {
return (member.id === mention.id && reaction.emoji.name === yesEmoji) || (member.id === mention.id && reaction.emoji.name === noEmoji);
};
msg.awaitReactions(filter, { max: 1, time: 10000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === yesEmoji) {
negotiating = true;
negotiate.channel.send('The mentioned user is okay to negotiate with you!');
}
else if (reaction.emoji.name === noEmoji) return negotiate.channel.send('The mentioned user is not okay to negotiate with you...')
}).catch(err => {
if(err) return message.channel.send(`${mention} did not react within the 10 seconds!`);
})
So first we got the two emojis, we want the user to react with. mention is our mentioned user, msg is the "yes or no" question and negotiating is set to false by default. At first we react to the question with our emojis. In this example I am using awaitReactions, because it is very simple to use. For this we need a filter. In this case I named the variable also filter. filter checks if the reaction wether is yesEmoji or noEmoji and if the user who reacted is mention (our mentioned user). Then in awaitReactions we want only 1 reaction (yes or no), and I set the time to 10 seconds, but you can change it if you want. After awaitReactions is set up we want to collect our reaction. This is done in .then(). collected gives us the reactions, and we only want the first one, so we store collected.first() in reaction. Now we have a really simple if-else statement. If the reacted emoji is yesEmoji, negotiating will be set to true and a message gets sent into the channel, otherwise it will only sent a message and return.
It is important to set negotiating only to true if the user reacted with yesEmoji. In your code it is true even if nothing happens, because as you run the command everything in that command code will be executed. and your last line there was negotiating = true;. And I think that is not what you wanted to do.

Discord Bot, Discord.js | Get bot to send message after clicking reaction

I'm trying to get my first discord bot to send a message after clicking a reaction,
One for yes reaction, one for no
I have my code already send an embed with the reactions
I created a Reaction collector but
the only thing now its that it instantly reacts with (reacted no) twice, even before I click the reaction
Help is greatly appreciated!
My Code so far:
const {Client, RichEmbed } = require('discord.js');
const client = new Client();
const a =
client.once('ready', () => {
console.log('boogie time!');
});
client.on('message', message => {
if(message.author.bot)
{
if(message.embeds)
{
const embedMsg = message.embeds.find(msg=> msg.title ==='Boogie Time!?');
if(embedMsg)
{
embedMsg.message.react('✅')
.then(reaction => reaction.message.react('❌'))
// This is filter, this specified which reactions it should capture, you can use filter to make sure you're only catching specific reactions by specific user
const filter = (reaction, user) => (reaction.emoji.name === '✅' || reaction.emoji.name === '❌') && user.id === message.author.id;
// Here, we're defining a collector that will be active for 30 seconds and collect reactions that pass the above filter
const collector = embedMsg.message.createReactionCollector(filter, {time: 10000});
// This event is emitted when a reaction passes through the filter
collector.on('collect', r => r.name === '✅' ?
console.log('Reacted Yes') : console.log('Reacted No'));
}
}
return;
}
if(message.content.toLowerCase() === 'boogie')
{
const embed = new RichEmbed();
embed.setTitle("Boogie Time!?")
embed.setColor("GREEN")
embed.setDescription("Are you sure?")
message.channel.send(embed);
};
});
You have a several problems here. The first issue is you are only looking at messages sent by a bot if(message.author.bot) and then later trying to filter by that message author which will always be a bot, not you or anyone else user.id === message.author.id. I think your intention may have been to not collect bot reactions.
The second issue you have is that the asynchronous execution is causing the collector to get created before the bot adds the initial reaction.
embedMsg.message.react('✅')
.then(reaction => reaction.message.react('❌'))
After this call to .react, the code below it starts immediate async execution, before the reactions complete. If you aren't listening to the bots reaction this shouldn't be an issue, but if you enclose the collector creating in a second .then statement it will ensure it doesn't create it until the second reaction is complete and you won't need to filter the user.id because the bot shouldn't react after that, thus eliminating both problems.
So the cause of the problem is the bot is collecting it's own two reactions. Why is it always saying 'React No' then?
This is the third issue:
collector.on('collect', r => r.name === '✅' ?
console.log('Reacted Yes') : console.log('Reacted No'));
Here you have forgotten to call out the reactions emoji. This line should be:
collector.on('collect', r => r.emoji.name === '✅' ?
console.log('Reacted Yes') : console.log('Reacted No'));
In conclusion, this should be the changes described above:
if(embedMsg)
{
embedMsg.message.react('✅')
.then(reaction => reaction.message.react('❌')
.then(() => {
// This is filter, this specified which reactions it should capture, you can use filter to make sure you're only catching specific reactions by specific user
const filter = (reaction, user) => (reaction.emoji.name === '✅' || reaction.emoji.name === '❌');
// Here, we're defining a collector that will be active for 30 seconds and collect reactions that pass the above filter
const collector = embedMsg.message.createReactionCollector(filter, {time: 10000});
// This event is emitted when a reaction passes through the filter
collector.on('collect', r => r.emoji.name === '✅' ?
console.log('Reacted Yes') : console.log('Reacted No'));
}));
}

Is it possible te get a user from the ReactionCollector in Discord.js?

It's about one month that i'm actively developing a Discord bot but I have a problem about grabbing users from a reaction with the ReactionCollector
I know that you can catch this with this example :
bot.on('messageReactionAdd',(reaction,user)=>{
console.log(user); //Return the user
console.log(reaction); //Return the Reaction
});
But I want to create a complex system and I don't know if it's possible or not to grab the user with the ReactionCollect to do something that would look like this :
let reactionCollector = new Discord.ReactionCollector(messagefilteroptions);
reactionCollector.on('collect', (reactions,user,collector)=>{
console.log(user); //Return the User
console.log(reaction); //Return the Reaction
console.log(collector); //Return the Collector
});
How do I solve the problem?
Answer for V11
for v12, see tipakA answer
A ReactionCollector is used to wait for a specific condition about reactions on a messages (a number of reactions, a certain time, ...). You have access to the reactions after the collector has collected the reactions.
You have an example here:
const filter = (reaction, user) => {
return reaction.emoji.name === '👌' && user.id === message.author.id;
};
const collector = message.createReactionCollector(filter, { time: 15000 });
collector.on('collect', (reaction, reactionCollector) => {
console.log(`Collected ${reaction.emoji.name}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
The collector will collect all 👌 reactions. For every reactions, it will log the name of the emoji, and after 15 secondes, it will log how many reactions were added.
However, we can't access the user who reacted during the collect because the reaction is a MessageReaction. This type has a property which list all the users who reacted, because it's linked to the message and not the event which was fired when someone clicked.
note: you can access the last user by browsing the users Collection. Since it extend the Map, it remembers the original insertion order of the keys. But it will work only for one reaction.
However, the filter function has a user and a reaction. The filter function is used to filter what type of reaction you want to collect (for example, only from people with a specific role, or only one type of reaction, ...).
Here, if you want to log the user, you can do something like this:
const filter = (reaction, user) => {
console.log(user);
return reaction.emoji.name === '👌' && user.id === message.author.id;
};
However, if you want to do something with the users who reacted, you can do it after the collector has finished collecting the reactions:
collector.on('end', collected => {
console.log(collected.forEach((reaction => reaction.users.forEach(console.log))));
});
Depending on what type of reactions you're waiting, you will maybe have to verify the users hasn't already reacted to another reactions on the message (to avoid using it twice).
Use the ReactionCollector if you have to wait reactions on a particular messages. If you want to use it for every messages, use bot.on('messageReactionAdd',...)
Previous answers are outdated by now, as they are for version 11 of Discord.js.
Version 12 was released since then, and as it brings multiple changes, Collectors also got a "refresh".
Now, the collect event on ReactionCollector instead of giving reaction and collector itself, gives reaction and user objects.
const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === message.author.id;
const collector = message.createReactionCollector(filter, { time: 10000 });
collector.on('collect', (reaction, user) => {
console.log(`${user.tag} reacted with ${reaction.emoji.name}.`);
});
This is a bit late, but you could put your code in the filter and use that instead of on collect
const filter = (reaction, user) => {
console.log(user);
if(return reaction.emoji.name === '👌' && user.id === message.author.id) {
// Your code :)
}
return reaction.emoji.name === '👌' && user.id === message.author.id;
};

Having trouble with await reactions

I want the bot to delete it's message after a user reacts to the message with a specific emoji. When I tried this with the code below, nothing happens. No errors whatsoever. I also don't want a time limit, just do a thing when it gets one reaction. Current code:
const filter = (reaction, user) => {
return ['🗑'].includes(reaction.emoji.name) && user.id === message.author.id;
};
message.awaitReactions(filter, { max: 1})
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '🗑') {
sentMessage.delete(1000)
} else {
message.reply('you reacted with a thumbs down.');
}
})
.catch(collected => {
console.log(`After a minute, only ${collected.size} out of 4 reacted.`);
message.reply('you reacted with neither a thumbs up, nor a thumbs down.');
what does your filter look like? We con't see the first line of it. Your problem is that you try to check the emote twice. Once in the filter and then again in the function. Only use the filter here, or use the function if you want multiple emotes (i wouldn't recommend it).
my solution would look like this:
var message = msg.channel.send("test message");
const filter = (reaction, user) => reaction.emoji.name === ':ok_hand:' //whatever emote you want to use, beware that .await.Reactions can only check a singel emote
message.then(m=>{m.awaitReactions(filter, { max: 1})
.then(collected => {
console.log("do what ever");
m.delete();//such as this
})
.catch(console.error);
});
This works for me. Keep in mind that #awaitReactions isn't very versatile. If you want multiple ways of interacting with a message, you may want to look at #createReactionCollector which works the same way, but is triggered on every emote change instead.
I hope I helped.

Categories

Resources