How do you add a role based on a message reaction? - javascript

Is there anything remotely wrong with this code?
no errors pop up and there isn't a reaction once the bot sends the messages.
any help would be appreciated, thank you in advance!
const a = msg.guild.roles.get('666712822985654322'); //Verified User
// the role constants are in the same chronological order as below.
const filter = (reaction,user) => ['668236468384169986'].includes(reaction.emoji.name);
const embed = new Discord.RichEmbed()
.setColor(0x00FF00)
.setTitle('Rules')
.setDescription(`
In order to gain access to the rest of the server you must read and abide by these rules:
By reacting with :white_check_mark: you agree to these rules
Roles:
:white_check_mark: ${a.toString()}`)
.setThumbnail(msg.author.avatarURL)
.addField('Rule #1:You do not talk about fight club', 'Second Rule: You do not TALK about fight club')
.setFooter("Use \'!command list\' to get aquainted with Peb 3000");
msg.channel.send(embed).then(async message => {
await message.react('668236468384169986'); //white check mark
message.awaitReaction(filter, {})
.then(collected =>{
const reaction = collected.first();
switch(reaction.emoji.name) {
case('\:white_check_mark:'):
message.member.addRole(a).catch(err => {
console.log(err);
return message.channel.send(`Error adding you to this role: **${err.message}**`);
});
message.channel.send(`You have been added to the **${a.name}** role!`).then(m => m.delete(3000));
break;
}
}).catch(collected => {
return msg.collected.send(`I couldn't add you to this role!`)
})
});

I'd recommend reading both An Idiot's Guide - Using Emojis as well as Discord.js Guide - Reactions, as your current approach for Unicode emojis won't work.
In your case, :white_check_mark: should be ✅ or an equivalent.

The collected options will triggeret when collector end collect, you no provide any options to stop collector, so its will never happen.
The 1 way to give member role on react follow this code. But when bot restart, you need again use this command and create collector.
const roleToAdd = msg.guild.roles.get('666712822985654322'); //Verified Role
if(!roleToAdd) return
let embed = new Discord.RichEmbed()
.setColor(0x00FF00)
.setTitle('Rules')
.setDescription(`
In order to gain access to the rest of the server you must read and abide by these rules:
By reacting with :white_check_mark: you agree to these rules
Roles:
:white_check_mark: ${a.toString()}`)
.setThumbnail(msg.author.avatarURL)
.addField('Rule #1:You do not talk about fight club', 'Second Rule: You do not TALK about fight club')
.setFooter("Use \'!command list\' to get aquainted with Peb 3000");
msg.channel.send(embed).then(message => {
const filter = (reaction, user) => reaction.emoji.name === '✅' && user.id === msg.author.id && reaction.message.id = message.id
const collector = message.createReactionCollector(filter, {});
collector.on('collect', r => {
if(r.emoji.name === '✅') {
let member = message.guild.members.get(reaction.users.last().id)
member.addRole(roleToAdd)
.then( member => {
message.channel.send(`You have been added to the **${roleToAdd.name}** role!`).then(m => m.delete(3000));
})
.catch(console.error)
}
})
collector.on('end', collected => console.log(`Collected ${collected.size} items`));
})
The way number 2 its listen reactionadd event. After restart its will work.
bot.on('messageReactionAdd', (reaction, user) => {
if(reaction.message.id === 'YOUR MESSAGE ID' && reaction.emoji.name === 'youreactionname') {
let meber = reaction.message.guild.members.get(user.id)
member.addRole('yourRole')
}
.catch(console.error)
});

Related

Unable to find a role by its name

I'm trying to make a command where you can set up an LFG role (LFG = looking for game).
Right now, I need the bot to find a role by its name, but it doesn't work. I have no idea why, I have tried many other thing like finding the role by its ID or structuring the code differently but nothing... Heres is the code:
collector1.on('collect', () => {
// Si l'utilisateur a cliqué sur 1️⃣ LFG
message.reactions.removeAll();
const embed1 = new MessageEmbed()
.setTitle(
`**--------------------LFG role configuration--------------------**`,
)
.addField(
`You clicked on 1️⃣`,
`Send in the next 30 the name of the new LFG role.`,
true,
)
.addField(
`Missclicked?`,
`Wait 30 seconds for the bot to send a timeout message and try again.`,
true,
);
let filter = (m) => m.author.id === message.author.id;
m.edit(embed1).then(() => {
message.channel
.awaitMessages(filter, {
max: 1,
time: 30000,
errors: ['time'],
})
.then((message) => {
message.reactions.removeAll();
message = message.first();
let role = message.guild.roles.cache.find((r) => r.name === message);
message.channel.send(`Alright, The new lfg role is ${role}!`);
})
.catch((collected) => {
message.channel.send('Timeout.');
});
});
});
Also, I have a second problem which is the bot doesn't remove all the reactions.
message is not a string- it's a Message object. I think you meant message.content
let role = message.guild.roles.cache.find((r) => r.name === message.content);
Also, I have a second problem which is the bot doesn't remove all the reactions
Maybe you meant m.reactions.removeAll()?
To find a role by name you can simply use
message.guild.roles.find(role => role.name === "Rolename");

