import { Result } from "@sapphire/framework"; import { LabelBuilder, MessageFlags, ModalBuilder, TextInputBuilder, TextInputStyle, } from "discord.js"; import { option } from "@purrkit/router"; import db, { addTicketComment, eq, getActorByDiscordIdAndGuildDiscordId, getGuildByDiscordId, getTicket, guilds, } from "@stealth-developers/db"; import { kitten } from "@/client"; import { errorMessage, handleError, upsertUser } from "@/lib"; import * as actions from "./actions"; export const configTextModal = kitten.modal("config-text", { options: { key: option.string({ required: true }), }, run: async (interaction, { key }) => { const value = interaction.fields.getTextInputValue("text-value"); if (!interaction.guildId) return errorMessage(interaction, "This interaction can only be used in a server."); const guild = await getGuildByDiscordId(interaction.guildId); if (!guild) return errorMessage(interaction, "Failed to update configuration: Guild not found."); const [res] = await db .update(guilds) .set({ [key]: value }) .where(eq(guilds.id, guild.id)) .returning(); if (!res) return errorMessage(interaction, "Failed to update configuration."); return interaction.reply({ content: "Configuration updated successfully!", flags: [MessageFlags.Ephemeral], }); }, }); export const closeTicketModal = kitten.modal("close-ticket", { options: { ticketId: option.string({ required: true }), }, run: async (interaction, { ticketId }) => { await interaction.deferReply({ flags: ["Ephemeral"] }); if (!interaction.guild) return errorMessage(interaction, "You must run this command in a guild"); const ticket = await getTicket(ticketId); if (!ticket) return errorMessage(interaction, "Ticket not found"); const user = await upsertUser(interaction.user, interaction.guild); if (!user) return errorMessage(interaction, "Failed to upsert user"); const reasons = { public: interaction.fields.getTextInputValue("reason:public"), private: user.moderator ? interaction.fields.getTextInputValue("reason:private") : undefined, }; const result = await Result.fromAsync(actions.closeTicket(user, ticket.id, reasons)); if (result.isErr()) return handleError(interaction, result.unwrapErr(), "Failed to close ticket."); return interaction.followUp({ content: "Ticket closed successfully" }); }, }); export const commentModal = kitten.modal("m-comment-modal", { options: { ticketId: option.string({ required: true }), }, async run(interaction, { ticketId }) { if (!interaction.guild) return; const actor = await getActorByDiscordIdAndGuildDiscordId( interaction.user.id, interaction.guild.id, ); if (!actor) return interaction.reply({ content: "You are not a moderator", flags: ["Ephemeral"] }); await addTicketComment({ actorId: actor.id, content: interaction.fields.getTextInputValue("comment"), ticketId, }); await interaction.reply({ content: "Comment added successfully", flags: ["Ephemeral"] }); }, }); export const TicketModalPresets = { close: (id: string, isModerator: boolean) => { const description = isModerator ? "The reason for closing the ticket; this will be shared with the user" : "The reason for closing the ticket"; const reasonLabel = new LabelBuilder() .setLabel("Reason") .setDescription(description) .setTextInputComponent( new TextInputBuilder() .setStyle(TextInputStyle.Paragraph) .setCustomId("reason:public") .setRequired(true), ); const privateReasonLabel = new LabelBuilder() .setLabel("Private Reason") .setDescription("The reason for closing the ticket.") .setTextInputComponent( new TextInputBuilder() .setStyle(TextInputStyle.Paragraph) .setCustomId("reason:private") .setRequired(isModerator), ); const labels = isModerator ? [reasonLabel, privateReasonLabel] : [reasonLabel]; const modal = new ModalBuilder() .setCustomId(closeTicketModal.id({ ticketId: id })) .setTitle("Close ticket") .addLabelComponents(...labels); return modal; }, comment: (id: string) => { const commentLabel = new LabelBuilder() .setLabel("Comment") .setDescription("The comment to add to the ticket") .setTextInputComponent( new TextInputBuilder() .setStyle(TextInputStyle.Paragraph) .setCustomId("comment") .setRequired(true), ); const modal = new ModalBuilder() .setCustomId(commentModal.id({ ticketId: id })) .setTitle("Add comment") .addLabelComponents(commentLabel); return modal; }, }; export const TicketModals = [closeTicketModal, configTextModal, commentModal];