Creating a menu like structure (discord.js) - javascript

I wanted to create a menu of items that the bot can do and then the user can select the operation to perform.
For example:
When I say +Menu then the bot shows something like:
1. Time in NY
2. Movies currently running
3. Sports News
Then I wanted to take the user's input (1,2 or 3) and then based on their selection, the bot will execute the task.
But I am not sure how to read the user's input after the command (+Menu) and wanted to ask for help.

You are looking for a message collector. See the docs here
Personally I would create an embed with the options in it e.g.
const menuEmbed = new Discord.MessageEmbed()
.setTitle("Menu")
.addFields(
{ name: "1.", value: "Time in NY"},
{ name: "2.", value: "Movies currently running"},
{ name: "3.", value: "Sports News"}
);
message.channel.send(menuEmbed).then(() => {
const filter = (user) => {
return user.author.id === message.author.id //only collects messages from the user who sent the command
};
try {
let collected = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
let choice = collected.first().content; //takes user input and saves it
//do execution here
}
catch(e)
{
return message.channel.send(`:x: Setup cancelled - 0 messages were collected in the time limit, please try again`).then(m => m.delete({ timeout: 4000 }));
};
});
Then use a collector to let the user choose an option.
Bear in mind this is using async/await and must be in an async function.

Related

Regarding Discord.js v13 ticket bot's add user command

Alright so, I've been working on a fork of a ticket bot src from github, It had one flaw, the same flaw i've been trying to fix for around two days now. I'm quite a beginner and i like poking around with src's off of github and i wanted to fix this issue.
The Bug
Basically this is a ticket bot. Once a user creates a ticket, the bot creates a channel and pings the support team role, works fine so far. You can use the /add (target) command to add another user to the ticket channel. That also works. But when you use the command for a second time, It replaces the previously added user with the new user passed in the argument. I've been looking at docs and other src's quite a bit for hours and I just couldn't figure this out for some reason.
Expected Output
The expected output goes something like this.
/add (target1) - User gets added to the ticket channel
/add (target2) - The user gets added to the ticket channel and also keeps the other user in.
The Code Snippet
const {
SlashCommandBuilder
} = require('#discordjs/builders');
module.exports = {
data: new SlashCommandBuilder()
.setName('add')
.setDescription('Add a user')
.addUserOption(option =>
option.setName('target')
.setDescription('Member to be added to the ticket.')
.setRequired(true)),
async execute(interaction, client) {
const chan = client.channels.cache.get(interaction.channelId);
const user = interaction.options.getUser('target');
if (chan.name.includes('ticket')) {
chan.edit({
permissionOverwrites: [{
id: user,
allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'],
},
{
id: interaction.guild.roles.everyone,
deny: ['VIEW_CHANNEL'],
},
{
id: client.config.roleSupport,
allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'],
},
],
}).then(async () => {
interaction.reply({
content: `<#${user.id}> has been added!`
});
});
} else {
interaction.reply({
content: 'you don\'t have a ticket!',
ephemeral: true
});
};
},
};
I'd really appreciate some help with this, Please excuse my inexperience guys! Thanks in advance and have a nice day.

Discord js v12 Add rights to a channel if user reacts to a specific message

I have a problem that I can't solve:
Every time someone reacts to a specific message a channel gets created, and then the person who reacted first is the only one who has the permissions to see this channel. I set the max amount of reactions to "2", and I want it so that the second person who reacts with the message also gets permissions to see the created channel, but I don't know how to do it. Does somebody has an example?
This is what I currently have:
message.guild.channels.create("Busfahrer", {
type: "text",
parent: category,
permissionOverwrites: [
{
id: message.guild.id,
allow: ['SEND_MESSAGES', 'EMBED_LINKS', 'ATTACH_FILES', 'READ_MESSAGE_HISTORY'],
deny: ['VIEW_CHANNEL'],
}
]
})
Keep track of who reacts first and second and only give it to the second person:
const collector = reactionMessage2p.createReactionCollector(filter2p, {max: 2, time: 20000, errors: ['time'] })
let reactedUsers = []
collector.on("collect", (reaction, user) => {
reactedUsers.push(user.id)
})
collector.on("end", async () => {
let targetUser = reactedUsers[1]
// channel is the channel you create
channel.updateOverwrite(targetUser, {
VIEW_CHANNEL: true
})
})
I got some of this code from your other question

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);
});
})

