Discord Bot in JS not reading reactions - javascript

I am currently developing a Discord bot and I am trying to add a kind of menu as the bot is supposed to be a guide for a game.
To make that work I am trying to add bot messages after reacting to the prior message.
I am testing it on a test message and the bot is supposed to send Test1 if a user reacts with 👍
After reacting, the bot simply does nothing. It doesn't crash nor does it send the intended message.
My code:
case 'Testembed': //Testembed mit Reactions
message.channel.send({embeds: [Testembed.de.data]}).then((question) => {
question.react('🙃')
question.react('👍')
const filter = (reaction, user) => {
return ['👍','🙃'].includes(reaction.emoji.name) && !user.bot;
};
const collector = question.createReactionCollector(filter, { //<-- Here it stops working
max: 1,
time: 15000
});
collector.on('end', (collected, reason) => {
if (reason === 'time') {
message.channel.send('Ran out of time...');
} else {
let userReaction = collected.array()[0];
let emoji = userReaction._emoji.name;
if (emoji === '👍'){
message.channel.send('Test1');
} else if (emoji === '🙃') {
message.channel.send('Test2');
} else {
message.channel.send("I don't understand ${emoji}...");
}
}
});
});
break;
Edit: Bot now throws new error:
throw er; // Unhandled 'error' event
^
TypeError: collected.array is not a function

In discord.js#14.x.x, the method to create a reaction collector changed. Now, the collector would only take one argument and the filter variable would have to be passed in the object. An example would look like this:
const filter = (reaction, user) => {
return ['👍','🙃'].includes(reaction.emoji.name) && !user.bot;
};
const collector = question.createReactionCollector({
max: 1,
time: 15000,
filter
});

Related

Change message with reactions Discord.js

Im a bit new creating Discord bots, my plan with this is to have like a book with the help command that if you press the arrow it changes to the next page, and if you press another arrow it changes to the previus page, I'll simpifly my code to make it more easier to understand.
async execute(message, client){
var msg1 = await message.channel.send('how are')
msg1.react('▶') //send the message
client.on('messageReactionAdd', async (reaction, user) =>{ //wait for the reaction
if(user.bot) return
if (message.reaction.id === msg1.id){
message.channel.messages.fetch(msg1.id).then(msg => msg.delete())
var msg2 = await message.channel.send('you?')
msg2.react('◀') //delete the previus message, send the second and react to it
}
else if (message.reaction.id === msg2.id){
message.channel.messages.fetch(msg2.id).then(msg => msg.delete())
var msg1 = await message.channel.send('how are')
msg1.react('▶') //delete the second message, send the first and react
}
})
}
I know this isnt going to work but i hope you understand the major idea, how can i do this so it actually works?
If you want to listen for reactions to old messages you need to fetch the messageId, etc. This is simple to understand. Here is a Guide.
If you only want it to send a message, react to it, and listen to the next reaction it's easier. There is also a Guide for it.
In your case with the book, I would use the second method and then loop it.
So if someone presses the button it starts the function from the beginning.
This is only an example I never tested it and can't say if it works, It's only made to show you what I meant:
const reactionName1 = '▶';
const reactionName2 = '◀';
const text1= 'How are';
const text2 = 'you?';
module.exports = {
async execute(message, client) {
if(message.author.user.bot) return;
message.channel.send('Hello!').then(msg => {
nextMessage(msg, message.author, reactionName1, text1)
});
},
}
function nextMessage(message, author, reactionName, text) {
message.edit(text).then(() => {
message.react(reactionName);
const filter = (reaction, user) => {
return [reactionName].includes(reaction.emoji.name) && user.id === author.id;
};
message.awaitReactions({ filter, max: 1, time: 60000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
message.reactions.removeAll();
if(reaction.emoji.name === reactionName1) return nextMessage(message, author, reactionName2, text2);
if(reaction.emoji.name === reactionName2) return nextMessage(message, author, reactionName1, text1);
})
.catch(collected => {
message.reactions.removeAll();
return message.edit('You had to press the reaction').then(() => message.delete({ timeout: 4000 })).catch(o_O=>{});
});
});
};
I hope that it was a bit helpful.

Timed Mute Command 'UnhandledPromiseRejectionWarning: DiscordAPIError: Unknown Role' error

