How can I make my bot respond on reactions? - javascript

I'm currently trying to make a ticket system on my bot with reactions, it shows no error but when I react it won't give out the "Hi" output, my code is the following:
client.on("ready", async () => {
const guild = client.guilds.cache.get("my server ID")
const channel = guild.channels.cache.get("the channel ID")
const message = guild.channels.cache.get("the same channel ID").send(new Discord.MessageEmbed()
.setAuthor("Tickets", guild.iconURL({ dynamic: true })).setDescription("React to the emoji below to start a ticket")).then(sent => {
sent.react("✉️")
const filter = (r, u) => r.emoji.name === "✉️";
const collector = sent.createReactionCollector(filter, { max: 1 });
collector.on("collect", (r, u) => {
if(u.bot) return null;
else channel.send("Hi")
})
})
})

The reason why the bot won't respond is that it has already collected the ✉️ in the message from the bot itself, thus it has reached its max of 1 reaction. But it checks that u.bot is indeed true (in the collect event), and thus will not respond at all.
To fix this, you can remove if(u.bot) return null; inside of the collection event, and put it in the filter instead, like this:
const filter = (r, u) => r.emoji.name === "✉️" && !u.bot;

Related

Discord.js not sending message for a specific role

I'm making a system for a position, where you get an achievement for a position, I want to warn such a user that when he wins the position he won the achievement, but I don't know how to do it, so I improvised the command below!
const client = require("../index.js")
const wait = require('util').promisify(setTimeout);
client.on('messageCreate', async message => {
const member = await message.guild.members.fetch({
user: message.user.id,
force: true
})
var canal = message.guild.channels.cache.find(ch => ch.id === "980553632116269080");
if(!member.roles.cache.has("980553630782464068")) {
await member.roles.cache.get("980553630782464068")
return message.member.send(`${client.emoji.success} We Have Added PlayStation Role`)
}
})
I want him to be like this
https://i.stack.imgur.com/ocALk.jpg

Message collector responds to other people's messages

I'm trying to make a collector which will collect the mentioned user's message. But even with filter my bot respond to it's own message and other peoples messages! Here is my test.js file code:
const mentioned = message.mentions.users.first();
const filter1 = (msg) => {
return msg.author.id === mentioned.id
}
const collector1 = await message.channel.createMessageCollector({ filter1, max: 1, time: 120000 })
collector1.on('collect', message => {
console.log(message.content)
})
collector1.on('end', (collected) => {
if (collected.size === 0) return message.channel.send("Mentioned user did not respond in time!")
collected.forEach((message) => {
if (message.content.toLowerCase() == 'accept') {
message.channel.send(`${mentioned} accepted!`)
}
if (message.content.toLowerCase() == 'cancel') return message.channel.send(`${mentioned} declined!`)
})
})
I was changing my filter many times, but I still can't fix this problem, so what am I doing wrong?
Also I use djs v13
The problem is you're trying to use Short-Hand Property Assignment to assign the filter option. However, you pass in "filter1" which results in {filter1: filter1}. Since this does not resolve to a filter option for TextChannel#createMessageCollector() the method disregards the unknown option and therefor your collector has no filter.
Change your filter1 variable to filter
const filter = (msg) => {
return msg.author.id === mentioned.id
}
const collector1 = await message.channel.createMessageCollector({ filter, max: 1, time: 120000 })

Discord js direct message await not working

So my discord bot asks a user in DM for an API secret. I want to await the user's response so that I can do further things with my key.
From client.on('messageCreate') after a user requests to add key I call this function
async function takeApiSecret(msg) {
const botMsg = await msg.author.send("Please provide your api secret");
const filter = collected => collected.author.id === msg.author.id;
const collected = await botMsg.channel.awaitMessages(filter, {
max: 1,
time: 50000,
}).catch(() => {
msg.author.send('Timeout');
});
However I am not able to await the user's response and collect it. Instead when I reply I get another message on my client.on('messageCreate'). Any leads what I could be doing wrong?
In discord.js v13.x, the parameters of awaitMessages() changed a little bit. There are no longer separate parameters for filter and options; filter is now contained within options. This should fix your problem:
const filter = collected => collected.author.id === msg.author.id;
const collected = await botMsg.channel.awaitMessages({
filter,
max: 1,
time: 50000,
}).catch(() => {
msg.author.send('Timeout');
});
You can find the documentation here. For some reason, the options do not appear to be fully documented, but you can view the example on that page to see the new format.
Additionally, if this code is called whenever a message is sent via DM, you may need to prevent collected messages from triggering the rest of your messageCreate event listener code. Here's one way you could do that:
Outside messageCreate handler:
const respondingUsers = new Set();
Right before awaitMessages()
respondingUsers.add(msg.author.id);
Inside your .then() and .catch() on your awaitMessages():
respondingUsers.delete(msg.author.id);
Near the top of your messageCreate handler, right after your other checks (e.g. checking if the message is a DM):
if (respondingUsers.has(msg.author.id)) return;
If we put all of this together, it may look something like this (obviously, modify this to work with your code):
const respondingUsers = new Set();
client.on('messageCreate', msg => {
if (msg.channel.type != "DM") return;
if (respondingUsers.has(msg.author.id)) return;
respondingUsers.add(msg.author.id);
const filter = collected => collected.author.id === msg.author.id;
const collected = botMsg.channel.awaitMessages({
filter,
max: 1,
time: 50000,
})
.then(messages => {
msg.author.send("Received messages");
respondingUsers.delete(msg.author.id);
})
.catch(() => {
msg.author.send('Timeout');
respondingUsers.delete(msg.author.id);
});
})

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.

Categories

Resources