diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index 052bdfa..13ab9f8 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -1,7 +1,8 @@ import { transformInteraction, kCommands, type CommandMap, logger } from "@yuudachi/framework"; import type { Event } from "@yuudachi/framework/types"; -import { ApplicationCommandType, Events, Client } from "discord.js"; +import { ApplicationCommandType, Events, Client, PermissionFlagsBits, ButtonStyle, ComponentType } from "discord.js"; import { injectable, inject } from "tsyringe"; +import { CUSTOM_ID_SEPARATOR } from "../util/constants.js"; @injectable() export default class implements Event { @@ -13,6 +14,66 @@ export default class implements Event { public execute() { this.client.on(this.event, async (interaction) => { + if (!interaction.inCachedGuild()) { + return; + } + + if (interaction.isButton()) { + try { + const [idPrefix] = interaction.customId.split(CUSTOM_ID_SEPARATOR); + switch (idPrefix) { + case "solved": { + const { channel, member, channelId } = interaction; + if (!channel?.isThread()) { + return; + } + + if ( + channel.ownerId !== interaction.user.id && + !member.permissionsIn(channelId).has(PermissionFlagsBits.ManageMessages) + ) { + await interaction.reply({ + ephemeral: true, + content: "Only the original poster or support staff can close a thread!", + }); + return; + } + + await interaction.update({ + components: [ + { + type: ComponentType.ActionRow, + components: [ + { + type: ComponentType.Button, + customId: "solved", + style: ButtonStyle.Secondary, + label: "Marked as resolved", + emoji: "🔒", + disabled: true, + }, + ], + }, + ], + }); + + await channel.edit({ + locked: true, + archived: true, + }); + + break; + } + + default: + break; + } + } catch (error_) { + const error = error_ as Error; + logger.error(error, error.message); + } + } + if ( !interaction.isCommand() && !interaction.isUserContextMenuCommand() && @@ -22,10 +83,6 @@ export default class implements Event { return; } - if (!interaction.inCachedGuild()) { - return; - } - const command = this.commands.get(interaction.commandName.toLowerCase()); if (command) { try { diff --git a/src/events/threadCreate.ts b/src/events/threadCreate.ts index bac9e1b..c1d0322 100644 --- a/src/events/threadCreate.ts +++ b/src/events/threadCreate.ts @@ -3,7 +3,7 @@ import { setTimeout as wait } from "node:timers/promises"; import { logger } from "@yuudachi/framework"; import type { Event } from "@yuudachi/framework/types"; import type { ThreadChannel } from "discord.js"; -import { Events, Client } from "discord.js"; +import { Events, Client, ComponentType, ButtonStyle } from "discord.js"; import { injectable } from "tsyringe"; import { ASSISTCHANNELS } from "../util/constants.js"; @@ -30,7 +30,22 @@ export default class implements Event { "- Show your code!", "- Explain what exactly your issue is.", "- Not a discord.js issue? Check out <#237743386864517122>.", + "- Issue solved? Press the button!", ].join("\n"), + components: [ + { + type: ComponentType.ActionRow, + components: [ + { + type: ComponentType.Button, + customId: "solved", + style: ButtonStyle.Secondary, + label: "Solved", + emoji: "✅", + }, + ], + }, + ], }); } catch (error_) { const error = error_ as Error; diff --git a/src/util/constants.ts b/src/util/constants.ts index fb52eef..36a1f45 100644 --- a/src/util/constants.ts +++ b/src/util/constants.ts @@ -22,5 +22,7 @@ export const TAB = "\u200B \u200B \u200B" as const; export const EMOJI_NEWBIE = "<:newbie:962332319623049226>" as const; export const ASSISTCHANNELS = ["986520997006032896", "998942774994927646"]; +export const CUSTOM_ID_SEPARATOR = ":" as const; + export const URL_REGEX = /(?https?:\/\/(?:www\.|(?!www))[\dA-Za-z][\dA-Za-z-]+[\dA-Za-z]\.\S{2,}|www\.[\dA-Za-z][\dA-Za-z-]+[\dA-Za-z]\.\S{2,}|https?:\/\/(?:www\.|(?!www))[\dA-Za-z]+\.\S{2,}|www\.[\dA-Za-z]+\.\S{2,})/g;