feat: refactor modal creation to use plain objects for improved readability and structure

This commit is contained in:
2025-10-03 22:38:25 -05:00
parent 150128174f
commit ce87dc2b0d

View File

@@ -1,13 +1,11 @@
import { import {
ActionRowBuilder,
ButtonInteraction, ButtonInteraction,
Message, Message,
MessageComponentInteraction, MessageComponentInteraction,
MessageFlags, MessageFlags,
ModalBuilder, TextChannel, TextChannel,
TextInputBuilder,
TextInputStyle,
} from "discord.js"; } from "discord.js";
import { ComponentType, TextInputStyle } from "discord-api-types/v10";
import logger from "../../../core/lib/logger"; import logger from "../../../core/lib/logger";
import {CommandMessage} from "../../../core/types/commands"; import {CommandMessage} from "../../../core/types/commands";
import {listVariables} from "../../../core/lib/vars"; import {listVariables} from "../../../core/lib/vars";
@@ -128,7 +126,10 @@ async function handleEditorInteractions(
filter: (interaction: MessageComponentInteraction) => interaction.user.id === originalMessage.author.id filter: (interaction: MessageComponentInteraction) => interaction.user.id === originalMessage.author.id
}); });
collector.on("collect", async (interaction: ButtonInteraction) => { collector.on("collect", async (interaction: MessageComponentInteraction) => {
// Verificar que sea una interacción de botón
if (!interaction.isButton()) return;
try { try {
await handleButtonInteraction( await handleButtonInteraction(
interaction, interaction,
@@ -227,27 +228,31 @@ async function handleEditTitle(
originalMessage: Message, originalMessage: Message,
blockState: BlockState blockState: BlockState
): Promise<void> { ): Promise<void> {
const modal = new ModalBuilder() const modal = {
.setCustomId("edit_title_modal") title: "Editar Título del Bloque",
.setTitle("Editar Título del Bloque"); customId: "edit_title_modal",
components: [
const titleInput = new TextInputBuilder() {
.setCustomId("title_input") type: ComponentType.Label,
.setLabel("Título") label: "Título",
.setStyle(TextInputStyle.Short) component: {
.setPlaceholder("Escribe el título del bloque...") type: ComponentType.TextInput,
.setValue(blockState.title || "") customId: "title_input",
.setRequired(true) style: TextInputStyle.Short,
.setMaxLength(256); required: true,
placeholder: "Escribe el título del bloque...",
const actionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(titleInput); value: blockState.title || "",
modal.addComponents(actionRow); maxLength: 256
}
}
]
} as const;
await interaction.showModal(modal); await interaction.showModal(modal);
try { try {
const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 }); const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 });
const newTitle = modalInteraction.fields.getTextInputValue("title_input").trim(); const newTitle = modalInteraction.components.getTextInputValue("title_input").trim();
if (newTitle) { if (newTitle) {
blockState.title = newTitle; blockState.title = newTitle;
@@ -263,7 +268,6 @@ async function handleEditTitle(
}); });
} catch { } catch {
// Modal timed out or error occurred // Modal timed out or error occurred
// no-op
} }
} }
@@ -273,27 +277,31 @@ async function handleEditDescription(
originalMessage: Message, originalMessage: Message,
blockState: BlockState blockState: BlockState
): Promise<void> { ): Promise<void> {
const modal = new ModalBuilder() const modal = {
.setCustomId("edit_description_modal") title: "Editar Descripción del Bloque",
.setTitle("Editar Descripción del Bloque"); customId: "edit_description_modal",
components: [
const descriptionInput = new TextInputBuilder() {
.setCustomId("description_input") type: ComponentType.Label,
.setLabel("Descripción") label: "Descripción",
.setStyle(TextInputStyle.Paragraph) component: {
.setPlaceholder("Escribe la descripción del bloque...") type: ComponentType.TextInput,
.setValue(blockState.description || "") customId: "description_input",
.setRequired(false) style: TextInputStyle.Paragraph,
.setMaxLength(4000); required: false,
placeholder: "Escribe la descripción del bloque...",
const actionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(descriptionInput); value: blockState.description || "",
modal.addComponents(actionRow); maxLength: 4000
}
}
]
} as const;
await interaction.showModal(modal); await interaction.showModal(modal);
try { try {
const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 }); const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 });
const newDescription = modalInteraction.fields.getTextInputValue("description_input").trim(); const newDescription = modalInteraction.components.getTextInputValue("description_input").trim();
blockState.description = newDescription || undefined; blockState.description = newDescription || undefined;
await updateEditor(editorMessage, { await updateEditor(editorMessage, {
@@ -316,27 +324,31 @@ async function handleEditColor(
originalMessage: Message, originalMessage: Message,
blockState: BlockState blockState: BlockState
): Promise<void> { ): Promise<void> {
const modal = new ModalBuilder() const modal = {
.setCustomId("edit_color_modal") title: "Editar Color del Bloque",
.setTitle("Editar Color del Bloque"); customId: "edit_color_modal",
components: [
const colorInput = new TextInputBuilder() {
.setCustomId("color_input") type: ComponentType.Label,
.setLabel("Color (formato HEX)") label: "Color (formato HEX)",
.setStyle(TextInputStyle.Short) component: {
.setPlaceholder("#FF5733 o FF5733") type: ComponentType.TextInput,
.setValue(blockState.color ? `#${blockState.color.toString(16).padStart(6, '0')}` : "") customId: "color_input",
.setRequired(false) style: TextInputStyle.Short,
.setMaxLength(7); required: false,
placeholder: "#FF5733 o FF5733",
const actionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(colorInput); value: blockState.color ? `#${blockState.color.toString(16).padStart(6, '0')}` : "",
modal.addComponents(actionRow); maxLength: 7
}
}
]
} as const;
await interaction.showModal(modal); await interaction.showModal(modal);
try { try {
const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 }); const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 });
const colorValue = modalInteraction.fields.getTextInputValue("color_input").trim(); const colorValue = modalInteraction.components.getTextInputValue("color_input").trim();
if (colorValue) { if (colorValue) {
const cleanColor = colorValue.replace('#', ''); const cleanColor = colorValue.replace('#', '');
@@ -382,26 +394,30 @@ async function handleAddContent(
originalMessage: Message, originalMessage: Message,
blockState: BlockState blockState: BlockState
): Promise<void> { ): Promise<void> {
const modal = new ModalBuilder() const modal = {
.setCustomId("add_content_modal") title: "Añadir Contenido de Texto",
.setTitle("Añadir Contenido de Texto"); customId: "add_content_modal",
components: [
const contentInput = new TextInputBuilder() {
.setCustomId("content_input") type: ComponentType.Label,
.setLabel("Contenido") label: "Contenido",
.setStyle(TextInputStyle.Paragraph) component: {
.setPlaceholder("Escribe el contenido de texto...") type: ComponentType.TextInput,
.setRequired(true) customId: "content_input",
.setMaxLength(4000); style: TextInputStyle.Paragraph,
required: true,
const actionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(contentInput); placeholder: "Escribe el contenido de texto...",
modal.addComponents(actionRow); maxLength: 4000
}
}
]
} as const;
await interaction.showModal(modal); await interaction.showModal(modal);
try { try {
const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 }); const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 });
const content = modalInteraction.fields.getTextInputValue("content_input").trim(); const content = modalInteraction.components.getTextInputValue("content_input").trim();
if (content) { if (content) {
blockState.components.push({ blockState.components.push({
@@ -454,26 +470,30 @@ async function handleAddImage(
originalMessage: Message, originalMessage: Message,
blockState: BlockState blockState: BlockState
): Promise<void> { ): Promise<void> {
const modal = new ModalBuilder() const modal = {
.setCustomId("add_image_modal") title: "Añadir Imagen",
.setTitle("Añadir Imagen"); customId: "add_image_modal",
components: [
const imageInput = new TextInputBuilder() {
.setCustomId("image_input") type: ComponentType.Label,
.setLabel("URL de la Imagen") label: "URL de la Imagen",
.setStyle(TextInputStyle.Short) component: {
.setPlaceholder("https://ejemplo.com/imagen.png") type: ComponentType.TextInput,
.setRequired(true) customId: "image_input",
.setMaxLength(512); style: TextInputStyle.Short,
required: true,
const actionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(imageInput); placeholder: "https://ejemplo.com/imagen.png",
modal.addComponents(actionRow); maxLength: 512
}
}
]
} as const;
await interaction.showModal(modal); await interaction.showModal(modal);
try { try {
const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 }); const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 });
const imageUrl = modalInteraction.fields.getTextInputValue("image_input").trim(); const imageUrl = modalInteraction.components.getTextInputValue("image_input").trim();
if (imageUrl && DisplayComponentUtils.isValidUrl(imageUrl)) { if (imageUrl && DisplayComponentUtils.isValidUrl(imageUrl)) {
blockState.components.push({ blockState.components.push({
@@ -488,12 +508,12 @@ async function handleAddImage(
await modalInteraction.reply({ await modalInteraction.reply({
content: "✅ Imagen añadida correctamente.", content: "✅ Imagen añadida correctamente.",
ephemeral: true flags: MessageFlags.Ephemeral
}); });
} else { } else {
await modalInteraction.reply({ await modalInteraction.reply({
content: "❌ URL de imagen inválida.", content: "❌ URL de imagen inválida.",
ephemeral: true flags: MessageFlags.Ephemeral
}); });
} }
} catch { } catch {
@@ -507,27 +527,31 @@ async function handleCoverImage(
originalMessage: Message, originalMessage: Message,
blockState: BlockState blockState: BlockState
): Promise<void> { ): Promise<void> {
const modal = new ModalBuilder() const modal = {
.setCustomId("cover_image_modal") title: "Imagen de Portada",
.setTitle("Imagen de Portada"); customId: "cover_image_modal",
components: [
const coverInput = new TextInputBuilder() {
.setCustomId("cover_input") type: ComponentType.Label,
.setLabel("URL de la Imagen de Portada") label: "URL de la Imagen de Portada",
.setStyle(TextInputStyle.Short) component: {
.setPlaceholder("https://ejemplo.com/portada.png") type: ComponentType.TextInput,
.setValue(blockState.coverImage || "") customId: "cover_input",
.setRequired(false) style: TextInputStyle.Short,
.setMaxLength(512); required: false,
placeholder: "https://ejemplo.com/portada.png",
const actionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(coverInput); value: blockState.coverImage || "",
modal.addComponents(actionRow); maxLength: 512
}
}
]
} as const;
await interaction.showModal(modal); await interaction.showModal(modal);
try { try {
const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 }); const modalInteraction = await interaction.awaitModalSubmit({ time: 300000 });
const coverUrl = modalInteraction.fields.getTextInputValue("cover_input").trim(); const coverUrl = modalInteraction.components.getTextInputValue("cover_input").trim();
if (coverUrl && DisplayComponentUtils.isValidUrl(coverUrl)) { if (coverUrl && DisplayComponentUtils.isValidUrl(coverUrl)) {
blockState.coverImage = coverUrl; blockState.coverImage = coverUrl;
@@ -542,7 +566,7 @@ async function handleCoverImage(
await modalInteraction.reply({ await modalInteraction.reply({
content: coverUrl ? "✅ Imagen de portada actualizada." : "✅ Imagen de portada removida.", content: coverUrl ? "✅ Imagen de portada actualizada." : "✅ Imagen de portada removida.",
ephemeral: true flags: MessageFlags.Ephemeral
}); });
} catch { } catch {
// ignore // ignore