feat: add block movement and deletion functionality in interactive editor

This commit is contained in:
2025-10-04 00:15:43 -05:00
parent 68cab85eff
commit 0fedf1549a
2 changed files with 727 additions and 2 deletions

View File

@@ -5,7 +5,7 @@ import {
MessageFlags,
TextChannel,
} from "discord.js";
import { ComponentType, TextInputStyle } from "discord-api-types/v10";
import { ComponentType, TextInputStyle, ButtonStyle } from "discord-api-types/v10";
import logger from "../../../core/lib/logger";
import {CommandMessage} from "../../../core/types/commands";
import {listVariables} from "../../../core/lib/vars";
@@ -202,6 +202,113 @@ async function handleButtonInteraction(
await handleCoverImage(interaction, editorMessage, originalMessage, blockState);
break;
case "move_block": {
const options = blockState.components.map((c: any, idx: number) => ({
label: c.type === 10 ? `Texto: ${c.content?.slice(0, 30) || '...'}` : c.type === 14 ? 'Separador' : c.type === 12 ? `Imagen: ${c.url?.slice(-30) || '...'}` : `Componente ${c.type}`,
value: String(idx),
description: c.type === 10 && (c.thumbnail || c.linkButton) ? (c.thumbnail ? 'Con thumbnail' : 'Con botón link') : undefined,
}));
await interaction.reply({
flags: MessageFlags.Ephemeral,
content: 'Selecciona el bloque que quieres mover:',
components: [
{ type: 1, components: [ { type: 3, custom_id: 'move_block_select', placeholder: 'Elige un bloque', options } ] },
],
});
const replyMsg = await interaction.fetchReply();
// @ts-ignore
const selCollector = replyMsg.createMessageComponentCollector({ componentType: ComponentType.StringSelect, max: 1, time: 60000, filter: (it: any) => it.user.id === originalMessage.author.id });
selCollector.on('collect', async (sel: any) => {
const idx = parseInt(sel.values[0]);
await sel.update({
content: '¿Quieres mover este bloque?',
components: [
{ type: 1, components: [
{ type: 2, style: ButtonStyle.Secondary, label: '⬆️ Subir', custom_id: `move_up_${idx}`, disabled: idx === 0 },
{ type: 2, style: ButtonStyle.Secondary, label: '⬇️ Bajar', custom_id: `move_down_${idx}`, disabled: idx === blockState.components.length - 1 },
]},
],
});
// @ts-ignore
const btnCollector = replyMsg.createMessageComponentCollector({ componentType: ComponentType.Button, max: 1, time: 60000, filter: (b: any) => b.user.id === originalMessage.author.id });
btnCollector.on('collect', async (b: any) => {
if (b.customId.startsWith('move_up_')) {
const i2 = parseInt(b.customId.replace('move_up_', ''));
if (i2 > 0) {
const item = blockState.components[i2];
blockState.components.splice(i2, 1);
blockState.components.splice(i2 - 1, 0, item);
}
await b.update({ content: '✅ Bloque movido arriba.', components: [] });
} else if (b.customId.startsWith('move_down_')) {
const i2 = parseInt(b.customId.replace('move_down_', ''));
if (i2 < blockState.components.length - 1) {
const item = blockState.components[i2];
blockState.components.splice(i2, 1);
blockState.components.splice(i2 + 1, 0, item);
}
await b.update({ content: '✅ Bloque movido abajo.', components: [] });
}
await updateEditor(editorMessage, {
display: await DisplayComponentUtils.renderPreview(blockState, originalMessage.member!, originalMessage.guild!),
components: DisplayComponentUtils.createEditorButtons(false),
});
btnCollector.stop();
selCollector.stop();
});
});
break;
}
case "delete_block": {
const options: any[] = [];
if (blockState.coverImage) options.push({ label: '🖼️ Imagen de Portada', value: 'cover_image', description: 'Imagen principal del bloque' });
blockState.components.forEach((c: any, idx: number) => options.push({
label: c.type === 10 ? `Texto: ${c.content?.slice(0, 30) || '...'}` : c.type === 14 ? `Separador ${c.divider ? '(Visible)' : '(Invisible)'}` : c.type === 12 ? `Imagen: ${c.url?.slice(-30) || '...'}` : `Componente ${c.type}`,
value: String(idx),
description: c.type === 10 && (c.thumbnail || c.linkButton) ? (c.thumbnail ? 'Con thumbnail' : 'Con botón link') : undefined,
}));
if (options.length === 0) {
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
// @ts-ignore
await interaction.editReply({ content: '❌ No hay elementos para eliminar.' });
break;
}
await interaction.reply({
flags: MessageFlags.Ephemeral,
content: 'Selecciona el elemento que quieres eliminar:',
components: [
{ type: 1, components: [ { type: 3, custom_id: 'delete_block_select', placeholder: 'Elige un elemento', options } ] },
],
});
const replyMsg = await interaction.fetchReply();
// @ts-ignore
const selCollector = replyMsg.createMessageComponentCollector({ componentType: ComponentType.StringSelect, max: 1, time: 60000, filter: (it: any) => it.user.id === originalMessage.author.id });
selCollector.on('collect', async (sel: any) => {
const selectedValue = sel.values[0];
if (selectedValue === 'cover_image') {
// @ts-ignore
blockState.coverImage = null;
await sel.update({ content: '✅ Imagen de portada eliminada.', components: [] });
} else {
const idx = parseInt(selectedValue);
blockState.components.splice(idx, 1);
await sel.update({ content: '✅ Elemento eliminado.', components: [] });
}
await updateEditor(editorMessage, {
display: await DisplayComponentUtils.renderPreview(blockState, originalMessage.member!, originalMessage.guild!),
components: DisplayComponentUtils.createEditorButtons(false),
});
selCollector.stop();
});
break;
}
case "show_variables":
await handleShowVariables(interaction);
break;
@@ -221,7 +328,7 @@ async function handleButtonInteraction(
default:
await interaction.reply({
content: `⚠️ Funcionalidad \`${customId}\` en desarrollo.`,
flags: MessageFlags.Ephemeral
flags: MessageFlags.Ephemeral,
});
break;
}