Get count of member's messages in channel in discord.js

Is there any way how to count messages of specified user in specified Discord channel in discord.js? When I use:
const countMyMessages = async (channel, member) => {
const messages = await channel.messages.fetch()
const myMessages = message.filter(m => m.author.id === member.id)
console.log(myMessages.size)
}
Only 50 messages are fetched, so I can't count all messages of user. And option limit can have max value 100. /guilds/guild_id/messages/search API on the other hand is not available for bots.
You will need to use a storage system to keep this kind of statistics on Discord.
I recommend you to use SQLite at first (like Enmap npm package).
I can quickly draw a structure for you based on this one.
const Enmap = require("enmap");
client.messages = new Enmap("messages");
client.on("message", message => {
if (message.author.bot) return;
if (message.guild) {
const key = `${message.guild.id}-${message.author.id}`;
client.messages.ensure(key, {
user: message.author.id,
guild: message.guild.id,
messages: 0
});
client.messages.inc(key, "messages");
// Do your stuff here.
console.log(client.messages.get(key, "messages"))
}
});

I'm trying to create a channel named like user args. [DISCORD.JS V12]

It just gives me an error that the function message.guild.channels.create does not work because it's not a correct name.
My intention is to create a command where you will be asked how the channel you want to create be named. So it's ask you this. After this you send the wanted name for the channel. Now from this the bot should name the channel.
(sorry for bad english and low coding skills, im a beginner)
module.exports = {
name: "setreport",
description: "a command to setup to send reports or bugs into a specific channel.",
execute(message, args) {
const Discord = require('discord.js')
const cantCreate = new Discord.MessageEmbed()
.setColor('#f07a76')
.setDescription(`Can't create channel.`)
const hasPerm = message.member.hasPermission("ADMINISTRATOR");
const permFail = new Discord.MessageEmbed()
.setColor('#f07a76')
.setDescription(`${message.author}, you don't have the permission to execute this command. Ask an Admin.`)
if (!hasPerm) {
message.channel.send(permFail);
}
else if (hasPerm) {
const askName = new Discord.MessageEmbed()
.setColor(' #4f6abf')
.setDescription(`How should the channel be called?`)
message.channel.send(askName);
const collector = new Discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { max: 1, time: 10000 });
console.log(collector)
var array = message.content.split(' ');
array.shift();
let channelName = array.join(' ');
collector.on('collect', message => {
const created = new Discord.MessageEmbed()
.setColor('#16b47e')
.setDescription(`Channel has been created.`)
message.guild.channels.create(channelName, {
type: "text",
permissionOverwrites: [
{
id: message.guild.roles.everyone,
allow: ['VIEW_CHANNEL','READ_MESSAGE_HISTORY'],
deny: ['SEND_MESSAGES']
}
],
})
.catch(message.channel.send(cantCreate))
})
}
else {
message.channel.send(created)
}
}
}
The message object currently refers to the original message posted by the user. You're not declaring it otherwise, especially seeing as you're not waiting for a message to be collected before defining a new definition / variable for your new channel's name.
NOTE: In the following code I will be using awaitMessages() (Message Collector but promise dependent), as I see it more fitting for this case (Seeing as you're more than likely not hoping for it to be asynchronous) and could clean up the code a little bit.
const filter = m => m.author.id === message.author.id
let name // This variable will later be used to define our channel's name using the user's input.
// Starting our collector below:
try {
const collected = await message.channel.awaitMessages(filter, {
max: 1,
time: 30000,
errors: ['time']
})
name = collected.first().content /* Getting the collected message and declaring it as the variable 'name' */
} catch (err) { console.error(err) }
await message.guild.channels.create(name, { ... })

Categories

Resources