feat(tickets): /manage-ticket command
vi v@vt3e.cat
Thu, 26 Feb 2026 21:51:49 +0000
3 files changed,
225 insertions(+),
193 deletions(-)
D
src/interactions/buttons/tickets/message.ts
@@ -1,151 +0,0 @@
-import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - type ChatInputCommandInteraction, - type Client, - ContainerBuilder, - type GuildMember, - LabelBuilder, - ModalBuilder, - type ModalSubmitInteraction, - SlashCommandBuilder, - TextDisplayBuilder, - TextInputBuilder, - TextInputStyle, -} from "discord.js"; - -import { makeComponentId } from "@/utils/components"; -import { formatMessage } from "@/utils/formatting"; -import { loggers } from "@/utils/logging"; -import { hasManagerPermissions } from "@/utils/permissions"; -import { getGuild } from "@/utils/queries"; - -const logger = loggers.interactions.child({ name: "messageCommand" }); - -const commandData = new SlashCommandBuilder() - .setName("ticket-message") - .setDescription("Send the ticket message in the designated channel") - .addChannelOption((c) => - c - .setName("channel") - .setDescription("The channel to send the ticket message in") - .setRequired(true), - ); - -const MODAL_ID = makeComponentId(commandData, "message"); -const INPUT_ID = "message_content"; - -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { - if (!interaction.guild || !interaction.member) { - await interaction.reply({ - content: "❌ This command can only be used in a server.", - flags: ["Ephemeral"], - }); - return; - } - - const hasPerms = await hasManagerPermissions( - interaction.member as GuildMember, - ); - if (!hasPerms) { - await interaction.reply({ - content: "❌ You don't have permission to use this command.", - flags: ["Ephemeral"], - }); - return; - } - - const targetChannel = interaction.options.getChannel("channel", true); - - // construct & show the modal - const textInput = new LabelBuilder() - .setLabel("Message Content") - .setTextInputComponent( - new TextInputBuilder() - .setCustomId(INPUT_ID) - .setStyle(TextInputStyle.Paragraph) - .setRequired(true), - ); - - await interaction.showModal( - new ModalBuilder() - .setCustomId(`${MODAL_ID}:${targetChannel.id}`) - .setTitle("Ticket Message") - .setLabelComponents(textInput), - ); -} - -async function modalExecute( - _client: Client, - interaction: ModalSubmitInteraction, -) { - if (!interaction.guild || !interaction.member) return; - - const channelId = interaction.customId.split(":")[2]; - - const { data: guildData } = await getGuild(interaction.guild.id); - const channel = interaction.guild.channels.cache.get(channelId); - if (!channel) { - await interaction.reply({ - content: "❌ The channel specified is invalid.", - flags: ["Ephemeral"], - }); - return; - } - - if (!channel.isSendable()) { - await interaction.reply({ - content: "❌ I'm not able to send messages in the specified channel.", - flags: ["Ephemeral"], - }); - return; - } - - const message = interaction.fields.getTextInputValue(INPUT_ID); - const formatted = formatMessage(message, interaction); - - const controls = new ActionRowBuilder<ButtonBuilder>().addComponents( - new ButtonBuilder() - .setCustomId("ticket:create") - .setLabel("Open a Ticket") - .setEmoji("📩") - .setStyle(ButtonStyle.Success), - ); - - const container = new ContainerBuilder() - .addTextDisplayComponents(new TextDisplayBuilder().setContent(formatted)) - .addActionRowComponents(controls); - - const sent = await channel - .send({ components: [container], flags: ["IsComponentsV2"] }) - .catch((err) => { - logger.error({ err, channelId }, "Failed to send ticket message"); - return null; - }); - - if (!sent) { - await interaction.reply({ - content: "❌ Failed to send the message in the specified channel.", - flags: ["Ephemeral"], - }); - return; - } - - await interaction.reply({ - content: `✅ Message sent successfully! ${sent.url}`, - flags: ["Ephemeral"], - allowedMentions: { - users: [], - }, - }); -} - -export default { - data: commandData, - execute, - modalExecute, -};