discord.js: How do I replace reactions with buttons in my ticket system?

I am developing my ticketing system in the last time. I saw an update of 'Ticketsbot' and turned curious "how is that possible???, i have never seen that!"
So, can you please help me how can I replace reactions with such buttons.
The part of my code (part which is responsible for reactions):
let embed = new discord.MessageEmbed()
.setAuthor(`Welcome to your ticket!`)
.addField('Here you can:', ':one: Report an issue or bug of the server.\n:two: Suggest any idea for the server.\n:three: Report a staff member of the server.')
.addField('Make sure to be patient, support will be with you shortly.', `<#&837064899322052628>`)
.setColor('#468DFF')
.setFooter(`AftNetwork`)
let embed2 = new discord.MessageEmbed()
.setAuthor(`React with ⛔ if your issue has been resolved.`)
.setColor('#468DFF')
.setFooter(`AftNetwork`)
let reactionMessage = null;
try {
reactionMessage = await channel.send(`${message.author}`, {
embed: embed,
}).then(message => message.channel.send(embed2));
} catch (error) {
console.log(error);
return message.channel.send(
'⚠️ Error sending message in ticket channel!',
);
}
try {
await reactionMessage.react('🔒');
await reactionMessage.react('⛔');
} catch (err) {
console.log(err);
return channel.send('⚠️ Error sending emojis!');
}
const collector = reactionMessage.createReactionCollector(
(reaction, user) => {
// collect only reactions from the original
// author and users w/ admin permissions
const isOriginalAuthor = message.author.id === user.id;
const isAdmin = message.guild.members.cache
.find((member) => member.id === user.id)
.hasPermission('MANAGE_MESSAGES');
return isOriginalAuthor || isAdmin;
},
{ dispose: true },
);
collector.on('collect', (reaction, user) => {
switch (reaction.emoji.name) {
// lock: admins only
case '🔒':
const isAdmin = message.guild.members.cache
.find((member) => member.id === user.id)
.hasPermission('MANAGE_MESSAGES');
if (isAdmin) {
channel.updateOverwrite(message.author, {
SEND_MESSAGES: false,
});
} else {
// if not an admin, just remove the reaction
// like nothing's happened
reaction.users.remove(user);
}
break;
// close: anyone i.e. any admin and the member
// created the ticket
case '⛔':
channel.send('Deleting this ticket in 5 seconds...');
setTimeout(() => channel.delete(), 5000);
break;
}
});
Have a good day!
For now there is no official wrapper so here is an unofficial library that you can use and also here is a small exemple. You can join their discord on the link provided for more help.
let button = new MessageButton()
.setLabel("I like")
.setStyle("blurple")
.setEmoji("🍕")
.setID("like_button")
what you will add is the above code and in the .send() funtion it will be this channel.send(`${message.author}`, {embed: embed, component: button})
and that's basically it.

How would I bypass a cetian role on a cooldown script discord.js/ command that restricts a certain command to a certain channel