I'm making a timed mute command, but i get a lot of errors, the principal one being :
(node:6584) UnhandledPromiseRejectionWarning: DiscordAPIError: Unknown Role
at RequestHandler.execute (c:\Users\user\Desktop\DiscordJSBOT\node_modules\discord.js\src\rest\RequestHandler.js:154:13)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async RequestHandler.push (c:\Users\user\Desktop\DiscordJSBOT\node_modules\discord.js\src\rest\RequestHandler.js:39:14)
at async GuildMemberRoleManager.remove (c:\Users\user\Desktop\DiscordJSBOT\node_modules\discord.js\src\managers\GuildMemberRoleManager.js:125:7)
(Use `node --trace-warnings ...` to show where the warning was created)
Here is the bugged code :
const ms = require('ms');
module.exports = {
name : 'mute',
description: 'Mutes given user',
execute(client, message, args) {
if(!message.member.hasPermission('MUTE_MEMBERS') && message.member.hasPermission('MANAGE_ROLES')) {
return message.reply('You need permissions to use this command !');
}
const target = message.mentions.users.first();
if(target) {
const member = message.guild.members.cache.get(target.id)
if(member) {
const muteRole = message.guild.roles.cache.find(role => role.name === "Muted");
if(muteRole) {
const RoleFolder = []
const roles = member.roles.cache.map(role => role);
roles.forEach(role => {
RoleFolder.push(role.id)
member.roles.remove(role.id)
});
member.roles.add(muteRole.id)
setTimeout(function () {
member.roles.remove(muteRole.id)
RoleFolder.forEach(roles => {
member.roles.add(roles)
})
}, ms(args[1]));
} else {
return message.reply('Make sure you have a role nammed "Muted" when trying to mute a member');
}
} else {
return message.reply('There was an error while attempting to get member object of mentioned user !')
}
} else {
return message.reply('You need a user to mute ! ');
}
}
}
The problem comes from the fact that I get all roles from the user, store it and then give it back. I don't know if there is any other way to do it but that's what I found.
Thanks !
The error DiscordAPIError: Unknown Role is showing up because you are trying to remove a role from a user that the discord API cannot find. This role is the #everyone role which all members have.
You also do not need to run map on the roles, as you can already iterrate over the cache collection.
The code in your question:
const RoleFolder = []
const roles = member.roles.cache.map(role => role);
roles.forEach(role => {
RoleFolder.push(role.id)
member.roles.remove(role.id)
});
Can be changed to:
const RoleFolder = []
member.roles.cache.forEach(role => {
if (role.id === member.guild.id) return;
RoleFolder.push(role.id)
member.roles.remove(role.id)
});
To ignore the role that doesn't exist in the discord API, you can check for:
role.id === member.guild.id or role.rawPosition === 0
You can use return to skip executing code for that particular role, meaning it isn't added to the RoleFolder, and doesn't try to remove the role.
Edit: I would avoid using role.name === '#everyone' as a user can create a role called #everyone and this would be missed, so I have updated my answer to check for a better condition.

How do I edit an embed field with discord.js?

