Editing a reply's message components resends an interaction, how do I stop it? - discord

I have made a bot command that
replies with a select menu
waits for the selection to be made
edits the reply to have a buttons instead of the select menu
waits for a button to be pressed
edits the reply again
It works, however, whenever I edit a reply's message components like that, immediately after the edit, the bot receives a new interaction, that does not go anywhere.
The result is that the new component will act like it was pressed, giving me the loading symbol, until the interaction has failed. Then the component works fine, just the red "The application did not respond" text remains.
This is of course fairly annoying and also confusing and ugly for the user. So I'm hoping someone can tell me whether I can do anything about it, and if so what exactly.
Here's is a very simple example command that demonstrates this behaviour:
client.on('interactionCreate', async interaction => {
console.log('interaction received');
const { commandName } = interaction;
if (commandName === 'test') {
const select = new MessageActionRow().addComponents(
new MessageSelectMenu().setCustomId('select').setPlaceholder(`Select a match to tip on.`)
.addOptions([ {label: `select me`, value: `testValue`} ])
)
await interaction.reply({ content: 'Please make a selection', components: [select], ephemeral: true });
const collectedSelect = await interaction.channel?.awaitMessageComponent({ componentType: 'SELECT_MENU'})
console.log(collectedSelect.values[0]);
const button = new MessageActionRow().addComponents(
new MessageButton().setCustomId(`button`).setLabel('push me').setStyle('PRIMARY')
)
await interaction.editReply({ content: 'Thanks for making a selection. Now, please push the button.', components: [button], ephemeral: true });
const collectedButton = await interaction.channel?.awaitMessageComponent({ componentType: 'BUTTON'})
console.log(collectedButton.customId);
return interaction.editReply({ content: 'Thanks for pushing the button.', components: [], ephemeral: true });
}
}

Oh, well. I was looking for something else and found this little guy that solves my problem: update()
It just needs to be run on the interaction collected with .awaitMessageComponent(), not the original interaction (like in my op).
It looks like this then:
const select = new MessageActionRow().addComponents(
new MessageSelectMenu().setCustomId('select').setPlaceholder(`Select a match to tip on.`)
.addOptions([ {label: `select me`, value: `testValue`} ])
)
await interaction.reply({ content: 'Please make a selection', components: [select], ephemeral: true });
const collectedSelect = await interaction.channel?.awaitMessageComponent({ componentType: 'SELECT_MENU'})
console.log(collectedSelect.values[0]);
const button = new MessageActionRow().addComponents(
new MessageButton().setCustomId(`button`).setLabel('push me').setStyle('PRIMARY')
)
await collectedSelect.update({ content: 'Thanks for making a selection. Now, please push the button.', components: [button], ephemeral: true });
const collectedButton = await interaction.channel?.awaitMessageComponent({ componentType: 'BUTTON'})
console.log(collectedButton.customId);
return collectedButton.update({ content: 'Thanks for pushing the button.', components: [], ephemeral: true });
I honestly, do not know why .editReply() wouldn't already work, but whatever I guess.

Related

How can I DM the user an embed before he is kicked (discord.js)

I'm trying to make a blacklist command, and how do I make it so it sends an embed instead of normal message.
(Also, I'm new to discord.js)
Here's my script:
module.exports = {
data: new SlashCommandBuilder()
.setName('blacklist')
.setDescription('Blacklist someone from the server')
.addUserOption((option) => option.setName('member')
.setDescription('Who are you blacklisting?')),
async execute(interaction) {
await interaction.deferReply();
const member = interaction.options.getMember('member');
if (!interaction.member.roles.cache.some(r => r.name === "Blacklist perms")) {
return interaction.editReply({ content: 'You do not have permission to use this command!' });
}
member.send("You have been blacklisted!")
member.kick().catch(err => {
interaction.editReply({ content: `I do not have enough permissions to do that.`})
})
await interaction.editReply({ content: `${member} has been succesfully blacklisted!` });
},
};```
Since your function is already async, simply await sending the message before you call kick.
await member.send("You have been blacklisted!")
member.kick().catch(err => {
interaction.editReply({ content: 'I do not have enough permissions to do that.'})
})
You might also wanna catch() on the send method because users can have DMs from server members disabled or blocked your bot.
You also might consider banning the user instead, because this system would fail if your bot ever happens to go offline when a blacklisted user tries to join. Additionally, depending on how fast your bot reacts, the user may still have time to spam in channels or do something harmful before your bot is able to kick them.
To send an embed either use an EmbedBuilder or a plain JavaScript object with the correct embed structure.
Example:
member.send({ embeds:[{
title: "Title",
description: "Hello World!"
}] })

My bot sends an embed that is invisible to all users and shows no message sent

I've been working on using JS to create a simple Discord Bot for my server. I have been trying to have it send a message with the rules of the server embedded into it. When the /rules command is run, I receive a notification to state a message was sent, but there is no message to be seen on any device. I am able to view message history so I do not understand why there is no visible embed or message.
My code was made using Autocode's Discord Embed Builder, and has worked for other embeds within the same Bot. A link to view the full embed code in the Builder and see how it is supposed to look is here.
It would be much easier to learn to make these yourself than using a generator and trying to reverse engineer how their coding works:
a simple example would be this:
const {
MessageEmbed
} = require('discord.js')
module.exports = {
name: "rules",
description: "Post rules",
run: async (client, interaction) => {
// build the message
const embed = new MessageEmbed()
.setColor('#00ff00') //change the color if you want
.setTitle('Some Title')
.setDescription(`Some description`)
.addFields({
name: 'Rule Name/Number',
value: 'Rule text',
inline: true
}, {
name: 'Rule Name/Number',
value: `Rule text`,
inline: true
}, {
name: 'Rule Name/Number',
value: 'Rule text',
inline: true
})
// add more if needed
// send the message
interaction.channel.send({
embeds: [embed]
})
// confirm they are sent and complete the interaction only visible to you
return interaction.reply({
content: 'Done',
ephemeral: true
})
}
}

Discord.js Filter Discord Events From Only 1 Server

I am working on trying to filter events for only 1 server rather than all servers the bot is in, but I'm trying to figure out how to exactly save each guild the bot is in as an collection so I can just filter events based on a guild ID I desire. Is this even possible? This is a snippet of the code I have to date, it's able to display the server names and ID's the bot is currently in, the events are working properly but triggering for all servers rather than the one I desire, how would I go about filtering for one guild collection?
const Discord = require('discord.js')
const bot = new Discord.Client()
const config = require('./config.json')
bot.on('ready', () => {
console.log(`Logged in as ${bot.user.tag}!`);
//Sets Activity
//client.user.setStatus('invisible')
bot.user.setActivity("Discord Cooks", { type: "WATCHING"})
console.log("Set User Activity!");
//Online Webhook
const webhookClient = new Discord.WebhookClient('','');
const embed = new Discord.MessageEmbed()
.setTitle(`${bot.user.tag} is online`)
.setColor('#FFFF00')
.setTimestamp()
webhookClient.send(embed);
bot.guilds.cache.forEach((guild) => {
console.log(guild.name, guild.id);
});
});
bot.on("channelCreate", (channel) => {
console.log(`channelCreate: ID: ${channel.id} Name: ${channel.name}`);
});
bot.on("channelUpdate", (oldChannel, newChannel) => {
console.log(`channelUpdate -> ${oldChannel.name} to ${newChannel.name}`);
});
bot.on("channelDelete", (channel) => {
console.log(`channelDelete: ID: ${channel.id} Name: ${channel.name}`);
});
bot.login(config.bottoken)
You can only execute code if event happened on exact server in much easier way:
if(guild.id == "GUILD_ID") {
// code
}
Also as #MrMythical said, you can just use if (message.guild.id !== "GUILD_ID") return; if you only need to run your code for 1 guild!

Embed message discord.js

Ive seen many discord embed codes like this:
(This is an old question and im new to coding so...)
const { MessageEmbed } = require('discord.js');
const exampleEmbed = new MessageEmbed()
.setColor('#0099ff')
.setTitle('Some title')
.setURL('https://discord.js.org/')
.setAuthor('Some name', 'https://i.imgur.com/AfFp7pu.png', 'https://discord.js.org')
.setDescription('Some description here')
.setThumbnail('https://i.imgur.com/AfFp7pu.png')
.addFields(
{ name: 'Regular field title', value: 'Some value here' },
{ name: '\u200B', value: '\u200B' },
{ name: 'Inline field title', value: 'Some value here', inline: true },
{ name: 'Inline field title', value: 'Some value here', inline: true },
)
.addField('Inline field title', 'Some value here', true)
.setImage('https://i.imgur.com/AfFp7pu.png')
.setTimestamp()
.setFooter('Some footer text here', 'https://i.imgur.com/AfFp7pu.png');
channel.send({ embeds: [exampleEmbed] });
So, what i dont understand is what is the trigger? Like you're supposed to type .ping for pong right? so what do i type to get my bot type this embed?
The way you're sending your embed is(afaik) specific to version 13 of discord.js and you most likely haven't updated discord.js yet:
channel.send({ embeds: [exampleEmbed] });
the version I am currently using is 12.5.3 .
Check your version of discord.js in package.json and if the version is not 13 or above, update or if you want to stick with version 12.5.3 try some of the methods below:
channel.send( exampleEmbed );
Or like this:
channel.send({ embed: exampleEmbed });
Sending the embed like this: "{ embeds: [exampleEmbed] }" makes discord think you are sending an empty message and therefore it doesn't send anything.
This code is meant to be inside an event handler (such as on.message). If that code is already inside an event handler (except for this const { MessageEmbed } = require('discord.js');, it should go at the top), and if it is still not sending, then you should change this line:
channel.send({ embeds: [exampleEmbed] });
to
message.channel.send(exampleEmbed)
There is no trigger in the code sample you provided. You need to have a listener for the message event or interactionCreate event to listen to traditional message-based commands and slash commands. You can pass in handlers into these listeners and respond to command usages.
Since it looks like you're reading the discord.js guide, I would suggest reading from the start, where you would be introduced to how to handle messages first.
To send it, just use a message event. Like this:
const { MessageEmbed, Client } = require('discord.js');
const client = new Client();
client.on('message', msg => {
const { channel, content } = msg;
if(msg.content === 'someCommand') {
const exampleEmbed = new MessageEmbed()
//setProperties...
channel.send({ embeds: [exampleEmbed] });
}
})
client.login('[TOKEN_HERE'])
What's happening here is that the client is receiving a Message object when someone messages (msg). We then use the channel and content properties to evaluate the command, and send the embed if the command is correct. I took out the property settings to save space. You can add them back.

How to edit an embed with your bot Discord.js?

How can I edit an sent embed with my bot? First I contructed an embed:
const countdownEmbed = {
color: 0x0099ff,
title:('Countdown'),
author: {
name:`${user_name}`,
icon_url: `${user_pfp}`,
},
description: 'Your countdown starts in **3 seconds**',
thumbnail: {
url: `${client_pfp}`,
},
timestamp: new Date(),
footer: {
text: `© ${client_name}`,
icon_url: `${client_pfp}`,
},
};
Then I made a new embed:
const countdownEmbed2 = {
title:("New title!"),
description: 'Your countdown starts in **2 seconds**',
};
After creating the "updated" embed I tried to send the message and then edit it after a second:
message.channel.send({ embed: countdownEmbed })
.then((msg)=> {
setTimeout(function(){
msg.edit(countdownEmbed2);
}, 1000)
});
My code only sends the initial embed and does not edit it. But if I change the CountEmbed2 in msg.edit(countdownEmbed2) to a string, it will edit the message itself in Discord, but not the embed. Is there a way to fix this? Or is there an easier way to edit an embed?
I am unsure why but after my test, I concluded that your issue is caused by the way you're writing your embeds.
if you use the MessageEmbed constructor (if you're using discord.js v11 it's RichEmbed) it'll work.
This worked while testing it out:
const countdownEmbed = new MessageEmbed()
.setDescription('test1')
const countdownEmbed2 = new MessageEmbed()
.setDescription('test2')
.setColor('RED')
message.channel.send({ embed: countdownEmbed }).then((msg) => {
setTimeout(function () {
msg.edit(countdownEmbed2);
}, 1000)
})
Here is an example of an edit
const editEmbed = new Discord.MessageEmbed()
.setDescription('this is the old description')
message.channel.send(editEmbed).then((m) =>
m.edit(editEmbed.setDescription('this is the new description')))
let me know if this worked

Resources