This is the current code that I have, I would like to make it where if you have a certain role then you can bypass the cooldown, also if anyone knows how to make a command that restricts a certain command to a certain channel, instead of having this really long message.channel.id.
const Discord = require('discord.js');
const fetch = require('node-fetch');
const talkedRecently = new Set();
module.exports.run = async(client, message, args, queue, searcher, ) => {
if (talkedRecently.has(message.author.id)) {
message.channel.send("Wait 1 minute before getting typing this again. " +'<#'+ message.author.id + '>');
} else {
switch(args[0].toLowerCase()){
case 'neko':
if(message.channel.id === '739002385531404288'||
message.channel.id === '646849145289834506'||
message.channel.id === '785079847763574794'||
message.channel.id === '782891383361896469'||
message.channel.id === '784417039425994772'){
fetch('https://nekos.life/api/v2/img/lewd')
.then(res => res.json())
.then(json => {
let nekoEmbed = new Discord.MessageEmbed()
.setTitle('Lewd Nekos! (=^・ω・^=)')
.setImage(json.url)
message.channel.send(nekoEmbed)
})
}else{
return}}
talkedRecently.add(message.author.id);
setTimeout(() => {
talkedRecently.delete(message.author.id);
}, 60000);
}
}
module.exports.config = {
name: "hentai",
aliases: ['ht']
}
```
Answering Your First Question:
Simply check if the member has a certain role. If they do, construct your if statement so that it will not fire if they have that role
Make sure to use message.member when checking roles
if (talkedRecently.has(message.author.id) && !message.member.roles.cache.has('bypass role id here')) {
// Your cooldown message
}
Learn more about Roles#has
Answering your 2nd question:
You can have an array of channel id's then use includes to check if any of the id's in the array match the current channel id
const ids = ['id1', 'id2', 'id3', 'id4'] // And so on
if (ids.includes(message.channel.id)) {
// Your Code
}
Learn more about Array.prototype.includes

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.js V12 Message Collector "bug"?

I am making a roster command, and this is my code so far, the error is when it comes to the admin it bugs out like in the picture and it doesn't continue... It also saves all of the answers in a file.
So an admin does $roster setup and it starts saving replies for the names of each file. This is the only part I've done for now, so the setup. And I am getting that bug there, there's no error in the console.
client.on('message', async message => {
if (message.content.startsWith(prefix + "roster")) {
if (!message.member.hasPermission('ADMINISTRATOR')) return message.channel.send('You do not have that permission! :x:').then(message.react(':x:'))
if (message.author.bot){}
else {
!fs.existsSync(`./roster/` + message.guild.id) && fs.mkdirSync(`./roster/` + message.guild.id, { recursive: true })
const args = message.content.slice(prefix.length + 7).split(/ +/)
let uReply = args[0];
if(!uReply) return message.channel.send("Please use the following options: `setup`, `send`, `add` or `remove`!")
//SETUP
if(uReply === "setup") {
const collector = new Discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { time: 10000 });
message.channel.send("Please write the exact role name of leader role (with emojis if it has).")
collector.on('collect', message => {
let leaderRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Leader`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the leader role is called \`${leaderRole}\`.`)
collector.off
message.channel.send("Now, whats the role name of co-leader or co-owner role (with emojis if it has)?")
collector.on('collect', message => {
let coleaderRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Co-Leader`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the co-leader/co-owner role is called \`${coleaderRole}\`.`)
collector.off
message.channel.send("Now, whats the role name of admin role (with emojis if it has)?")
collector.on('collect', message => {
let adminRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Admin`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the admin role is called \`${adminRole}\`.`)
collector.off
message.channel.send("Awesome, now whats the role name of staff role (with emojis if it has)?")
collector.on('collect', message => {
let staffRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Staff`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the staff role is called \`${staffRole}\`.`)
collector.off
message.channel.send("Cool, now whats the role name of tiny-staff role (with emojis if it has)?")
collector.on('collect', message => {
let tinyStaffRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Tiny-Staff`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the tiny-staff role is called \`${tinyStaffRole}\`.`)
collector.off
message.channel.send("Just a few more, now whats the role name of higher ranked members role (with emojis if it has)?")
collector.on('collect', message => {
let HigherRankedRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `HigherRanked`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the higher ranked members role is called \`${HigherRankedRole}\`.`)
collector.off
message.channel.send("Last one, whats the role name of the normal members role (with emojis if it has)?")
collector.on('collect', message => {
let NormalMembersRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `NormalMembers`+".txt", message.content, (err) => console.error);
message.channel.send(`Awesome, the normal members role is called \`${NormalMembersRole}\`.`)
message.channel.send("That's it for setup.")
collector.off
})})})})})})})
}
}
}});
Picture:
I believe that the error comes from the original MessageCollector listener not being properly disabled, so the original listener still triggers for each additional message.
It looks like you tried to stop the original listener with collector.off, but because this is a statement instead of a function call, it doesn't do anything. Furthermore, if it did function, it would end the parent collector and none of the subsequent collector.on callbacks would work.
Instead, I would replace the collector.on functions with collector.once and remove the collector.off statements. Changing it to collector.once automatically ends the listener after it receives the first event, which is what you want in this scenario. If you wanted to receive more than one event, you'd have to use something else.
For example, the listener would look something like this:
collector.once('collect', message => {
let leaderRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Leader`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the leader role is called \`${leaderRole}\`.`)
/* ... Rest of code ... */
}

Categories

Resources