change message with cool embed
This commit is contained in:
parent
780bd5f957
commit
e8413fe863
|
@ -1,9 +1,8 @@
|
||||||
{
|
{
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"run": "tsx src/index.ts",
|
||||||
"start": "node dist/index.js",
|
"register": "tsx src/index.ts --register"
|
||||||
"dev": "tsx src/index.ts"
|
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
24
src/award_message.ts
Normal file
24
src/award_message.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { EmbedBuilder, MessageReaction, PartialMessageReaction } from 'discord.js';
|
||||||
|
|
||||||
|
export default function awardEmbed(reaction: MessageReaction | PartialMessageReaction) {
|
||||||
|
function formatTime(time: Date) {
|
||||||
|
const yyyy = time.getFullYear();
|
||||||
|
const mm = time.getMonth().toString().padStart(2, '0');
|
||||||
|
const dd = time.getDate().toString().padStart(2, '0');
|
||||||
|
const hh = time.getHours().toString().padStart(2, '0');
|
||||||
|
const MM = time.getMinutes().toString().padStart(2, '0');
|
||||||
|
return `${yyyy}-${mm}-${dd} ${hh}:${MM}`;
|
||||||
|
}
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setColor(0x777777)
|
||||||
|
.setAuthor({
|
||||||
|
name: reaction.message.author?.displayName || "unknown",
|
||||||
|
iconURL: reaction.message.author?.avatarURL() || undefined,
|
||||||
|
})
|
||||||
|
.setDescription(reaction.message.content || null)
|
||||||
|
.setThumbnail(reaction.message.attachments.filter((attachment) => !(!attachment.height && !attachment.width)).first()?.url || null)
|
||||||
|
.addFields({
|
||||||
|
name: `${reaction.emoji.name} x${reaction.count} `,
|
||||||
|
value: `in <#${reaction.message.channelId}> • ${formatTime(reaction.message.createdAt)}\n-# ${reaction.message.id}`,
|
||||||
|
})
|
||||||
|
}
|
83
src/commands.ts
Normal file
83
src/commands.ts
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
import { SlashCommandBuilder, SlashCommandSubcommandBuilder } from '@discordjs/builders';
|
||||||
|
|
||||||
|
const output = new SlashCommandSubcommandBuilder()
|
||||||
|
.setName('output')
|
||||||
|
.setDescription('Set the output channel')
|
||||||
|
.addChannelOption(option =>
|
||||||
|
option.setName('channel')
|
||||||
|
.setDescription('The channel to send messages to')
|
||||||
|
.setRequired(true));
|
||||||
|
const channels = new SlashCommandSubcommandBuilder()
|
||||||
|
.setName('channels')
|
||||||
|
.setDescription('Configure channel list')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('add_remove')
|
||||||
|
.setDescription('add_remove')
|
||||||
|
.setRequired(true)
|
||||||
|
.addChoices(
|
||||||
|
{ name: 'Add', value: 'add' },
|
||||||
|
{ name: 'Remove', value: 'remove' }
|
||||||
|
))
|
||||||
|
.addChannelOption(option =>
|
||||||
|
option.setName('channel')
|
||||||
|
.setDescription('The channel to list')
|
||||||
|
.setRequired(true));
|
||||||
|
const channels_type = new SlashCommandSubcommandBuilder()
|
||||||
|
.setName('channels_type')
|
||||||
|
.setDescription('Set the channel list type')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('channels_type')
|
||||||
|
.setDescription('include or exclude')
|
||||||
|
.setRequired(true)
|
||||||
|
.addChoices(
|
||||||
|
{ name: 'Include', value: 'include' },
|
||||||
|
{ name: 'Exclude', value: 'exclude' }
|
||||||
|
));
|
||||||
|
const emojis = new SlashCommandSubcommandBuilder()
|
||||||
|
.setName('emojis')
|
||||||
|
.setDescription('Configure emoji list')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('add_remove')
|
||||||
|
.setDescription('add_remove')
|
||||||
|
.setRequired(true)
|
||||||
|
.addChoices(
|
||||||
|
{ name: 'Add', value: 'add' },
|
||||||
|
{ name: 'Remove', value: 'remove' }
|
||||||
|
))
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('emoji')
|
||||||
|
.setDescription('The emoji to list')
|
||||||
|
.setRequired(true));
|
||||||
|
const emojis_type = new SlashCommandSubcommandBuilder()
|
||||||
|
.setName('emojis_type')
|
||||||
|
.setDescription('Set the emoji list type')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('emojis_type')
|
||||||
|
.setDescription('include or exclude')
|
||||||
|
.setRequired(true)
|
||||||
|
.addChoices(
|
||||||
|
{ name: 'Include', value: 'include' },
|
||||||
|
{ name: 'Exclude', value: 'exclude' }
|
||||||
|
));
|
||||||
|
const count = new SlashCommandSubcommandBuilder()
|
||||||
|
.setName('count')
|
||||||
|
.setDescription('Set the number of reactions to trigger')
|
||||||
|
.addIntegerOption(option =>
|
||||||
|
option.setName('count')
|
||||||
|
.setDescription('The number of reactions to trigger')
|
||||||
|
.setRequired(true));
|
||||||
|
|
||||||
|
|
||||||
|
const config = new SlashCommandBuilder()
|
||||||
|
.setName('config')
|
||||||
|
.setDescription('Configure the bot')
|
||||||
|
.addSubcommand(output)
|
||||||
|
.addSubcommand(channels)
|
||||||
|
.addSubcommand(channels_type)
|
||||||
|
.addSubcommand(emojis)
|
||||||
|
.addSubcommand(emojis_type)
|
||||||
|
.addSubcommand(count);
|
||||||
|
|
||||||
|
const commands = [config];
|
||||||
|
export default commands;
|
||||||
|
|
|
@ -2,7 +2,7 @@ import fs from 'fs';
|
||||||
|
|
||||||
import { Entry } from './entry.ts';
|
import { Entry } from './entry.ts';
|
||||||
|
|
||||||
export function writeConfig(entries: Entry[]) {
|
export async function writeConfig(entries: Entry[]) {
|
||||||
const data = JSON.stringify(entries, null, 2);
|
const data = JSON.stringify(entries, null, 2);
|
||||||
fs.writeFile('./config.json', data, (err) => {
|
fs.writeFile('./config.json', data, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
20
src/entry.ts
20
src/entry.ts
|
@ -1,12 +1,18 @@
|
||||||
|
export enum Type {
|
||||||
|
INCLUDE = "include",
|
||||||
|
EXCLUDE = "exclude"
|
||||||
|
}
|
||||||
|
|
||||||
export class Entry {
|
export class Entry {
|
||||||
server: string;
|
server: string;
|
||||||
channel: string;
|
output_channel: string = "";
|
||||||
emoji: string;
|
output_hook: string = "";
|
||||||
count: number;
|
channel_type: Type = Type.EXCLUDE;
|
||||||
constructor(server: string, channel: string, emoji: string, count: number) {
|
channels: string[] = [];
|
||||||
|
emoji_type: Type = Type.EXCLUDE;
|
||||||
|
emojis: string[] = [];
|
||||||
|
count: number = 3;
|
||||||
|
constructor(server: string) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.channel = channel;
|
|
||||||
this.emoji = emoji;
|
|
||||||
this.count = count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
250
src/index.ts
250
src/index.ts
|
@ -1,3 +1,24 @@
|
||||||
|
import 'dotenv/config'
|
||||||
|
const TOKEN = process.env.TOKEN;
|
||||||
|
const CLIENT_ID = process.env.CLIENT_ID;
|
||||||
|
if (!TOKEN || !CLIENT_ID) {
|
||||||
|
console.error(`No ${TOKEN ? "CLIENT_ID" : "TOKEN"} provided`);
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
import commands from "./commands.ts";
|
||||||
|
|
||||||
|
if (process.argv.includes("--register")) {
|
||||||
|
const rest = new REST({ version: "10" }).setToken(TOKEN);
|
||||||
|
try {
|
||||||
|
console.log("refreshing slash commands...");
|
||||||
|
await rest.put(Routes.applicationCommands(CLIENT_ID), { body: commands });
|
||||||
|
console.log("OK");
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
import {
|
import {
|
||||||
REST,
|
REST,
|
||||||
Routes,
|
Routes,
|
||||||
|
@ -5,99 +26,173 @@ import {
|
||||||
Partials,
|
Partials,
|
||||||
GatewayIntentBits,
|
GatewayIntentBits,
|
||||||
Events,
|
Events,
|
||||||
|
TextChannel,
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
|
|
||||||
import { writeConfig, readConfig } from "./config.ts";
|
import { writeConfig, readConfig } from "./config.ts";
|
||||||
|
|
||||||
import 'dotenv/config'
|
|
||||||
const TOKEN = process.env.TOKEN;
|
|
||||||
const CLIENT_ID = process.env.CLIENT_ID;
|
|
||||||
if (!TOKEN) {
|
|
||||||
console.error("No token provided");
|
|
||||||
process.exit();
|
|
||||||
}
|
|
||||||
if (!CLIENT_ID) {
|
|
||||||
console.error("No client ID provided");
|
|
||||||
process.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
const rest = new REST({ version: "10" }).setToken(TOKEN);
|
|
||||||
try {
|
|
||||||
console.log("refreshing slash commands...");
|
|
||||||
await rest.put(Routes.applicationCommands(CLIENT_ID), {
|
|
||||||
body: [
|
|
||||||
{
|
|
||||||
name: "config",
|
|
||||||
description: "Replies with the channel ID",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
console.log("OK");
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
intents: [
|
intents: [
|
||||||
GatewayIntentBits.Guilds,
|
GatewayIntentBits.Guilds,
|
||||||
GatewayIntentBits.GuildMessages,
|
GatewayIntentBits.GuildMessages,
|
||||||
GatewayIntentBits.GuildMessageReactions,
|
GatewayIntentBits.GuildMessageReactions,
|
||||||
|
GatewayIntentBits.MessageContent,
|
||||||
],
|
],
|
||||||
partials: [Partials.Message, Partials.Channel, Partials.Reaction],
|
partials: [Partials.Message, Partials.Channel, Partials.Reaction],
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on("ready", () => {
|
client.on("ready", () => {
|
||||||
if (!client.user) return;
|
if (!client.user) {
|
||||||
|
console.error("Failed to login");
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`Logged in as ${client.user.tag}!`);
|
console.log(`Logged in as ${client.user.tag}!`);
|
||||||
|
client.user.setActivity("👑let's award funny messages!");
|
||||||
});
|
});
|
||||||
|
|
||||||
import { Entry } from "./entry.ts";
|
import { Entry, Type } from "./entry.ts";
|
||||||
const entries: Entry[] = readConfig();
|
const entries: Entry[] = readConfig();
|
||||||
|
writeConfig(entries);
|
||||||
|
|
||||||
import modal from "./modal/configure.ts";
|
|
||||||
client.on("interactionCreate", async (interaction) => {
|
client.on("interactionCreate", async (interaction) => {
|
||||||
if (!interaction.isChatInputCommand()) return;
|
if (interaction.isChatInputCommand()) {
|
||||||
|
|
||||||
if (interaction.commandName === "config") {
|
if (interaction.commandName === "config") {
|
||||||
await interaction.showModal(modal);
|
if (interaction.user.id !== interaction.guild?.ownerId) {
|
||||||
}
|
|
||||||
});
|
|
||||||
client.on(Events.InteractionCreate, async (interaction) => {
|
|
||||||
if (!interaction.isModalSubmit()) return;
|
|
||||||
if (interaction.customId === "config") {
|
|
||||||
const emoji = interaction.fields.getTextInputValue("emoji");
|
|
||||||
const count = parseInt(interaction.fields.getTextInputValue("count"));
|
|
||||||
const channelId = interaction.fields.getTextInputValue("channelId");
|
|
||||||
const serverId = interaction.guildId;
|
|
||||||
if (!emoji || !channelId) {
|
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
content: "Please fill out all fields",
|
content: "Only the server owner can configure the bot",
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (serverId === null) {
|
const subcommand = interaction.options.getSubcommand(true);
|
||||||
return;
|
if (subcommand === "output") {
|
||||||
}
|
const channel = interaction.options.getChannel("channel", true);
|
||||||
|
try {
|
||||||
console.log(`Set entry: ${serverId} -> ${channelId} (${emoji})`);
|
await interaction.deferReply({ ephemeral: true, });
|
||||||
const entry = entries.find((entry) => entry.server === serverId);
|
let entry = entries.find((entry) => entry.server === interaction.guildId);
|
||||||
if (entry) {
|
if (!entry) {
|
||||||
entry.channel = channelId;
|
entry = new Entry(interaction.guildId!);
|
||||||
entry.emoji = emoji;
|
entries.push(entry);
|
||||||
entry.count = count;
|
|
||||||
} else {
|
|
||||||
entries.push(new Entry(serverId, channelId, emoji, count));
|
|
||||||
}
|
}
|
||||||
|
entry.output_channel = channel.id;
|
||||||
writeConfig(entries);
|
writeConfig(entries);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
await interaction.followUp({
|
||||||
|
content: `Set output to <#${channel.id}>`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (subcommand === "channels") {
|
||||||
|
const channel = interaction.options.getChannel("channel", true);
|
||||||
|
const mode = interaction.options.getString("add_remove", true);
|
||||||
|
try {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
let entry = entries.find((entry) => entry.server === interaction.guildId);
|
||||||
|
if (!entry) {
|
||||||
|
entry = new Entry(interaction.guildId!);
|
||||||
|
entries.push(entry);
|
||||||
|
}
|
||||||
|
if (mode === "add") entry.channels.push(channel.id);
|
||||||
|
else entry.channels = entry.channels.filter((c) => c !== channel.id);
|
||||||
|
writeConfig(entries);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
await interaction.followUp({
|
||||||
|
content: `Set to watch for reactions in <#${channel.id}>`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (subcommand === "channels_type") {
|
||||||
|
const channel_type = interaction.options.getString("channels_type", true);
|
||||||
|
try {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
|
||||||
await interaction.reply({
|
let entry = entries.find((entry) => entry.server === interaction.guildId);
|
||||||
content: `Set to send messages to <#${channelId}>, watching for ${emoji}`,
|
if (!entry) {
|
||||||
|
entry = new Entry(interaction.guildId!);
|
||||||
|
entries.push(entry);
|
||||||
|
}
|
||||||
|
entry.channel_type = channel_type as Type;
|
||||||
|
writeConfig(entries);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
await interaction.followUp({
|
||||||
|
content: `channel list type set to ${channel_type}`,
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} else if (subcommand === "emojis") {
|
||||||
|
const emoji = interaction.options.getString("emoji", true);
|
||||||
|
const mode = interaction.options.getString("add_remove", true);
|
||||||
|
try {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
let entry = entries.find(
|
||||||
|
(entry) => entry.server === interaction.guildId
|
||||||
|
);
|
||||||
|
if (!entry) {
|
||||||
|
entry = new Entry(interaction.guildId!);
|
||||||
|
entries.push(entry);
|
||||||
|
}
|
||||||
|
if (mode === "add") entry.emojis.push(emoji);
|
||||||
|
else entry.emojis = entry.emojis.filter((e) => e !== emoji);
|
||||||
|
await writeConfig(entries);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
await interaction.followUp({
|
||||||
|
content: `Set to watch for ${emoji}`,
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (subcommand === "emojis_type") {
|
||||||
|
const emoji_type = interaction.options.getString("emojis_type", true);
|
||||||
|
try {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
let entry = entries.find(
|
||||||
|
(entry) => entry.server === interaction.guildId
|
||||||
|
);
|
||||||
|
if (!entry) {
|
||||||
|
entry = new Entry(interaction.guildId!);
|
||||||
|
entries.push(entry);
|
||||||
|
}
|
||||||
|
entry.emoji_type = emoji_type as Type;
|
||||||
|
writeConfig(entries);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
await interaction.followUp({
|
||||||
|
content: `emoji list type set to ${emoji_type}`,
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (subcommand === "count") {
|
||||||
|
const count = interaction.options.getInteger("count", true);
|
||||||
|
try {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
let entry = entries.find(
|
||||||
|
(entry) => entry.server === interaction.guildId
|
||||||
|
);
|
||||||
|
if (!entry) {
|
||||||
|
entry = new Entry(interaction.guildId!);
|
||||||
|
entries.push(entry);
|
||||||
|
}
|
||||||
|
entry.count = count;
|
||||||
|
await writeConfig(entries);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
await interaction.followUp({
|
||||||
|
content: `The number needed to trigger is now ${count}`,
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
import awardEmbed from "./award_message.ts";
|
||||||
client.on(Events.MessageReactionAdd, async (reaction, user) => {
|
client.on(Events.MessageReactionAdd, async (reaction, user) => {
|
||||||
if (reaction.partial) {
|
if (reaction.partial) {
|
||||||
try {
|
try {
|
||||||
|
@ -109,25 +204,26 @@ client.on(Events.MessageReactionAdd, async (reaction, user) => {
|
||||||
}
|
}
|
||||||
if (!reaction.message.guild) return;
|
if (!reaction.message.guild) return;
|
||||||
|
|
||||||
const entry = entries.find(
|
const entry = entries.find((entry) => entry.server === reaction.message.guildId);
|
||||||
(entry) => entry.server === reaction.message.guildId
|
if (entry === undefined) return;
|
||||||
);
|
if ((entry.channel_type === Type.EXCLUDE) === entry.channels.includes(reaction.message.channelId)) return;
|
||||||
if (
|
if ((entry.emoji_type === Type.EXCLUDE) === entry.emojis.includes(`${reaction.emoji.name}`)) return;
|
||||||
!entry ||
|
|
||||||
reaction.emoji.name !== entry.emoji ||
|
|
||||||
reaction.count === null ||
|
|
||||||
reaction.count < entry.count
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const channel = await client.channels.fetch(entry.channel);
|
if (reaction.count === null || reaction.count < entry.count) return;
|
||||||
if (channel === null || !channel.isTextBased() || channel.isDMBased()) return;
|
|
||||||
|
|
||||||
if (reaction.count === entry.count) {
|
const channel = reaction.message.guild.channels.cache.get(entry.output_channel) as TextChannel;
|
||||||
await channel.send(
|
channel.messages.fetch({ limit: 5 }).then((messages) => {
|
||||||
`🎉 ${reaction.count} people have reacted with ${entry.emoji}! 🎉`
|
messages.find((message) => {
|
||||||
);
|
if (message.embeds[0]?.fields[0].value.includes(reaction.message.id)) {
|
||||||
|
message.delete();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
channel.send({
|
||||||
|
embeds: [awardEmbed(reaction)]
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
client.login(TOKEN);
|
client.login(TOKEN);
|
|
@ -1,42 +0,0 @@
|
||||||
import {
|
|
||||||
ModalBuilder,
|
|
||||||
TextInputBuilder,
|
|
||||||
ActionRowBuilder,
|
|
||||||
TextInputStyle,
|
|
||||||
ModalActionRowComponentBuilder,
|
|
||||||
} from 'discord.js';
|
|
||||||
|
|
||||||
const modal = new ModalBuilder()
|
|
||||||
.setCustomId('config')
|
|
||||||
.setTitle('Configuration');
|
|
||||||
|
|
||||||
const emojiInput = new TextInputBuilder()
|
|
||||||
.setCustomId('emoji')
|
|
||||||
.setLabel('Emoji')
|
|
||||||
.setStyle(TextInputStyle.Short)
|
|
||||||
.setPlaceholder('Enter the emoji')
|
|
||||||
.setValue('⭐')
|
|
||||||
.setRequired(true);
|
|
||||||
|
|
||||||
const countInput = new TextInputBuilder()
|
|
||||||
.setCustomId('count')
|
|
||||||
.setLabel('Count')
|
|
||||||
.setStyle(TextInputStyle.Short)
|
|
||||||
.setPlaceholder('Enter the count')
|
|
||||||
.setValue('5')
|
|
||||||
.setRequired(true);
|
|
||||||
|
|
||||||
const channelIdInput = new TextInputBuilder()
|
|
||||||
.setCustomId('channelId')
|
|
||||||
.setLabel('Channel ID')
|
|
||||||
.setStyle(TextInputStyle.Short)
|
|
||||||
.setPlaceholder('Enter the channel ID')
|
|
||||||
.setRequired(true);
|
|
||||||
|
|
||||||
const first = new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(emojiInput)
|
|
||||||
const second = new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(countInput)
|
|
||||||
const third = new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(channelIdInput)
|
|
||||||
|
|
||||||
modal.addComponents(first, second, third);
|
|
||||||
|
|
||||||
export default modal;
|
|
Loading…
Reference in New Issue
Block a user