Is anyone able to show me how I could add the discord Interactive Buttons onto this embed. I'm looking for just a simple button that will link somewhere. Thanks for the help
const Discord = require("discord.js")
const { Client, Message } = require('discord.js');
const { MessageEmbed } = require('discord.js');
module.exports = {
name: 'text',
cooldown: 1000,
run: async(client, message, args) => {
message.delete()
const exampleEmbed = new MessageEmbed()
.setColor('#000')
.setAuthor("Text")
.setDescription('Text')
.addFields(
{
name: `TextTitle`,
value: `Text`,
inline: true
},
{
name: `TextTitle`,
value: `Text`
} )
message.channel.send(exampleEmbed)}
}
First of all, you should call the MessageButton and MessageActionRow:
const { MessageEmbed, MessageActionRow, MessageButton } = require('discord.js');
Then we make a simple embed:
const exampleEmbed = new MessageEmbed()
.setColor('#000')
.setAuthor({ name: "Text" })
.setDescription('Text')
.addFields(
{
name: `TextTitle`,
value: `Text`,
inline: true
},
{
name: `TextTitle`,
value: `Text`
})
After that, We make a row and add some buttons to it:
const row = new MessageActionRow()
.addComponents(
new MessageButton()
.setLabel('Invite') // label of the button
.setEmoji('โ') // emoji
.setURL('https://https://stackoverflow.com') // URL of where the button leads the user
.setStyle('LINK') // style of the button
)
Then we send them:
message.channel.send({ embeds: [exampleEmbed], components: [row] })
There are 5 styles of building buttons:
PRIMARY,
SECONDARY,
SUCCESS,
DANGER,
LINK
Final Result:
You can visit Discordjs guides for More Info on Buttons
UPDATE: Discord.js v12
For creating buttons in discord.js v12, We should import buttons from the discord-buttons package.
const { MessageButton } = require('discord-buttons');
Then we make the button:
let button = new MessageButton()
.setStyle('url')
.setURL('https://stackoverflow.com')
.setLabel('invite');
Then we send it:
message.channel.send('test',button)
discord buttons v12 styles:
green
red
blurple
url
Related
I'm trying to make a game ban appeal, using the Discord-Modals package, and it seems to work good so far, however, the modal looks odd on phones, which will be a problem.
There are no errors, Here is what it looks like:
On PC, and On Phone1 Phone2
As you can see, On PC there was the Do you think the ban was fair? select drop down, but on both phones, it wasn't there.
I'm not sure of this is fixable, but I sure hope it is.
Code:~
// Main requirements
const { CHANNEL_SSU, CHANNEL_ROLESEL, BOT_PREFIX, ROLE_DEV } = require('../../config.json')
const commandName = '2gba'
// Optional Requirements
const { MessageEmbed, MessageActionRow, MessageButton, MessageCollector, InteractionType } = require('discord.js')
const { Modal, TextInputComponent, showModal, SelectMenuComponent } = require(`discord-modals`)
// Main Code
module.exports = client => {
client.on('messageCreate', async message => {
if (message.author.bot) return;
if (!message.content.toLowerCase().startsWith(BOT_PREFIX)) return;
const command = message.content.split(' ')
const args = message.content.substring(1).split(' ')
if (command.toString().toLowerCase().replace(BOT_PREFIX, '').startsWith(commandName)) {
if (!message.member.roles.cache.has(ROLE_DEV)) return message.reply("Only Developers can use this command!")
const buttonsRow1 = new MessageActionRow().addComponents(
new MessageButton()
.setCustomId('GBAempty5')
.setLabel(' ')
.setStyle('SECONDARY')
.setDisabled(true),
new MessageButton()
.setCustomId('GBA2')
.setLabel('Appeal')
.setStyle('DANGER')
.setDisabled(false),
new MessageButton()
.setCustomId('GBAempty6')
.setLabel(' ')
.setStyle('SECONDARY')
.setDisabled(true)
)
const GBAEmbed = new MessageEmbed()
.setTitle('Appeal Your Game Ban! 222')
.setColor('DARK_BLUE')
.setFooter({ text: 'ASRP | System Bot' })
.setThumbnail(message.guild.iconURL({ dynamic: true, size: 512 }))
message.delete()
message.channel.send({ embeds: [GBAEmbed], components: [buttonsRow1] })
}
})
client.on(`interactionCreate`, async (interaction) => {
if (!interaction.isButton) return
if (interaction.customId == 'GBA2') {
const modal = new Modal()
.setCustomId(`gbamodal`)
.setTitle(`ASRP | Game Ban Appeal`)
.addComponents(
new TextInputComponent()
.setCustomId("RobloxUsername-gba")
.setLabel("Roblox Username")
.setStyle("SHORT")
.setMinLength(1)
.setPlaceholder('Please check for any typos.')
.setRequired(true),
new TextInputComponent()
.setCustomId("Moderator-gba")
.setLabel("Who banned you?")
.setStyle("SHORT")
.setMinLength(1)
.setPlaceholder('This field is optional.')
.setRequired(false),
new TextInputComponent()
.setCustomId("unbanreason-gba")
.setLabel("Why should we unban you?")
.setStyle("LONG")
.setMinLength(1)
.setPlaceholder('Give us a reason to unban you.')
.setRequired(true),
new TextInputComponent()
.setCustomId("banreason-gba")
.setLabel("Why were you banned from asrp?")
.setStyle("LONG")
.setMinLength(1)
.setPlaceholder('Give us the reason you were banned for.')
.setRequired(true),
new SelectMenuComponent()
.setCustomId('fair-gba')
.setPlaceholder('Do you think your punishment was fair?')
.addOptions(
{
label: "Yes",
description: "You think the punishment was fair.",
value: "Yes",
emoji: "โ
"
},
{
label: "No",
description: "You think the punishment was unfair.",
value: "No, I think it's unfair.",
emoji: "โ"
}
)
);
showModal(modal, {
client: client,
interaction: interaction
})
}
});
client.on('modalSubmit', async modal => {
if (modal.customId === 'gbamodal') {
const RBXuser = modal.getTextInputValue('RobloxUsername-gba');
let BanMod = modal.getTextInputValue('Moderator-gba');
if (!BanMod) BanMod = 'None Stated';
const ReasonUnban = modal.getTextInputValue('unbanreason-gba');
const ReasonBan = modal.getTextInputValue('banreason-gba');
const Fairness = modal.getSelectMenuValues('fair-gba');
const user = modal.user
const appealEmbed = new MessageEmbed()
.setTitle(`New Game Ban Appeal`)
.setAuthor({ name: `User: ${user.tag} (${user.id})` })
.addFields(
{name: `Q: Roblox Username`, value: `A: ${RBXuser}`},
{name: `Q: Who banned you?`, value: `A: ${BanMod}`},
{name: `Q: Why should we unban you?`, value: `A: ${ReasonUnban}`},
{name: `Q: Why were you banned?`, value: `A: ${ReasonBan}`},
{name: `Q: Do you think the ban was fair?`, value: `A: ${Fairness}`}
)
.setFooter({ text: `This is beta, please report any errors.` })
.setThumbnail(user.displayAvatarURL({ dynamic: true, size: 512 }))
await modal.reply({ content: 'Your submission was recieved successfully!', ephemeral: true }).then(() => {
client.guilds.cache.get(`954881682429853726`).channels.cache.get('998833987810246666').send({ embeds: [appealEmbed] });
})
console.log(modal.getTextInputValue('RobloxUsername-gba'))
console.log(modal.getTextInputValue('Moderator-gba'))
console.log(modal.getTextInputValue('unbanreason-gba'))
console.log(modal.getTextInputValue('banreason-gba'))
console.log(modal.getSelectMenuValues('fair-gba'))
}
});
}
Extra Information:
Node Version: 'v16.14.2'
NPM Version: '8.5.0'
Discord.js Version: '^13.7.0'
Thank you in advance.
Select Menu's within Modals are unsupported and not documented by Discord - this is not a user issue nor an issue with the code.
Select Menu's just don't show up on mobile and only partially work within Modals (as of August 2022).
hey im trying to make a slashCommand that generate random pics with button..
so when a user use the command it will sent an embed with button and then the button when a user clicked that, the embed will edited and load another picture
but It seems i was doing it wrong..
Node: v17.7.2
Discord.js: 13.2.0
here is my code
const { MessageEmbed, MessageActionRow, MessageButton } = require('discord.js');
const superagent = require('superagent');
const ee = require("../../config.json");
module.exports = {
name: 'waifu',
description: 'Give you a random anime waifus pics',
run: async (client, interaction, args) => {
let { body } = await superagent.get(`https://api.waifu.pics/sfw/waifu`);
const msg = await interaction.followUp({
embeds: [
new MessageEmbed()
.setColor(ee.color)
.setTitle("Waifu ๐ณ")
.setImage(body.url)
.setTimestamp()
],
components: [
new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId('nextWaifu')
.setLabel('More Waifu')
.setStyle('SUCCESS')
)
],
fetchReply: true
});
let embed = msg.embeds
embed.color = ee.color;
embed.image = body.url;
let components = msg.components
return msg.edit({ embeds: [embed], components: [components], fetchReply: true });
}
}
I am making a ticket system, everything works fine except when I go onto a different account to test out what the ticket system looks like for the people using it, I try to react to the "Player Report", "Bug Report", etc... as seen in the code, it just says i am unable to use the buttons and then throws this error.
Full error:
C:\Users\wrigh\Documents\Discord Bots\Practice Bot - Copy\node_modules\discord.js\src\structures\interfaces\InteractionResponses.js:90
if (this.deferred || this.replied) throw new Error('INTERACTION_ALREADY_REPLIED');
^
Error [INTERACTION_ALREADY_REPLIED]: The reply to this interaction has already been sent or deferred.
at ButtonInteraction.reply (C:\Users\wrigh\Documents\Discord Bots\Practice Bot - Copy\node_modules\discord.js\src\structures\interfaces\InteractionResponses.js:90:46)
at C:\Users\wrigh\Documents\Discord Bots\Practice Bot - Copy\Events\Ticket\initialTicket.js:86:24
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async C:\Users\wrigh\Documents\Discord Bots\Practice Bot - Copy\Events\Ticket\initialTicket.js:79:9
at async Object.execute (C:\Users\wrigh\Documents\Discord Bots\Practice Bot - Copy\Events\Ticket\initialTicket.js:20:9) {
[Symbol(code)]: 'INTERACTION_ALREADY_REPLIED'
Ticket.js Code:
const { MessageEmbed, CommandInteraction, MessageActionRow, MessageButton } = require("discord.js");
const { OPENTICKET } = require("../../Structures/config.json");
module.exports = {
name: "ticket",
description: "Setup your ticket",
permission: "ADMINISTRATOR",
/**
*
* #param {CommandInteraction} interaction
*/
async execute(interaction) {
const { guild } = interaction;
const Embed = new MessageEmbed()
.setAuthor(
guild.name + " | Ticketing System",
guild.iconURL({ dynamic: true})
)
.setDescription(
"Open a ticket to discuss any of the issues listed on the button."
)
.setColor("BLUE");
const Buttons = new MessageActionRow();
Buttons.addComponents(
new MessageButton()
.setCustomId("player")
.setLabel("Player Report")
.setStyle("PRIMARY")
.setEmoji("๐ฎ"),
new MessageButton()
.setCustomId("bug")
.setLabel("Bug Report")
.setStyle("SECONDARY")
.setEmoji("โ"),
new MessageButton()
.setCustomId("other")
.setLabel("Other Report")
.setStyle("SUCCESS")
.setEmoji("โค"),
);
await guild.channels.cache
.get(OPENTICKET)
.send({ embeds: [Embed], components: [Buttons] });
interaction.reply({ content: "Done", ephemeral: true });
},
};
InitialTicket.js Code:
const { ButtonInteraction, MessageEmbed, MessageActionRow, MessageButton } = require("discord.js");
const DB = require("../../Structures/Handlers/Schemas/Ticket");
const { PARENTID, EVERYONEID } = require("../../Structures/config.json");
const Ticket = require("../../Structures/Handlers/Schemas/Ticket");
module.exports = {
name: "interactionCreate",
/**
*
* #param {ButtonInteraction} interaction
*/
async execute(interaction) {
if(!interaction.isButton()) return;
const { guild, member, customId } = interaction;
if (!["player", "bug", "other"].includes(customId)) return;
const ID = Math.floor(Math.random() * 90000) + 10000;
await guild.channels
.create(`${customId + "-" + ID}`, {
type: "GUILD_TEXT",
parent: PARENTID,
permissionOverwrites: [
{
id: member.id,
allow: ["SEND_MESSAGES", "VIEW_CHANNEL", "READ_MESSAGE_HISTORY"],
},
{
id: EVERYONEID,
deny: ["SEND_MESSAGES", "VIEW_CHANNEL", "READ_MESSAGE_HISTORY"],
},
],
})
.then(async (channel) => {
await DB.create({
GuildID: guild.id,
MemberID: member.id,
TicketID: ID,
ChannelID: channel.id,
Closed: false,
Locked: false,
Type: customId,
});
const Embed = new MessageEmbed()
.setAuthor(
`${guild.name} | Ticket: ${ID}`,
guild.iconURL({ dynamic: true })
)
.setDescription(
"Please wait patiently for a response from the Staff team, in the mean while, describe your issue in as much detail."
)
.setFooter("The buttons below are staff only buttons.");
const Buttons = new MessageActionRow();
Buttons.addComponents(
new MessageButton()
.setCustomId("close")
.setLabel("Save and close")
.setStyle("PRIMARY")
.setEmoji("๐พ"),
new MessageButton()
.setCustomId("lock")
.setLabel("lock")
.setStyle("SECONDARY")
.setEmoji("๐"),
new MessageButton()
.setCustomId("unlock")
.setLabel("unlock")
.setStyle("SUCCESS")
.setEmoji("๐"),
);
channel.send({
embeds: [Embed],
components: [Buttons],
});
await channel
.send({ content: `${member} here is your ticket` })
.then((m) => {
setTimeout(() => {
m.delete().catch(() => {});
}, 1 * 3000);
interaction.reply({
content: `${member} your ticket has been created: ${channel}`,
ephemeral: true
});
});
});
},
};
If you need to see any other parts of the bot please just ask, any help is rlly appreciated.
Any questions feel free to ask and I will try answer them to the best of my ability.
I am somewhat new to JavaScript and Node.js so please be patient with me.
Are these executed from the same button press/same interaction? If so, then set the reply that happens second to interaction.followUp() or interaction.editReply (depending on whether you want a second message (followUp) or to edit the existing message (editReply)).
So currently I'm making a ticket system which runs when a topic is selected via menu. However, the selection can't be undone automatically. Is there any way?
So I mean when I select the Bug topic and after the ticket being created, the select menu don't go back to Please select(The light letters) but I want to make that happen.
-- sorry for my poor english skills
+)
Currently when the menu is selected, we get input via modal and makes the ticket.
So
import Modal, { TextInputComponent } from '../../structures/Modal.js';
import { TextInputStyle } from 'discord-api-types/v9';
export const id = 'ticket-type';
function makeModel(type) {
return placeholders[type](new Modal()
.setCustomId('create-ticket')
.setTitle('ํฐ์ผ ๋ง๋ค๊ธฐ'));
}
const placeholders = {
report: (modal) => modal.addComponents(
new TextInputComponent()
.setCustomId('report')
.setLabel('์ ๊ณ ํ ์ฌ๋์ Minecraft IGN(๋๋ค์)์ ์์ฑํด์ฃผ์ธ์.')
.setPlaceholder('์์: komq')
.setRequired(true)
.setMaxLength(16),
new TextInputComponent()
.setCustomId('reason')
.setLabel('์๋ฐ๋ ๊ท์น์ ์จ์ฃผ์ธ์.')
.setPlaceholder('์์: ํต ์ฌ์ฉ')
.setRequired(true)
.setMaxLength(30),
),
feedback: (modal) => modal.addComponents(new TextInputComponent()
.setCustomId('feedback')
.setLabel('ํด๋น ์๋ฒ์๊ฒ ์ค ํผ๋๋ฐฑ ๋ด์ฉ์ ์์ฑํด์ฃผ์ธ์.')
.setPlaceholder('์์: ์ด ๋ฏธ๋๊ฒ์์ ์ด๋ฐ ๊ฒ ์์๋ค๋ฉด ์ข๊ฒ ์ด์.')
.setRequired(true)
.setMinLength(5)
.setMaxLength(500)
.setStyle(TextInputStyle.Paragraph)),
bug_report: (modal) => modal.addComponents(new TextInputComponent()
.setCustomId('bug_report')
.setLabel('๋ฐ๊ฒฌํ ๋ฒ๊ทธ๋ฅผ ์จ์ฃผ์ธ์. ์์ ๋ฑ์ ์ฒจ๋ถ ์๋ฃ๊ฐ ์์ผ๋ฉด ๋ ์ข์ต๋๋ค.')
.setPlaceholder('์์: ์ด ๋ฏธ๋๊ฒ์์์ ํน์ ํ๋์ ํ๋ฉด ๋ธ๋ก์ด ํ๊ดด๋ฉ๋๋ค.')
.setRequired(true)
.setMinLength(5)
.setMaxLength(500)
.setStyle(TextInputStyle.Paragraph)),
};
export async function onRun(menu) {
await makeModel(menu.values[0]).sendToInteraction(menu);
}
and after the input,
import { clientId, ticketCategoryId, ticketPingRoleId } from '../../constants/config.js';
import { MessageActionRow, MessageButton, MessageEmbed, Permissions } from 'discord.js';
import getTheme from '../../constants/themes.js';
export const id = 'create-ticket';
export const closeTicketRow = new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId('close-ticket')
.setLabel('ํฐ์ผ ๋ซ๊ธฐ')
.setEmoji('๐')
.setStyle('DANGER'),
);
const types = {
feedback: 'ํผ๋๋ฐฑ', bug_report: '๋ฒ๊ทธ ์ ๊ณ ', report: '์ ๊ณ ',
};
export async function onRun(ticket) {
const category = await ticket.guild.channels.fetch(ticketCategoryId);
const type = Object.keys(types).find((t) => ticket.getValue(t));
const channel = await category.createChannel(
'์์ฒญ ' + (Math.random() + 1).toString(36).substring(7), {
type: 'GUILD_TEXT',
topic: ticket.member.id,
permissionOverwrites: [
{
id: ticket.guild.roles.everyone.id,
deny: [Permissions.FLAGS.VIEW_CHANNEL],
},
{
id: ticket.member.id,
allow: [Permissions.FLAGS.VIEW_CHANNEL],
},
{
id: clientId,
allow: [Permissions.FLAGS.VIEW_CHANNEL],
},
],
},
);
ticket.reply({ content: 'ํฐ์ผ์ ์ ์ํ์ต๋๋ค!', ephemeral: true });
const embed = new MessageEmbed()
.setColor(getTheme('primary'))
.addField('์ฑ๋', `<#${channel.id}>`)
.setAuthor({ name: ticket.member.user.tag, iconURL: ticket.member.user.displayAvatarURL() })
.setTimestamp()
.addField('์ ํ', types[type]);
let send = ticket.getValue(type);
if (type === 'report') {
send += '์(๋ฅผ) ' + ticket.getValue('reason') + '(์ผ)๋ก ์ ๊ณ ํฉ๋๋ค.';
} else {
send = '```' + send + '```';
}
await channel.send({ embeds: [embed], components: [closeTicketRow] });
await channel.send(`<#&${ticketPingRoleId}>,\n${send}`);
}
I couldn't find any function to set the selected menu to default. So, I would be thankful if you give me the function and where should I run that.
So I made a discord selection menu ticket that when I select that category it makes a channel and send a message with a button. The button is supposed to delete the channel when pressed, but it doesn't seem to work. I think I have found the error but I don't know how to fix it. It is probably easy to fix but I'm stuck.
The code: (I think the error is located in the end here)
} else if (Discord.MessageButton.customId === 'del') {
const channel = message.guild.channel
channel.delete();
const Discord = require("discord.js");
const { MessageSelectMenu, MessageActionRow } = require("discord.js");
module.exports = {
name: "ticket",
author: "Falcone",
run: async(client, message, args) => {
if (!message.member.permissions.has("ADMINISTRATOR")) return message.reply('You Dont Have the `ADMINISTRATOR` permision');
message.delete();
let embed = new Discord.MessageEmbed()
.setColor("RANDOM")
.setDescription(`Test`)
.setThumbnail(message.guild.iconURL({ dynamic: true }))
.setAuthor(message.guild.name, message.guild.iconURL({ dynamic: true }));
let painel = new MessageActionRow().addComponents( new MessageSelectMenu()
.setCustomId('menu')
.setPlaceholder('Test') // Mensagem estampada
.addOptions([
{
label: 'Support',
description: '',
emoji: '๐โโ๏ธ',
value: '1',
},
{
label: 'Test',
description: '',
emoji: 'โ',
value: '2',
},
{
label: 'Test',
description: '',
emoji: '๐ค',
value: '3',
}
])
);
message.channel.send({ embeds: [embed], components: [painel] }).then(msg => {
const filtro = (interaction) =>
interaction.isSelectMenu()
const coletor = msg.createMessageComponentCollector({
filtro
});
coletor.on('collect', async (collected) => {
let ticket = collected.values[0]
collected.deferUpdate()
if (ticket === "1") {
const embed = new Discord.MessageEmbed()
.setTitle('Ticket')
.setDescription('Hello there, \n The staff will be here as soon as possible mean while tell us about your issue!\nThank You!')
.setColor('GREEN')
.setTimestamp()
const del = new MessageActionRow()
.addComponents(
new Discord.MessageButton()
.setCustomId('del')
.setLabel('๐๏ธ Delete Ticket!')
.setStyle('DANGER'),
);
message.guild.channels.create(`${collected.user.id}`, {
type : 'GUILD_TEXT',
permissionOverwrites : [
{
id : message.guild.id,
deny : ['VIEW_CHANNEL']
},
{
id : collected.user.id,
allow : ['VIEW_CHANNEL', 'SEND_MESSAGES', 'ATTACH_FILES']
}
]
}).then(async (msg) => {
msg.send({ embeds: [embed], components: [del] }).then(msg => msg.pin() );
})
} else if (Discord.MessageButton.customId === 'del') {
const channel = message.guild.channel
channel.delete();
}
})
});
}
}
MessageButton.customId is not a static property. That means it must be done on an instance, not the class. Something that you could try is this:
const msg = await message.channel.send({
content: "Which one?",
components: [
new Discord.MessageActionRow().addComponents([
new Discord.MessageButton().setLabel("Delete").setStyle("DANGER").setCustomId("DEL"), //delete button
new Discord.MessageButton().setLabel("Cancel").setStyle("DANGER").setCustomId("CAN") //cancel button
])
]
})
//Create button collector
const collector = msg.createMessageComponentCollector({
componentType: "BUTTON",
filter: (c) => c.member.id === msg.member.id,
max: 1
})
//Handle button click
collector.on("collect", i => {
if(i.customId === "CAN") return i.reply("Cancelled")
if(i.customId === "DEL") i.channel.delete() //or whatever channel you want to delete
})
Warning: I did not test this code. You can tell me any problems you have and I will try to modify this