From 66842510dcb64118722f685a9fbe0e4082a9a21a Mon Sep 17 00:00:00 2001 From: Julian Vennen Date: Mon, 3 Jun 2024 20:49:19 +0200 Subject: [PATCH] Create reusable classes for modal fields --- src/commands/user/BanCommand.js | 49 +++++------------ src/commands/user/KickCommand.js | 25 ++------- src/commands/user/MuteCommand.js | 34 +++--------- src/commands/user/PardonCommand.js | 36 +++--------- src/commands/user/SoftBanCommand.js | 40 ++++---------- src/commands/user/StrikeCommand.js | 40 ++++---------- src/commands/user/StrikePurgeCommand.js | 55 +++++++------------ src/commands/user/UnbanCommand.js | 23 ++------ src/commands/user/UnmuteCommand.js | 23 ++------ src/commands/user/UserCommand.js | 14 ++++- src/modals/inputs/CommentInput.js | 13 +++++ src/modals/inputs/CountInput.js | 13 +++++ .../inputs/DeleteMessageHistoryInput.js | 13 +++++ src/modals/inputs/DurationInput.js | 12 ++++ src/modals/inputs/ReasonInput.js | 13 +++++ src/modals/inputs/TextInput.js | 12 ++++ src/modals/rows/SimpleActionRow.js | 11 ++++ 17 files changed, 186 insertions(+), 240 deletions(-) create mode 100644 src/modals/inputs/CommentInput.js create mode 100644 src/modals/inputs/CountInput.js create mode 100644 src/modals/inputs/DeleteMessageHistoryInput.js create mode 100644 src/modals/inputs/DurationInput.js create mode 100644 src/modals/inputs/ReasonInput.js create mode 100644 src/modals/inputs/TextInput.js create mode 100644 src/modals/rows/SimpleActionRow.js diff --git a/src/commands/user/BanCommand.js b/src/commands/user/BanCommand.js index 9b676853e..e59dfa349 100644 --- a/src/commands/user/BanCommand.js +++ b/src/commands/user/BanCommand.js @@ -1,10 +1,7 @@ import { - ActionRowBuilder, ModalBuilder, PermissionFlagsBits, PermissionsBitField, - TextInputBuilder, - TextInputStyle } from 'discord.js'; import MemberWrapper from '../../discord/MemberWrapper.js'; import {parseTime} from '../../util/timeutils.js'; @@ -15,6 +12,15 @@ import Confirmation from '../../database/Confirmation.js'; import UserActionEmbed from '../../embeds/UserActionEmbed.js'; import config from '../../bot/Config.js'; import {deferReplyOnce, replyOrEdit} from '../../util/interaction.js'; +import ReasonInput from '../../modals/inputs/ReasonInput.js'; +import CommentInput from '../../modals/inputs/CommentInput.js'; +import DeleteMessageHistoryInput from '../../modals/inputs/DeleteMessageHistoryInput.js'; +import DurationInput from '../../modals/inputs/DurationInput.js'; + +/** + * @typedef {DurationConfirmationData} BanConfirmationData + * @property {?number} deleteMessageTime + */ export default class BanCommand extends UserCommand { @@ -92,7 +98,7 @@ export default class BanCommand extends UserCommand { async executeButton(interaction) { const parts = interaction.customId.split(':'); if (parts[1] === 'confirm') { - /** @type {Confirmation<{reason: ?string, comment: ?string, duration: ?number, deleteMessageTime: ?number, user: import('discord.js').Snowflake}>}*/ + /** @type {Confirmation}*/ const data = await Confirmation.get(parts[2]); if (!data) { await interaction.update({content: 'This confirmation has expired.', embeds: [], components: []}); @@ -132,37 +138,10 @@ export default class BanCommand extends UserCommand { .setTitle(`Ban ${await member.displayName()}`.substring(0, MODAL_TITLE_LIMIT)) .setCustomId(`ban:${member.user.id}`) .addComponents( - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Reason') - .setCustomId('reason') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No reason provided')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Comment') - .setCustomId('comment') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No internal comment')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Duration') - .setCustomId('duration') - .setStyle(TextInputStyle.Short)), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Delete message history') - .setCustomId('delete') - .setStyle(TextInputStyle.Short) - .setValue('1 hour')), + new ReasonInput().toActionRow(), + new CommentInput().toActionRow(), + new DurationInput().toActionRow(), + new DeleteMessageHistoryInput().toActionRow(), )); } diff --git a/src/commands/user/KickCommand.js b/src/commands/user/KickCommand.js index af0459720..9435c2b1f 100644 --- a/src/commands/user/KickCommand.js +++ b/src/commands/user/KickCommand.js @@ -1,10 +1,7 @@ import { - ActionRowBuilder, ModalBuilder, PermissionFlagsBits, PermissionsBitField, - TextInputBuilder, - TextInputStyle } from 'discord.js'; import MemberWrapper from '../../discord/MemberWrapper.js'; import colors from '../../util/colors.js'; @@ -14,6 +11,8 @@ import Confirmation from '../../database/Confirmation.js'; import UserActionEmbed from '../../embeds/UserActionEmbed.js'; import config from '../../bot/Config.js'; import {deferReplyOnce, replyOrEdit} from '../../util/interaction.js'; +import ReasonInput from '../../modals/inputs/ReasonInput.js'; +import CommentInput from '../../modals/inputs/CommentInput.js'; export default class KickCommand extends UserCommand { @@ -65,7 +64,7 @@ export default class KickCommand extends UserCommand { async executeButton(interaction) { const parts = interaction.customId.split(':'); if (parts[1] === 'confirm') { - /** @type {Confirmation<{reason: ?string, comment: ?string, user: import('discord.js').Snowflake}>}*/ + /** @type {Confirmation}*/ const data = await Confirmation.get(parts[2]); if (!data) { await interaction.update({content: 'This confirmation has expired.', embeds: [], components: []}); @@ -103,22 +102,8 @@ export default class KickCommand extends UserCommand { .setTitle(`Kick ${await member.displayName()}`.substring(0, MODAL_TITLE_LIMIT)) .setCustomId(`kick:${member.user.id}`) .addComponents( - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Reason') - .setCustomId('reason') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No reason provided')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Comment') - .setCustomId('comment') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No internal comment')), + new ReasonInput().toActionRow(), + new CommentInput().toActionRow(), )); } diff --git a/src/commands/user/MuteCommand.js b/src/commands/user/MuteCommand.js index 0d0bb9b15..dc1530283 100644 --- a/src/commands/user/MuteCommand.js +++ b/src/commands/user/MuteCommand.js @@ -1,10 +1,7 @@ import { - ActionRowBuilder, ModalBuilder, PermissionFlagsBits, PermissionsBitField, - TextInputBuilder, - TextInputStyle } from 'discord.js'; import MemberWrapper from '../../discord/MemberWrapper.js'; import {formatTime, parseTime} from '../../util/timeutils.js'; @@ -16,6 +13,9 @@ import ErrorEmbed from '../../embeds/ErrorEmbed.js'; import UserActionEmbed from '../../embeds/UserActionEmbed.js'; import config from '../../bot/Config.js'; import {deferReplyOnce, replyOrEdit} from '../../util/interaction.js'; +import ReasonInput from '../../modals/inputs/ReasonInput.js'; +import CommentInput from '../../modals/inputs/CommentInput.js'; +import DurationInput from '../../modals/inputs/DurationInput.js'; export default class MuteCommand extends UserCommand { @@ -97,7 +97,7 @@ export default class MuteCommand extends UserCommand { async executeButton(interaction) { const parts = interaction.customId.split(':'); if (parts[1] === 'confirm') { - /** @type {Confirmation<{reason: ?string, comment: ?string, duration: ?number, user: import('discord.js').Snowflake}>}*/ + /** @type {Confirmation}*/ const data = await Confirmation.get(parts[2]); if (!data) { await interaction.update({content: 'This confirmation has expired.', embeds: [], components: []}); @@ -137,29 +137,9 @@ export default class MuteCommand extends UserCommand { .setTitle(`Mute ${await member.displayName()}`.substring(0, MODAL_TITLE_LIMIT)) .setCustomId(`mute:${member.user.id}`) .addComponents( - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Reason') - .setCustomId('reason') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No reason provided')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Comment') - .setCustomId('comment') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No internal comment')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Duration') - .setCustomId('duration') - .setStyle(TextInputStyle.Short)), + new ReasonInput().toActionRow(), + new CommentInput().toActionRow(), + new DurationInput().toActionRow(), )); } diff --git a/src/commands/user/PardonCommand.js b/src/commands/user/PardonCommand.js index 7642b68d5..2dbc3aecd 100644 --- a/src/commands/user/PardonCommand.js +++ b/src/commands/user/PardonCommand.js @@ -1,10 +1,8 @@ import { - ActionRowBuilder, bold, escapeMarkdown, + bold, escapeMarkdown, ModalBuilder, PermissionFlagsBits, - PermissionsBitField, - TextInputBuilder, - TextInputStyle + PermissionsBitField } from 'discord.js'; import MemberWrapper from '../../discord/MemberWrapper.js'; import colors from '../../util/colors.js'; @@ -14,6 +12,9 @@ import EmbedWrapper from '../../embeds/EmbedWrapper.js'; import {formatNumber, inlineEmojiIfExists} from '../../util/format.js'; import {deferReplyOnce, replyOrEdit} from '../../util/interaction.js'; import UserCommand from './UserCommand.js'; +import ReasonInput from '../../modals/inputs/ReasonInput.js'; +import CommentInput from '../../modals/inputs/CommentInput.js'; +import CountInput from '../../modals/inputs/CountInput.js'; export default class PardonCommand extends UserCommand { @@ -99,30 +100,9 @@ export default class PardonCommand extends UserCommand { .setTitle(`Pardon ${await member.displayName()}`.substring(0, MODAL_TITLE_LIMIT)) .setCustomId(`pardon:${member.user.id}`) .addComponents( - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Reason') - .setCustomId('reason') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No reason provided')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Comment') - .setCustomId('comment') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No internal comment')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Count') - .setCustomId('count') - .setStyle(TextInputStyle.Short) - .setPlaceholder('1')), + new ReasonInput().toActionRow(), + new CommentInput().toActionRow(), + new CountInput().toActionRow(), )); } diff --git a/src/commands/user/SoftBanCommand.js b/src/commands/user/SoftBanCommand.js index 7256f30de..595b68216 100644 --- a/src/commands/user/SoftBanCommand.js +++ b/src/commands/user/SoftBanCommand.js @@ -1,10 +1,7 @@ import { - ActionRowBuilder, ModalBuilder, PermissionFlagsBits, PermissionsBitField, - TextInputBuilder, - TextInputStyle } from 'discord.js'; import MemberWrapper from '../../discord/MemberWrapper.js'; import {parseTime} from '../../util/timeutils.js'; @@ -15,6 +12,14 @@ import Confirmation from '../../database/Confirmation.js'; import UserActionEmbed from '../../embeds/UserActionEmbed.js'; import config from '../../bot/Config.js'; import {deferReplyOnce, replyOrEdit} from '../../util/interaction.js'; +import ReasonInput from '../../modals/inputs/ReasonInput.js'; +import CommentInput from '../../modals/inputs/CommentInput.js'; +import DeleteMessageHistoryInput from '../../modals/inputs/DeleteMessageHistoryInput.js'; + +/** + * @typedef {ConfirmationData} SoftBanConfirmationData + * @property {?number} deleteMessageTime + */ export default class SoftBanCommand extends UserCommand { @@ -74,7 +79,7 @@ export default class SoftBanCommand extends UserCommand { async executeButton(interaction) { const parts = interaction.customId.split(':'); if (parts[1] === 'confirm') { - /** @type {Confirmation<{reason: ?string, comment: ?string, user: import('discord.js').Snowflake, deleteMessageTime: ?number}>}*/ + /** @type {Confirmation}*/ const data = await Confirmation.get(parts[2]); if (!data) { await interaction.update({content: 'This confirmation has expired.', embeds: [], components: []}); @@ -109,30 +114,9 @@ export default class SoftBanCommand extends UserCommand { .setTitle(`Soft-ban ${await member.displayName()}`.substring(0, MODAL_TITLE_LIMIT)) .setCustomId(`soft-ban:${member.user.id}`) .addComponents( - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Reason') - .setCustomId('reason') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No reason provided')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Comment') - .setCustomId('comment') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No internal comment')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Delete message history') - .setCustomId('delete') - .setStyle(TextInputStyle.Short) - .setValue('1 hour')), + new ReasonInput().toActionRow(), + new CommentInput().toActionRow(), + new DeleteMessageHistoryInput().toActionRow(), )); } diff --git a/src/commands/user/StrikeCommand.js b/src/commands/user/StrikeCommand.js index 0e0457570..a3f862dc6 100644 --- a/src/commands/user/StrikeCommand.js +++ b/src/commands/user/StrikeCommand.js @@ -1,12 +1,9 @@ import { - ActionRowBuilder, bold, escapeMarkdown, ModalBuilder, PermissionFlagsBits, PermissionsBitField, - TextInputBuilder, - TextInputStyle } from 'discord.js'; import MemberWrapper from '../../discord/MemberWrapper.js'; import colors from '../../util/colors.js'; @@ -17,6 +14,14 @@ import {inLimits} from '../../util/util.js'; import EmbedWrapper from '../../embeds/EmbedWrapper.js'; import {formatNumber, inlineEmojiIfExists} from '../../util/format.js'; import {deferReplyOnce, replyOrEdit} from '../../util/interaction.js'; +import ReasonInput from '../../modals/inputs/ReasonInput.js'; +import CommentInput from '../../modals/inputs/CommentInput.js'; +import CountInput from '../../modals/inputs/CountInput.js'; + +/** + * @typedef {ConfirmationData} StrikeConfirmationData + * @property {?number} count + */ export default class StrikeCommand extends UserCommand { @@ -91,7 +96,7 @@ export default class StrikeCommand extends UserCommand { async executeButton(interaction) { const parts = interaction.customId.split(':'); if (parts[1] === 'confirm') { - /** @type {Confirmation<{reason: ?string, comment: ?string, count: number, user: import('discord.js').Snowflake}>}*/ + /** @type {Confirmation}*/ const data = await Confirmation.get(parts[2]); if (!data) { await interaction.update({content: 'This confirmation has expired.', embeds: [], components: []}); @@ -131,30 +136,9 @@ export default class StrikeCommand extends UserCommand { .setTitle(`Strike ${await member.displayName()}`.substring(0, MODAL_TITLE_LIMIT)) .setCustomId(`strike:${member.user.id}`) .addComponents( - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Reason') - .setCustomId('reason') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No reason provided')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Comment') - .setCustomId('comment') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No internal comment')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Count') - .setCustomId('count') - .setStyle(TextInputStyle.Short) - .setPlaceholder('1')), + new ReasonInput().toActionRow(), + new CommentInput().toActionRow(), + new CountInput().toActionRow(), )); } diff --git a/src/commands/user/StrikePurgeCommand.js b/src/commands/user/StrikePurgeCommand.js index cca8e4dbf..73a0611e2 100644 --- a/src/commands/user/StrikePurgeCommand.js +++ b/src/commands/user/StrikePurgeCommand.js @@ -1,9 +1,8 @@ import StrikeCommand from './StrikeCommand.js'; import { - ActionRowBuilder, ModalBuilder, PermissionFlagsBits, - TextInputBuilder, TextInputStyle + TextInputStyle } from 'discord.js'; import MemberWrapper from '../../discord/MemberWrapper.js'; import Confirmation from '../../database/Confirmation.js'; @@ -12,6 +11,15 @@ import ChannelWrapper from '../../discord/ChannelWrapper.js'; import GuildWrapper from '../../discord/GuildWrapper.js'; import PurgeLogEmbed from '../../embeds/PurgeLogEmbed.js'; import {deferReplyOnce} from '../../util/interaction.js'; +import ReasonInput from '../../modals/inputs/ReasonInput.js'; +import CommentInput from '../../modals/inputs/CommentInput.js'; +import CountInput from '../../modals/inputs/CountInput.js'; +import TextInput from '../../modals/inputs/TextInput.js'; + +/** + * @typedef {StrikeConfirmationData} StrikePurgeConfirmationData + * @property {number} limit + */ export default class StrikePurgeCommand extends StrikeCommand { buildOptions(builder) { @@ -99,7 +107,7 @@ export default class StrikePurgeCommand extends StrikeCommand { async executeButton(interaction) { const parts = interaction.customId.split(':'); if (parts[1] === 'confirm') { - /** @type {Confirmation<{reason: ?string, comment: ?string, count: number, user: import('discord.js').Snowflake, limit: number}>}*/ + /** @type {Confirmation}*/ const data = await Confirmation.get(parts[2]); if (!data) { await interaction.update({content: 'This confirmation has expired.', embeds: [], components: []}); @@ -135,38 +143,15 @@ export default class StrikePurgeCommand extends StrikeCommand { .setTitle(`Strike-purge ${await member.displayName()}`.substring(0, MODAL_TITLE_LIMIT)) .setCustomId(`strike-purge:${member.user.id}`) .addComponents( - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Reason') - .setCustomId('reason') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No reason provided')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Comment') - .setCustomId('comment') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No internal comment')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Count') - .setCustomId('count') - .setStyle(TextInputStyle.Short) - .setPlaceholder('1')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Message deletion limit') - .setCustomId('limit') - .setStyle(TextInputStyle.Short) - .setPlaceholder('100')), + new ReasonInput().toActionRow(), + new CommentInput().toActionRow(), + new CountInput().toActionRow(), + new TextInput().setRequired(false) + .setLabel('Message deletion limit') + .setCustomId('limit') + .setStyle(TextInputStyle.Short) + .setPlaceholder('100') + .toActionRow(), )); } diff --git a/src/commands/user/UnbanCommand.js b/src/commands/user/UnbanCommand.js index 6bfc44044..445c2f22e 100644 --- a/src/commands/user/UnbanCommand.js +++ b/src/commands/user/UnbanCommand.js @@ -1,10 +1,7 @@ import { - ActionRowBuilder, ModalBuilder, PermissionFlagsBits, PermissionsBitField, - TextInputBuilder, - TextInputStyle } from 'discord.js'; import MemberWrapper from '../../discord/MemberWrapper.js'; import colors from '../../util/colors.js'; @@ -14,6 +11,8 @@ import UserActionEmbed from '../../embeds/UserActionEmbed.js'; import config from '../../bot/Config.js'; import {deferReplyOnce, replyOrEdit} from '../../util/interaction.js'; import UserCommand from './UserCommand.js'; +import ReasonInput from '../../modals/inputs/ReasonInput.js'; +import CommentInput from '../../modals/inputs/CommentInput.js'; export default class UnbanCommand extends UserCommand { getDefaultMemberPermissions() { @@ -79,22 +78,8 @@ export default class UnbanCommand extends UserCommand { .setTitle(`Unban ${await member.displayName()}`.substring(0, MODAL_TITLE_LIMIT)) .setCustomId(`unban:${member.user.id}`) .addComponents( - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Reason') - .setCustomId('reason') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No reason provided')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Comment') - .setCustomId('comment') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No internal comment')), + new ReasonInput().toActionRow(), + new CommentInput().toActionRow(), )); } diff --git a/src/commands/user/UnmuteCommand.js b/src/commands/user/UnmuteCommand.js index 792ad9d5e..677ef4ef2 100644 --- a/src/commands/user/UnmuteCommand.js +++ b/src/commands/user/UnmuteCommand.js @@ -1,10 +1,7 @@ import { - ActionRowBuilder, ModalBuilder, PermissionFlagsBits, PermissionsBitField, - TextInputBuilder, - TextInputStyle } from 'discord.js'; import MemberWrapper from '../../discord/MemberWrapper.js'; import colors from '../../util/colors.js'; @@ -14,6 +11,8 @@ import UserActionEmbed from '../../embeds/UserActionEmbed.js'; import config from '../../bot/Config.js'; import {deferReplyOnce, replyOrEdit} from '../../util/interaction.js'; import UserCommand from './UserCommand.js'; +import ReasonInput from '../../modals/inputs/ReasonInput.js'; +import CommentInput from '../../modals/inputs/CommentInput.js'; export default class UnmuteCommand extends UserCommand { getDefaultMemberPermissions() { @@ -79,22 +78,8 @@ export default class UnmuteCommand extends UserCommand { .setTitle(`Unmute ${await member.displayName()}`.substring(0, MODAL_TITLE_LIMIT)) .setCustomId(`unmute:${member.user.id}`) .addComponents( - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Reason') - .setCustomId('reason') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No reason provided')), - /** @type {*} */ - new ActionRowBuilder() - .addComponents(/** @type {*} */ new TextInputBuilder() - .setRequired(false) - .setLabel('Comment') - .setCustomId('comment') - .setStyle(TextInputStyle.Paragraph) - .setPlaceholder('No internal comment')), + new ReasonInput().toActionRow(), + new CommentInput().toActionRow(), )); } diff --git a/src/commands/user/UserCommand.js b/src/commands/user/UserCommand.js index 3e6e8309c..962d39953 100644 --- a/src/commands/user/UserCommand.js +++ b/src/commands/user/UserCommand.js @@ -25,6 +25,18 @@ const MODERATION_WARN_DURATION = 5 * 60; */ const CONFIRMATION_DURATION = 15 * 60; +/** + * @typedef {object} ConfirmationData + * @property {?string} reason + * @property {?string} comment + * @property {import('discord.js').Snowflake} [user] + */ + +/** + * @typedef {ConfirmationData} DurationConfirmationData + * @property {number} [duration] + */ + /** * @abstract */ @@ -79,7 +91,7 @@ export default class UserCommand extends Command { /** * @param {import('discord.js').Interaction} interaction * @param {MemberWrapper} member - * @param {Object} data data that will be saved for the confirmation + * @param {ConfirmationData} data data that will be saved for the confirmation * @return {Promise} should the punishment be executed now */ async preventDuplicateModeration(interaction, member, data = {}) { diff --git a/src/modals/inputs/CommentInput.js b/src/modals/inputs/CommentInput.js new file mode 100644 index 000000000..05c3df30c --- /dev/null +++ b/src/modals/inputs/CommentInput.js @@ -0,0 +1,13 @@ +import {TextInputStyle} from 'discord.js'; +import TextInput from './TextInput.js'; + +export default class CommentInput extends TextInput { + constructor() { + super(); + this.setRequired(false) + .setLabel('Comment') + .setCustomId('comment') + .setStyle(TextInputStyle.Paragraph) + .setPlaceholder('No comment provided'); + } +} diff --git a/src/modals/inputs/CountInput.js b/src/modals/inputs/CountInput.js new file mode 100644 index 000000000..2b02cf479 --- /dev/null +++ b/src/modals/inputs/CountInput.js @@ -0,0 +1,13 @@ +import {TextInputStyle} from 'discord.js'; +import TextInput from './TextInput.js'; + +export default class CountInput extends TextInput { + constructor() { + super(); + this.setRequired(false) + .setLabel('Count') + .setCustomId('count') + .setStyle(TextInputStyle.Short) + .setPlaceholder('1'); + } +} diff --git a/src/modals/inputs/DeleteMessageHistoryInput.js b/src/modals/inputs/DeleteMessageHistoryInput.js new file mode 100644 index 000000000..f696ac3d3 --- /dev/null +++ b/src/modals/inputs/DeleteMessageHistoryInput.js @@ -0,0 +1,13 @@ +import TextInput from './TextInput.js'; +import {TextInputStyle} from 'discord.js'; + +export default class DeleteMessageHistoryInput extends TextInput { + constructor() { + super(); + this.setRequired(false) + .setLabel('Delete message history') + .setCustomId('delete') + .setStyle(TextInputStyle.Short) + .setValue('1 hour'); + } +} diff --git a/src/modals/inputs/DurationInput.js b/src/modals/inputs/DurationInput.js new file mode 100644 index 000000000..370a45b93 --- /dev/null +++ b/src/modals/inputs/DurationInput.js @@ -0,0 +1,12 @@ +import {TextInputStyle} from 'discord.js'; +import TextInput from './TextInput.js'; + +export default class DurationInput extends TextInput { + constructor() { + super(); + this.setRequired(false) + .setLabel('Duration') + .setCustomId('duration') + .setStyle(TextInputStyle.Short); + } +} diff --git a/src/modals/inputs/ReasonInput.js b/src/modals/inputs/ReasonInput.js new file mode 100644 index 000000000..46a405aea --- /dev/null +++ b/src/modals/inputs/ReasonInput.js @@ -0,0 +1,13 @@ +import {TextInputStyle} from 'discord.js'; +import TextInput from './TextInput.js'; + +export default class ReasonInput extends TextInput { + constructor() { + super(); + this.setRequired(false) + .setLabel('Reason') + .setCustomId('reason') + .setStyle(TextInputStyle.Paragraph) + .setPlaceholder('No reason provided'); + } +} diff --git a/src/modals/inputs/TextInput.js b/src/modals/inputs/TextInput.js new file mode 100644 index 000000000..b0f6c8449 --- /dev/null +++ b/src/modals/inputs/TextInput.js @@ -0,0 +1,12 @@ +import {TextInputBuilder} from 'discord.js'; +import SimpleActionRow from '../rows/SimpleActionRow.js'; + +export default class TextInput extends TextInputBuilder { + /** + * Create a new action row with this input + * @returns {*} + */ + toActionRow() { + return new SimpleActionRow(this); + } +} diff --git a/src/modals/rows/SimpleActionRow.js b/src/modals/rows/SimpleActionRow.js new file mode 100644 index 000000000..9532388f8 --- /dev/null +++ b/src/modals/rows/SimpleActionRow.js @@ -0,0 +1,11 @@ +import {ActionRowBuilder} from 'discord.js'; + +export default class SimpleActionRow extends ActionRowBuilder { + /** + * @param {*} input + */ + constructor(input) { + super(); + this.addComponents(input); + } +}