I'm trying to make a draft bot that takes the player amount from an interaction in my draftSize.js file and uses that value in my join.js file as a maximum value for my MessageComponentCollector.
Here is draftSize.js
const { SlashCommandBuilder } = require('#discordjs/builders');
const { MessageActionRow, MessageButton } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('size')
.setDescription('Sets the size of total players in your draft.')
.addIntegerOption(option =>
option.setName('players')
.setDescription('Amount of players participating in the draft.')
.setRequired(true)),
async execute(interaction) {
let playerSize = interaction.options.getInteger('players');
await interaction.reply({ content: `You\'ve selected a ${playerSize} player draft. \n Next, type: ` + "```" + '/captains {#FirstCaptain} {#SecondCaptain}' + "```"});
console.log("test " + playerSize)
},
};
And here is join.js:
const { SlashCommandBuilder } = require('#discordjs/builders');
const { MessageActionRow, MessageButton, Message } = require('discord.js');
const { playerSize } = require('./draftSize');
module.exports = {
data: new SlashCommandBuilder()
.setName('join')
.setDescription('Allow players to join your draft.'),
async execute(interaction, channel) {
const row = new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId('joinButton')
.setLabel('Join')
.setStyle('SUCCESS'),
);
await interaction.reply({ content: `To join the draft, click the button below. Once the specified player amount has joined, the draft will begin!`, components: [row] });
const filter = i => {
return i.customId === 'joinButton'
};
const playerList = []
const collectChannel = interaction.channel;
const collector = collectChannel.createMessageComponentCollector({
filter,
max: playerSize,
time: 1000 * 30
})
collector.on('collect', (i = MessageComponentInteraction) => {
i.reply({
content: 'you clicked a button',
ephemeral: true
})
console.log(playerSize)
})
collector.on('end', (collection) => {
collection.forEach((click) => {
playerList.push(click.user.username)
})
collectChannel.send({ content: 'testing'})
console.log(playerList);
})
},
};
In my draftSize.js I get my playerSize value, but whenever I try to import the value into my join.js file to use as my collectors max value it always returns undefined.
Sorry if any of this was unclear. Let me know if you need any clarification.
Thanks!
Related
it might be a stupid question but since I'm a beginner I sadly don't understand most of how javascript works yet.
I'm trying to create a small Discord bot for a project that I'm working on and I would like to make it so you can select an option from a dropdown menu and whatever you select it sends a different embedded message in the channel. But whatever I do it doesn't send the embedded message. I've looked up multiple tutorials, but it seems like I'm missing something. Maybe someone can direct me in the right direction.
It is sending the dropdown menu, but sending error "InteractionAlreadyReplied". And whenever I try to select an option it won't send the embedded messages.
Here is my code so you can see the approach I'm using. I've tried using "MessageActionRow" and "MessageSelectMenu", but it seems like they don't work anymore. After inserting "ActionRowBuilder" and "StringSelectMenuBuilder" I got the menu working, but as said I don't get the embedded messages as an option. (didn't include the .env file since its only the token in there) I'm just not sure how I can make it so it connects the values from the dropdown menu to the right embeds.
CommandFile:
const { Discord, MessageActionRow, MessageSelectMenu,
SlashCommandBuilder, EmbedBuilder, roleMention, ButtonBuilder,
StringSelectMenuBuilder, StringSelectMenuOptionBuilder, ActionRowBuilder } = require('discord.js');
const { MessageEmbed } = require("discord.js")
module.exports = {
data: new SlashCommandBuilder()
.setName('dropdown')
.setDescription('Returns a select dropdown!'),
async execute(interaction, client, message, args) {
const row = new ActionRowBuilder()
.addComponents(
new StringSelectMenuBuilder()
.setCustomId("select")
.setPlaceholder("Wähle etwas aus:")
.addOptions([
{
label: "Auswahl 1",
description: "Beschreibung Auswahl 1",
value: "first"
},
{
label: "Auswahl 2",
description: "Beschreibung Auswahl 2",
value: "second"
},
{
label: "Auswahl 3",
description: "Beschreibung Auswahl 3",
value: "third"
},
])
)
let embed = new EmbedBuilder()
.setTitle("Embed Startseite")
.setDescription("Ab hier kann man selecten, was man möchte")
.setColor(0x18e1ee)
let sendmsg = await interaction.reply({ content:
"ㅤ", ephemeral:true, embeds: [embed], components: [row] })
let embed1 = new EmbedBuilder()
.setTitle("Embed 1")
.setDescription("Embed 1 Beschreibung")
.setColor(0x18e1ee)
let embed2 = new EmbedBuilder()
.setTitle("Embed 2")
.setDescription("Embed 2 Beschreibung")
.setColor(0x18e1ee)
let embed3 = new EmbedBuilder()
.setTitle("Embed 3")
.setDescription("Embed 3 Beschreibung")
.setColor(0x18e1ee)
const collector = message.createMessageComponentCollector({
componentType: "StringSelectMenuBuilder"
})
collector.on("collect", async (collected) => {
const value = collected.values[0]
if(value === "first") {
collected.reply({ embeds: [embed1], ephemeral:true })
}
if(value === "second") {
collected.reply({ embeds: [embed2], ephemeral:true })
}
if(value === "third") {
collected.reply({ embeds: [embed3], ephemeral:true })
}
})
}
}
bot.js:
require("dotenv").config();
const { token } = process.env;
const { Client, Collection, GatewayIntentBits, ChannelSelectMenuInteraction } = require("discord.js");
const fs = require("fs");
const client = new Client({ intents: GatewayIntentBits.Guilds });
client.commands = new Collection();
client.buttons = new Collection();
client.selectMenus = new Collection();
client.commandArray = [];
const functionFolders = fs.readdirSync(`./src/functions`);
for (const folder of functionFolders) {
const functionFiles = fs
.readdirSync(`./src/functions/${folder}`)
.filter((file) => file.endsWith(".js"));
for (const file of functionFiles)
require(`./functions/${folder}/${file}`)(client);
}
client.handleEvents();
client.handleCommands();
client.handleComponents();
client.login(token);
HandleComponents.js :
const { readdirSync } = require('fs');
module.exports = (client) => {
client.handleComponents = async () => {
const componentFolders = readdirSync(`./src/components`);
for (const folder of componentFolders) {
const componentFiles = readdirSync(`./src/components/${folder}`).filter(
(file) => file.endsWith('.js')
);
const { buttons, selectMenus } = client;
switch (folder) {
case "buttons":
for (const file of componentFiles) {
const button = require(`../../components/${folder}/${file}`);
buttons.set(button.data.name, button);
}
break;
case "selectMenus":
for (const file of componentFiles) {
const menu = require(`../../components/${folder}/${file}`);
selectMenus.set(menu.data.name, menu);
}
break;
default:
break;
}
}
};
};
HandleCommands.js :
const { REST } = require('#discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const fs = require("fs");
module.exports = (client) => {
client.handleCommands = async () => {
const commandFolders = fs.readdirSync("./src/commands");
for (const folder of commandFolders) {
const commandFiles = fs
.readdirSync(`./src/commands/${folder}`)
.filter(file => file.endsWith(".js"));
const { commands, commandArray } = client;
for (const file of commandFiles) {
const command = require(`../../commands/${folder}/${file}`);
commands.set(command.data.name, command);
commandArray.push(command.data.toJSON());
}
}
const clientId = "IDbutCensored";
const guildId = "IDbutCensored";
const rest = new REST({ version: '9' }).setToken(process.env.token);
try {
console.log("Started refreshing application (/) commands.");
await rest.put(Routes.applicationGuildCommands(clientId, guildId), {
body: client.commandArray,
});
console.log("Successfully reloaded application (/) commands.");
} catch (error) {
console.error(error);
}
};
};
handleEvents.js :
const fs = require("fs");
module.exports = (client) => {
client.handleEvents = async () => {
const eventFolders = fs.readdirSync(`./src/events`);
for (const folder of eventFolders) {
const eventFiles = fs
.readdirSync(`./src/events/${folder}`)
.filter((file) => file.endsWith(".js"));
switch (folder) {
case "client":
for (const file of eventFiles) {
const event = require(`../../events/${folder}/${file}`);
if (event.once) client.once(event.name, (...args) => event.execute(...args, client));
else client.on(event.name, (...args) => event.execute(...args, client));
}
break;
default:
break;
}
}
}
}
The error is pretty self explanatory. The error InteractionAlreadyReplied means you already replied and you're trying to reply again.
You can solve this by doing the following;
• Use .followUp() to send a new message
• If you deferred reply it's better to use .editReply()
• Information about responding to slash commands / buttons / select menus
From the Discord docs
I'm currently learning how to use Discords Buttons but I ran into a problem.
The following code should create a button with the command /startgame, when you press this button it should just say "hello".
const { SlashCommandBuilder } = require("#discordjs/builders")
const { MessageButton, MessageActionRow } = require("discord.js")
module.exports ={
data: new SlashCommandBuilder()
.setName("startgame")
.setDescription("Startet das Spiel"),
async execute(interactionCreate) {
if (interactionCreate.isCommand()) {
const row1 = new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId("start")
.setLabel(" Start ")
.setStyle(3)
.setDisabled(false),
)
await interactionCreate.reply({content: " ", components: [row1]})
}
else if(interactionCreate.isButton()) {
switch (interactionCreate.customId) {
case "start": {
return interactionCreate.reply("hello")
}
}
}
}
}
It creates the button, but when you press it, it only says: This interaction failed I appreciate any help.
OK so one of these parts should be under your event listener interactionCreate rather than in a command. So if you have that section in your main bot.js file it would look like this:
Command File
const {
SlashCommandBuilder
} = require("#discordjs/builders")
const {
MessageButton,
MessageActionRow
} = require("discord.js")
module.exports = {
data: new SlashCommandBuilder()
.setName("startgame")
.setDescription("Startet das Spiel"),
async execute(interaction) {
const row1 = new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId("start")
.setLabel(" Start ")
.setStyle(3)
)
return interaction.reply({
components: [row1]
})
}
}
bot.js file - could be named whatever you named it
client.on('interactionCreate', async interaction => {
if (interaction.isButton()) {
const buttonID = interaction.customId
if (buttonID === 'start') {
interaction.reply({
content: 'Hello'
})
}
}
})
So I am trying to make a suggestion command using discord buttons in Discord.JS. When I run the command the embed and the buttons send but whenever I click one of the buttons whether it be Upvote, Maybe, or Downvote it edits the embed, but it never updates the number. I've tried upvote_number ++ and upvote_number + 1 but it doesn't work. It would be awesome if somebody could help me with this. Thank you.
const Discord = require('discord.js');
const disbut = require('discord-buttons');
const { MessageActionRow, MessageButton } = require("discord-buttons");
const { Color, Prefix } = require("../../config.js");
const { MessageEmbed } = require("discord.js");
const disbutpages = require("discord-embeds-pages-buttons")
const db = require('quick.db');
module.exports = {
name: "suggest",
aliases: [],
description: "Suggestion Command",
usage: "^suggest <suggestion>",
run: async(client, message, args) => {
const SayMessage = message.content.slice(8).trim();
let upvote_number = 0
let downvote_number = 0
let maybe_number = 0
const embed = new Discord.MessageEmbed()
.setAuthor("Suggestion from: " + message.author.tag, message.author.displayAvatarURL({dynamic: true}))
.setThumbnail(message.author.displayAvatarURL({dynamic: true}))
.setDescription(SayMessage)
.addField(`Votes`, `Upvote: **${upvote_number}**
Downvote: **${downvote_number}**`)
let upvotebutton = new MessageButton()
.setLabel(`Upvote`)
.setID(`upvote`)
.setEmoji(`⬆️`)
.setStyle("green")
let maybebutton = new MessageButton()
.setLabel(`Maybe`)
.setID(`maybe`)
.setEmoji(`🤷`)
.setStyle("blurple")
let downvotebutton = new MessageButton()
.setLabel(`Downvote`)
.setID(`downvote`)
.setEmoji(`⬇️`)
.setStyle("red")
let row = new MessageActionRow()
.addComponents(upvotebutton, maybebutton, downvotebutton)
const MESSAGE = await message.channel.send(embed, { components: [row] })
const filter = ( button ) => button.clicker.user.id === message.author.id
const collector = MESSAGE.createButtonCollector(filter, { time : 120000 });
collector.on('collect', async (b) => {
if(b.id == "upvote") {
await upvote_number + 1
await MESSAGE.edit(embed, { components: [row] });
await b.reply.defer()
}
if(b.id == "downvote") {
downvote_number + 1
MESSAGE.edit(embed, { components: [row] });
await b.reply.defer()
}
if(b.id == "maybe") {
maybe_number + 1
MESSAGE.edit(embed, { components: [row] });
await b.reply.defer()
}
})
collector.on('end', (b) => {
})
}
};
You'd want to use the += operator for your question. By the way, because of how button collectors work, the suggestions will be timing out after some time, which may cause you some issues in the future, so you may want to switch to the event. My only other concerns are that you are using d.js 12 and discord-buttons which are both deprecated. As d.js 12 is losing support soon because of discord's api updates, I'd highly recommend switching to v13, as it has built in buttons, along with many other new features such as menus and slash commands.
let upvote_number = 0
let downvote_number = 0
let maybe_number = 0
/* ... */
collector.on('collect', async b => {
if(b.id == "upvote") {
upvote_number += 1
updateEmbed()
await MESSAGE.edit(embed, { components: [row] })
await b.reply.defer()
} else if (b.id == "downvote") {
downvote_number += 1
updateEmbed()
await MESSAGE.edit(embed, { components: [row] })
await b.reply.defer()
} else if (b.id == "maybe") {
maybe_number += 1
updateEmbed()
await MESSAGE.edit(embed, { components: [row] })
await b.reply.defer()
}
});
updateEmbed(){
embed.fields.find(i=>i.name==='Votes').value = `Upvote: **${upvote_number}**
Downvote: **${downvote_number}**`
}
tldr: Use += to set vars dynamically as well as update the embed object, and update to `discord.js#latest`
const ms = require('ms');
const { MessageEmbed } = require('discord.js')
module.exports = {
name: 'giveaway',
description: 'start a giveaway',
async execute(client, message, cmd, args, Discord){
let author = message.author.username;
var time;
time = args[0];
let title = args.join(" ").slice(3);
if(!message.member.permissions.has(['ADMINISTRATOR'])){
message.channel.send(`Sorry **${author}** But you don't have enough permissions to use this command!`)
} else {
if(message.member.permissions.has(['ADMINISTRATOR'])){
let giveawayEmbed = new MessageEmbed()
.setColor('BLACK')
.setThumbnail(`${message.author.displayAvatarURL()}`)
.setTitle(`${author}'s Giveaway 🎉`)
.setDescription(`**${title}**`)
.addField(`Duration :`, ms(ms(time), {
long: true
}), true)
.setFooter("React to this message with 🎉 to participate !")
var giveawaySent = await message.channel.send({ embeds: [giveawayEmbed] });
giveawaySent.react('🎉');
console.log(giveawaySent.id)
setTimeout(async function(){
const react = await giveawaySent.reactions.cache.find(r => r.emoji.name === '🎉').users.fetch();
let index = Math.map(Math.random() * react.length);
let winner = react[index];
console.log(react)
console.log(index)
console.log(winner)
let winnerEmbed = new MessageEmbed()
.setColor('GREEN')
.setDescription(`Congratulations **${winner}** you won **${title}**`)
message.reply({ embeds: [winnerEmbed] })
}, ms(time))
}
}
}
}
I'm trying to code a giveaway module however the winner result is coming out as undefined and I can't seem to figure out why, If you guys can help me out be greatly appreciated
These were logged by the console if it helps any
index = NaN
winner = undefined
const ms = require('ms');
const { MessageEmbed } = require('discord.js')
module.exports = {
name: 'giveaway',
description: 'start a giveaway',
async execute(client, message, cmd, args, Discord){
let author = message.author.username;
var time;
time = args[0];
let title = args.join(" ").slice(3);
if(!message.member.permissions.has(['ADMINISTRATOR'])){
message.channel.send(`Sorry **${author}** But you don't have enough permissions to use this command!`)
} else {
if(message.member.permissions.has(['ADMINISTRATOR'])){
let giveawayEmbed = new MessageEmbed()
.setColor('BLACK')
.setThumbnail(`${message.author.displayAvatarURL()}`)
.setTitle(`${author}'s Giveaway 🎉`)
.setDescription(`**${title}**`)
.addField(`Duration :`, ms(ms(time), {
long: true
}), true)
.setFooter("React to this message with 🎉 to participate !")
var giveawaySent = await message.channel.send({ embeds: [giveawayEmbed] });
giveawaySent.react('🎉');
console.log(giveawaySent.id)
setTimeout(async function(){
const react = await giveawaySent.reactions.cache.find(r => r.emoji.name === '🎉').users.fetch();
const reactArray = react.map(c => c)
let index = Math.floor(Math.random() * reactArray.length);
let winner = reactArray[index];
console.log(reactArray)
// console.log(react)
console.log(index)
console.log(winner)
let winnerEmbed = new MessageEmbed()
.setColor('GREEN')
.setDescription(`Congratulations **${winner}** you won **${title}**`)
message.reply({ embeds: [winnerEmbed] })
}, ms(time))
}
}
}
}
Seems to have resolved the issue, Added const reactArray = react.map(c => c)
Changed
let index = Math.floor(Math.random() * react.length); to let index = Math.floor(Math.random() * reactArray.length); which made const react = await giveawaySent.reactions.cache.find(r => r.emoji.name === '🎉').users.fetch(); into an array of user id's
So i am coding a bot , in Node.js with Visual Studio Code. I want to have a channel, that when a user joins the guild , will send 'Welcome user and invited by thisuser(Total Invites: 5)
The code is :
module.exports = (client) => {
const invites = {} // { guildId: { memberId: count } }
const getInviteCounts = async (guild) => {
return await new Promise((resolve) => {
guild.fetchInvites().then((invites) => {
const inviteCounter = {} // { memberId: count }
invites.forEach((invite) => {
const { uses, inviter } = invite
const { username, discriminator } = inviter
const name = `${username}#${discriminator}`
inviteCounter[name] = (inviteCounter[name] || 0) + uses
})
resolve(inviteCounter)
})
})
}
client.guilds.cache.forEach(async (guild) => {
invites[guild.id] = await getInviteCounts(guild)
})
client.on('guildMemberAdd', async (member) => {
const { guild, id } = member
const invitesBefore = invites[guild.id]
const invitesAfter = await getInviteCounts(guild)
console.log('BEFORE:', invitesBefore)
console.log('AFTER:', invitesAfter)
for (const inviter in invitesAfter) {
if (invitesBefore[inviter] === invitesAfter[inviter] - 1) {
const channelId = '731801004462571602'
const channel = guild.channels.cache.get(channelId)
const count = invitesAfter[inviter]
channel.send(
`Please welcome <#${id}> to the Discord! Invited by ${inviter} (${count} invites)`
)
invites[guild.id] = invitesAfter
return
}
}
})
}
This code works perfectly with console but i am facing a problem,never post the message in the channel!
The message might not be being sent because of the channel ID double check you are using the right channel ID and you might want to try changing
const channel = guild.channels.cache.get(channelId) to this
const channel = client.channels.cache.get(channelId)