.awaitMessageComponent() in an ephemeral reply and then editing it - discord.js

I have been trying to implement an interaction collector as per the discord.js guide, but the guide does not explain much of anything and the pieces I have puzzled together from other sources do not fit together. Here's the example from the guide:
message.awaitMessageComponent({ filter, componentType: 'SELECT_MENU', time: 60000 })
.then(interaction => interaction.editReply(`You selected ${interaction.values.join(', ')}!`))
.catch(err => console.log(`No interactions were collected.`));
It took me a day to figure out that you can define a message object like so:
message = await interaction.channel.send(content: 'text', components: >select menu<)
That works to run .awaitMessageComponent() and to grab the input from the select menu, however interaction.editReply() gives an error: INTERACTION_NOT_REPLIED
Moreover, I need it to be a reply anyway, however
message = await interaction.reply(content: 'text', components: >select menu<)
leaves message as undefined, so of course I cannot run .awaitMessageComponent() on it.
So I do not understand what I am supposed to do to do what that guide is doing.
I would very much appreciate any insight into this issue.
Unfortunately all other guides (usually on collectors) also start with a .send() message and most other resources go way over my head, as I have no real background in coding/scripting.
EDIT:
As Malik Lahlou points out, you can assign the reply by including the fetchReply:option, like so:
message = await interaction.reply({ components: [select menu], fetchReply: true })
However that still does not allow the guide's code to run (error INTERACTION_NOT_REPLIED, so after some more research I finally found a way to use .awaitMessageComponent() and applied to the guide's example it would look like this:
await interaction.reply({ components: [select menu], ephemeral: true });
const collectedSelect = await interaction.awaitMessageComponent({ filter, componentType: 'SELECT_MENU', time: 60000 })
.then(interaction => interaction.editReply(`You selected ${interaction.values.join(', ')}!`))
.catch(err => console.log(`No interactions were collected.`));

Simple answer, add the fetchReply option when replying to the interaction :
const message = await interaction.reply({
// content : ...,
// components : ...,
fetchReply: true
})
Another way would be to use interaction.fetchReply after awaiting the reply but it's better to directly give it as a parameter so discord.js does this stuff for us :D Here's an example on the official discord.js guide

Related

How to (and is it possible to) make link markup work in a discord bot message?

