bot: extract ticket closing login into action
vi did:web:vt3e.cat
Tue, 23 Jun 2026 20:24:42 +0100
3 files changed,
52 insertions(+),
13 deletions(-)
M
apps/bot/src/commands/tickets/actions.ts
→
apps/bot/src/commands/tickets/actions.ts
@@ -11,10 +11,12 @@ import { Result } from "@sapphire/framework";
import db, { desc, + editTicket, eq, getGuildByDiscordId, getTicketByChannelId, tickets, + type Actor, } from "@stealth-developers/db"; export * from "./config";@@ -100,7 +102,8 @@ createdChannel = channel;
const greeting = dbGuild.ticketGreeting; if (greeting) { - const container = new ContainerBuilder() + const greetingContainer = new ContainerBuilder() + .setAccentColor(0x3a9027) .addTextDisplayComponents( new TextDisplayBuilder({ content: greeting.replaceAll("{user}", `<@${subjectUser.discordId}>`),@@ -113,7 +116,28 @@ TicketButtonPresets.close(publicId),
), ); - channel.send({ components: [container], flags: ["IsComponentsV2"] }); + const uploadContainer = new ContainerBuilder() + .setAccentColor(0x3a9027) + .addTextDisplayComponents( + new TextDisplayBuilder({ + content: [ + "# Uploading Videos\n", + "You can either upload your video directly to this channel, or", + "you can use the button below to upload it directly to us, which", + "allows you to upload videos up to 2GB in size.", + ].join(" "), + }), + ) + .addActionRowComponents( + new ActionRowBuilder<ButtonBuilder>().addComponents( + TicketButtonPresets.upload(publicId), + ), + ); + + channel.send({ + components: [greetingContainer, uploadContainer], + flags: ["IsComponentsV2"], + }); } await tx.update(tickets).set({ channelId: channel.id }).where(eq(tickets.id, ticket.id));@@ -151,3 +175,20 @@ if (!ticket) throw new PublicError("Failed to close ticket: Ticket not found in database");
return TicketModalPresets.close(ticket.id, Boolean(dbUser.moderator)); } + +export async function closeTicket( + user: Actor, + ticketId: string, + reasons: { public: string; private?: string | null }, +) { + const result = await editTicket(ticketId, { + closedAt: new Date(), + closeReason: reasons.public, + privateReason: reasons.private, + closedBy: user.id, + status: "closed", + }); + + if (!result) throw new PublicError("Failed to close ticket: Ticket not found in database"); + return result; +}
M
apps/bot/src/components/modals/tickets/index.ts
→
apps/bot/src/components/modals/tickets/index.ts
@@ -2,9 +2,10 @@ import { TextInputBuilder, LabelBuilder, ModalBuilder } from "discord.js";
import { TextInputStyle } from "discord-api-types/v9"; import { option } from "@purrkit/router"; -import { editTicket, getTicket } from "@stealth-developers/db"; +import { getTicket } from "@stealth-developers/db"; import { kitten } from "@/client"; import { errorMessage, upsertUser } from "@/lib"; +import * as actions from "@/commands/tickets/actions"; export const closeTicketModal = kitten.modal("close-ticket", { options: {@@ -26,15 +27,7 @@ public: interaction.fields.getTextInputValue("reason:public"),
private: user.moderator ? interaction.fields.getTextInputValue("reason:private") : undefined, }; - const result = await editTicket(ticketId, { - closedAt: new Date(), - closeReason: reasons.public, - privateReason: reasons.private, - closedBy: user.id, - status: "closed", - }); - - if (!result) return errorMessage(interaction, "Failed to close ticket"); + await actions.closeTicket(user, ticket.id, reasons); return interaction.followUp({ content: "Ticket closed successfully" }); }, });