How do I edit an embed field with discord.js?
execute(client, connection, message, args) {
message.channel.send(client.helpers.get('CreateEmptyEmbed').execute("Poll", client, false)
.setTitle('test')
.addField(`0`)
).then(embedMessage => {
embedMessage.react(`✅`)
embedMessage.react(`❎`)
})
client.on('messageReactionAdd', (reaction, user) => {
if (user.id === client.user.id) return // if reaction is == bot return
if (reaction.emoji.name == '✅') message.channel.send(reaction.count)
embed.editfield("hi")
})
Any help would be greatly appriciated.
First of all, client.on('messageReactionAdd') fires for all reactions, and doesn't stop, it keeps firing until you stop the bot, so you need to use a Reaction Collector and to edit embed, you need to change the embeds field and edit the message itself.
execute(client, connection, message, args) {
message.channel.send(client.helpers.get('CreateEmptyEmbed').execute("Poll", client, false)
.setTitle('test')
.addField(`0`)
).then(embedMessage => {
embedMessage.react(`✅`)
embedMessage.react(`❎`)
const filter = (reaction, user) => user.bot!; //Ignores bot reactions
collector = embedMessage.createReactionCollector(filter,{time:15000)) //The time parameter (in milliseconds) specified for how much time the reactionCollector collects reactions
collector.on('collect',(reaction,user)=>{ //When a reaction is collected
const embed = embedMessage.embeds[0] // Get the embed that you want to edit.
embed.fields[0] = {name : 'The name of the new field' , value : 'Value of new field'}
await embedMessage.edit(embed)
})
collector.on('end',()=>{ //When the time we specified earlier is over
//Do stuff
})
})
let filter = m => m.author.id === message.author.id // to ensure same author is responding
message.channel.send(embedMessage).then(() =>{
message.channel.awaitMessages(filter, { // after he sends a message to the same channel
// You can also use ".awaitReactions" if you want to wait for reactions on the message sent
max: 1,// maximum responses
time: 30000,// timeout for waiting
errors: ['time']// type of error
})
.then(message =>{
// do what everyou like with the response
})
.catch(error => console.log)
});

Job Inquiry Bot for Discord.js

I am trying to create a bot that a user can DM to start a "job" inquiry.
Example:
A user messages the bot with !inquiry, then the bot asks questions about the job such as if it's a personal project or for a company, then what is the company or personal projects twitter, it will then ask what type of service they are requesting by supplying options and based on that option the bot will respond with "Please explain what you have in mind for your new xxx job"
Then once the user answers all those questions the bot sends an embed with what they answered.
I was thinking of using MessageCollector but I got stuck with how to do the logic. I have the bot responding to the user so I understand how to send messages through DM to a user. just don't quite understand how to implement the rest. I need a little push.
client.on("message", async (msg) => {
if (!msg.content.startsWith(prefix) || msg.author.bot) return;
if (msg.channel.type === "dm") {
const args = msg.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
const discordUser = msg.author.tag;
if (command !== "order") {
try {
sendFailMessage(msg, "wrongCommand");
} catch (e) {
console.warn("Failed sending Fail Message");
}
} else {
msg.channel.startTyping(1);
msg.author.send();
I've made something similar before so incase you want the full code and context: https://github.com/karizma/ravenxi/blob/master/commands/showcase/apply.js
But here's it rewritten for your context:
(note it's def not optimized since idk your context code, and you are passing variables for every call, but if you know js decently which you should if you are gonna use a libary, it shouldn't be too hard to better the code)
function sendNexQuestion(index, channel, questions, replys) {
return channel.send(questions[index])
.then(() => channel.awaitMessages(() => true, { max: 1, time: 30000, errors: ["time"] }))
.then(reply => {
const content = reply.first().content;
if (content === prefix + "cancel") throw "Self-Cancel";
if (content === prefix + "redo") {
replys.length = 0;
return sendNextQuestion(0, channel, questions, replys);
}
replys.push(content);
return index >= questions.length - 1 ? new Promise(res => res(replys)) : sendNextQuestion(index + 1, channel, questions, replys);
}).catch(err => {
if (err === "Self-Cancel") {
//user canceled
}
channel.send("Application Canceled");
});
}
client.on("message", async (msg) => {
if (!msg.content.startsWith(prefix) || msg.author.bot) return;
if (msg.channel.type === "dm") {
const args = msg.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
const questions = ["Why do you want this?", "Question 2"];
if (command === "inquiry") {
sendNexQuestion(0, msg.channel, questions, []).then(replys => {
//array of replys
})
}
}
});

Sending a DM to people who react to message - Discord JS

I'm trying to send a message to the first 5 people who react to the message, however it only sends a DM to the first person who reacted and does not allow anyone else to react or receive a DM.
How would I do this?
case 'await':
message.channel.sendMessage('React for dm').then(sentMessage => {
sentMessage.react('1️⃣').then(() => sentMessage.react('2️⃣'));
const filter = (reaction, user) => {
return ['1️⃣', '2️⃣'].includes(reaction.emoji.name);
};
sentMessage.awaitReactions(filter, {
max: 1,
time: 60000,
errors: ['time']
})
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '1️⃣') {
message.author.sendMessage('I told you I would!')
}
})
})
You have max: 1 That tells the collector to quit after it has successfully collected 1 reaction. You should set that to 5.
After that you need to loop through the collected to send a DM to all of them rather than using first().

Categories