What I'm trying to achieve is simple:
send a message like links: [link1](https://example.com/1), [link1](https://example.com/2) via a bot
get it displayed as "links: link1, link1"
In a ephemeral follow up, it works as expected:
const content = "links: [link1](https://example.com/1), [link1](https://example.com/2)"
await interaction.followUp({
ephemeral: true,
content,
})
But when I send this to a public channel like this:
await channel.send(content)
I'm getting it as plain text (links: [link1](https://example.com/1), [link1](https://example.com/2)) except the links are clickable.
Is it possible to get the same result as in an ephemeral message?
I've checked the permissions, there's only "embed" links (which sounds like "allow links in embeds", and not "allow links in messages) and it is enabled anyway on server for everyone, for the bot and in the channel. So what am I missing here?
PS Here they say that "it's only possible if the message was sent with webhook though", but I'm not quite sure what does this mean (can this be different for a public and an ephemeral message?)
You cannot use hyper links in normal messages sent by a bot. You need to use a Webhook. Considering you're using discord.js, see this guide on their documentation. When using something like that it will work as expected
const { WebhookClient } = require('discord.js');
const webhookClient = new WebhookClient({ url: "WEBHOOK_URL" });
webhookClient.send({
content: "[Hello world](https://github.com)",
username: "Webhook Username",
});
Otherwise you may use embeds and send one of these with your bot and the content you wish to have.
Right, so I've found a solution based on suggestion by Krypton. As an embed doesn't look nice and manual creation of a webhook is not an option for me, I've found that I can create a webhook on the go and use it.
After some testing, I've figured that such webhooks are also permanent (although they can be found in another part of settings than the manually created ones); they should be deleted as there's a limit of 15 webhooks – an attempt to create more fails (with DiscordAPIError[30007]: Maximum number of webhooks reached (15)).
Instead of doing
await channel.send(content)
I've put
// a guard, TypeScript requires us to be sure
if(channel instanceof TextChannel) {
const webhook = await channel.createWebhook({
// a message from a webhook has a different sender, here we set its name,
// for instance the same as the name of our bot (likewise, we can set an avatar)
name: "MyBot",
})
await webhook.send(content)
await webhook.delete()
}
This seems to be a minimal code change to get the links working.

Why doesn't my welcome message in discord.js work?

i have tried a lot of different ways but this seemed the most used and successful! But it doesn't seem to work for me? I don't need an embed just a simple message. How do i do this correctly?
client.on('guildMemberAdd', async newMember => {
const welcomeChannel = newMember.guild.channels.cache.find(channel => channel.id === 'my channel id is here')
welcomeChannel.send('welcome we hope you have fun')
})
I've tried your code on myself, it is working exactly just as you intended, so I'm assuming that you might not have put the correct intent. Now discord bot need specific intent (depends on what you are trying to do) to work correctly .
And in your case, you are probably missing the "GUILD_MEMBERS" intent. Change it like:
const client = new Client({
intents: 'GUILD_MEMBERS',
})
Also, in case if you are building a local bot and you don't care about intent or you just simply got annoyed by it.
You can also use
const client = new Client({
intents: 32767,
})

How do I manage voice connections from multiple bots in one code?

My code manages multiple and different Discord bots, and to check what bot has to perform a certain action there's an algorithm that looks just like the following:
function getHandlerByClient(client: Discord.Client): (typeof MusicHandler) {
if (Utils.checkClientByToken(client, Constants.MUSIC1_TOKEN)) return MusicHandler1;
else if (Utils.checkClientByToken(client, Constants.MUSIC2_TOKEN)) return MusicHandler2;
else if (Utils.checkClientByToken(client, Constants.MUSIC3_TOKEN)) return MusicHandler3;
return MusicHandler;
}
On previous Discord.js versions I could just execute something like:
let joinEvent = channel.join();
and it would work just fine, the correct bot instance would execute that code. Now everything's changed and I have to run:
let connection = DiscordVoice.joinVoiceChannel({
channelId: channel.id,
guildId: channel.guild.id,
adapterCreator: channel.guild.voiceAdapterCreator
});
and it doesn't even work as it did before: if I play something on bot#1 and then without having it stopped play something else on bot#2, bot#2 doesn't join the channel and plays everything in bot#1. So whenever I run play on any of the bots, all the others won't join channels until the first one called quits. How can I solve this?
I'm not sure if after 3 months my answer will help, but maybe someone will also face this problem.
I struggled all day with the same problem, and to my great fortune I found the answer in the official discord server discord.js.
solution
I simply add client.user.id as group identificator and use voiceAdapterCreator from a certain client that i need like this:
/* attachedBot.client - the bot client that you want to connect to voice channel */
const connection = joinVoiceChannel({
channelId: interaction.member.voice.channelId,
guildId: interaction.guild.id,
adapterCreator: (await (await attachedBot.client.guilds.fetch()).find(g => g.id === interaction.guild.id).fetch()).voiceAdapterCreator,
group: attachedBot.client.user.id
});
And this works fine for me

Discord.js move messages in a different Channel

I'm trying to make the t!suggestion command work on different Servers. My problem is that i used the Channel ID in the following Code, which is obviously not working on a second Server. So my thought was to exchange the Channel ID and use the Channel Name. Unfortunatley i have no idea how to do that. And therefore are my question. Is it possible to just change the Code and use the Channel Name instead of the Channel ID and would that work?
bot.on("message", async (message) => {
if (message.content.startsWith("t!suggestion")) {
var str = message.content.slice(" t!suggestion".length);
const channelToSendId = "8786607442820137466";
const embed = new Discord.MessageEmbed()
.setThumbnail("Picture")
.setAuthor("TestBot", "small picture")
.setTitle("Suggestion")
.setColor("#151515")
.addFields({ name: "Person, that suggested somenthing:", value: `<#!${message.author.id}>` }, { name: "suggestion:", value: `${str}` }, { name: "Channel:", value: `${message.channel}` })
.setTimestamp();
await bot.channels.cache
.get(channelToSendId)
.send(embed)
.then((embedMessage) => {
embedMessage.react("✅");
embedMessage.react("❌");
});
message.delete();
}
});
Using the find method will work.
Change this
bot.channels.cache.get(channelToSendId)
To this
bot.channels.cache.find(c => c.name === 'suggestions')
The get method always finds by id (that’s how discord.js sets it), but you can put a condition in find. Note that it is a function. Another problem is that this will still only work on one channel, even if the command is run in a different guild. To fix that, you should only check the current guild's channels.
message.guild.channels.cache.find(c => c.name === 'suggestions')
This will find the channel with the name suggestions (we don’t put the # in the code) and send the message there. Keep in mind you may receive an error if the channel is not found.

Discord.js mongoose registering 2 warnings instead of one

I am having issues across all the commands that share the same system as this one below.
All commands like ban, mute, kick are identical to this one and act the same in the mongoose part.
Take a look below, in the given code block.
const warnDoc = new WarningModel({
guildID: message.guild.id,
memberID: member.id,
warnings: [reason],
moderator: [message.member.id],
date: [Date.now()],
})
warnDoc.warnings.push(reason)
warnDoc.moderator.push(message.member.id)
warnDoc.date.push(Date.now())
await warnDoc.save().catch(err => console.log(err))
message.delete(message.author);
const logs = message.guild.channels.cache.find(channel => channel.name === "albot-mod-system");
if (!logs)
return console.log(`No logs channel exists in ${message.guild.name}`)
let warnembed = new Discord.MessageEmbed()
.setTitle(`Moderation | Audit Log`)
.addField("**Member**", `${member}`)
.addField("**Action**", "Warn")
.addField("**Reason**", `${reason ? `${reason}` : ''}`)
.addField("**Warning Count**:", `${warnDoc.warnings.length}`)
.setTimestamp(message.createdAt)
.setFooter(message.member.displayName, message.author.displayAvatarURL({ dynamic: true }))
.setColor(`#000000`)
logs.send(warnembed);
member.send(`You were warned in **${message.guild.name}** for: **${reason}**.`);
let warnEmbed2 = new MessageEmbed()
.setAuthor(`Moderation`)
.setDescription(`${member} has been warned successfully with the reason: ${reason}`)
.setTimestamp(message.createdAt)
.setFooter(message.member.displayName, message.author.displayAvatarURL({ dynamic: true }))
.setColor(`#000000`)
message.channel.send(warnEmbed2);
}
}
This is my warn command and when i run it, it normally gives 1 warning, but instead registers two. This issue came out of nowhere and it is confusing.
Anyone know the root issue of this?
Stuff ive tried:
Try a older mongoose version, no luck.
Play around with the mongoose parts in the code, no luck.
Revert to older versions of the command, no luck.
I honestly do not know what is causing this.
You're initializing WarningModel with a warnings array (warnings: [reason]) and pushing to it again with the same reason. Remove the push call.
Remove
warnDoc.warnings.push(reason)
You should also remove the following lines since moderator and date values are set while initializing the document.
warnDoc.moderator.push(message.member.id)
warnDoc.date.push(Date.now())

Resources