Refactor el comando de eliminación de bloques para mejorar la legibilidad y la gestión de interacciones, permitiendo la selección múltiple de bloques y simplificando la lógica de confirmación.

This commit is contained in:
Shni
2025-10-14 11:40:22 -05:00
parent deb08a3413
commit eb957df1e6

View File

@@ -1,11 +1,11 @@
import { import {
Message, Message,
ButtonInteraction, ButtonInteraction,
StringSelectMenuInteraction, StringSelectMenuInteraction,
MessageComponentInteraction, MessageComponentInteraction,
ComponentType, ComponentType,
ButtonStyle, ButtonStyle,
APIEmbed APIEmbed,
} from "discord.js"; } from "discord.js";
import { CommandMessage } from "../../../core/types/commands"; import { CommandMessage } from "../../../core/types/commands";
import type Amayo from "../../../core/client"; import type Amayo from "../../../core/client";
@@ -13,405 +13,502 @@ import type { JsonValue } from "@prisma/client/runtime/library";
import { hasManageGuildOrStaff } from "../../../core/lib/permissions"; import { hasManageGuildOrStaff } from "../../../core/lib/permissions";
interface BlockItem { interface BlockItem {
name: string; name: string;
id: string; id: string;
} }
interface ActionRowBuilder { interface ActionRowBuilder {
type: ComponentType.ActionRow; type: ComponentType.ActionRow;
components: any[]; components: any[];
} }
export const command: CommandMessage = { export const command: CommandMessage = {
name: "eliminar-bloque", name: "eliminar-bloque",
type: "message", type: "message",
aliases: ["bloque-eliminar", "bloque-embed", "blockdelete"], aliases: ["bloque-eliminar", "bloque-embed", "blockdelete"],
cooldown: 10, cooldown: 10,
description: "Elimina bloques DisplayComponents del servidor", description: "Elimina bloques DisplayComponents del servidor",
category: "Creacion", category: "Creacion",
usage: "eliminar-bloque [nombre_bloque]", usage: "eliminar-bloque [nombre_bloque]",
run: async (message: Message, args: string[], client: Amayo): Promise<void> => { run: async (
const allowed = await hasManageGuildOrStaff(message.member, message.guildId!, client.prisma); message: Message,
if (!allowed) { args: string[],
await message.reply("❌ No tienes permisos de ManageGuild ni rol de staff."); client: Amayo
return; ): Promise<void> => {
} const allowed = await hasManageGuildOrStaff(
message.member,
// If specific block name provided, handle direct deletion message.guildId!,
if (args.length > 0) { client.prisma
const blockName = args.join(" ").trim(); );
await handleDirectDeletion(message, client, blockName); if (!allowed) {
return; await message.reply(
} "❌ No tienes permisos de ManageGuild ni rol de staff."
);
// Otherwise, show interactive panel return;
await showDeletionPanel(message, client); }
}, await showDeletionPanel(message, client);
},
}; };
async function handleDirectDeletion( async function showDeletionPanel(
message: Message, message: Message,
client: Amayo, client: Amayo
blockName: string
): Promise<void> { ): Promise<void> {
const block = await client.prisma.blockV2Config.findFirst({ const blocks = await fetchBlocks(client, message.guildId!);
where: {
guildId: message.guildId!,
name: blockName
}
});
if (!block) { if (blocks.length === 0) {
await message.reply(`❌ No se encontró un bloque llamado \`${blockName}\`.`); await handleNoBlocks(message);
return; return;
} }
// Show confirmation for direct deletion const deleteEmbed = createDeletionEmbed(blocks);
const confirmEmbed: APIEmbed = { const actionRow = createBlockSelectRow(blocks);
color: 0xff6b35, const cancelRow = createCancelRow();
title: "⚠️ Confirmar Eliminación",
description: `¿Estás seguro de que quieres eliminar el bloque \`${blockName}\`?\n\n**Esta acción es irreversible.**`,
footer: { text: "Confirma la eliminación usando los botones" }
};
const confirmRow: ActionRowBuilder = { const panelMessage = await message.reply({
type: ComponentType.ActionRow, embeds: [deleteEmbed],
components: [ components: [actionRow, cancelRow],
{ });
type: ComponentType.Button,
style: ButtonStyle.Danger,
label: "🗑️ Confirmar Eliminación",
custom_id: `confirm_delete_${block.id}`
},
{
type: ComponentType.Button,
style: ButtonStyle.Secondary,
label: "❌ Cancelar",
custom_id: "cancel_delete"
}
]
};
const confirmMessage = await message.reply({ await handlePanelInteractions(panelMessage, message, client, blocks);
embeds: [confirmEmbed],
components: [confirmRow]
});
await handleConfirmationInteraction(confirmMessage, message, client, block);
} }
async function showDeletionPanel(message: Message, client: Amayo): Promise<void> { async function fetchBlocks(
const blocks = await fetchBlocks(client, message.guildId!); client: Amayo,
guildId: string
if (blocks.length === 0) { ): Promise<BlockItem[]> {
await handleNoBlocks(message); return await client.prisma.blockV2Config.findMany({
return; where: { guildId },
} select: { name: true, id: true },
orderBy: { name: "asc" },
const deleteEmbed = createDeletionEmbed(blocks); });
const actionRow = createBlockSelectRow(blocks);
const cancelRow = createCancelRow();
const panelMessage = await message.reply({
embeds: [deleteEmbed],
components: [actionRow, cancelRow]
});
await handlePanelInteractions(panelMessage, message, client, blocks);
}
async function fetchBlocks(client: Amayo, guildId: string): Promise<BlockItem[]> {
return await client.prisma.blockV2Config.findMany({
where: { guildId },
select: { name: true, id: true },
orderBy: { name: 'asc' }
});
} }
async function handleNoBlocks(message: Message): Promise<void> { async function handleNoBlocks(message: Message): Promise<void> {
const noBlocksEmbed: APIEmbed = { const noBlocksEmbed: APIEmbed = {
color: 0xf04747, color: 0xf04747,
title: "🗂️ Panel de Eliminación de Bloques", title: "🗂️ Panel de Eliminación de Bloques",
description: "📭 **No hay bloques disponibles**\n\nNo se encontraron bloques para eliminar en este servidor.\n\nPuedes crear nuevos bloques usando `!crear-embed`.", description:
footer: { text: "Sistema de gestión de bloques • Amayo Bot" } "📭 **No hay bloques disponibles**\n\nNo se encontraron bloques para eliminar en este servidor.\n\nPuedes crear nuevos bloques usando `!crear-embed`.",
}; footer: { text: "Sistema de gestión de bloques • Amayo Bot" },
};
await message.reply({ await message.reply({
embeds: [noBlocksEmbed] embeds: [noBlocksEmbed],
}); });
} }
function createDeletionEmbed(blocks: BlockItem[]): APIEmbed { function createDeletionEmbed(blocks: BlockItem[]): APIEmbed {
return { return {
color: 0xff6b35, color: 0xff6b35,
title: "🗑️ Panel de Eliminación de Bloques", title: "🗑️ Panel de Eliminación de Bloques",
description: `📊 **${blocks.length} bloque(s) encontrado(s)**\n\n⚠ **ADVERTENCIA:** La eliminación es permanente e irreversible.\n\nSelecciona el bloque que deseas eliminar del menú de abajo:`, description: `📊 **${blocks.length} bloque(s) encontrado(s)**\n\n⚠ **ADVERTENCIA:** La eliminación es permanente e irreversible.\n\nSelecciona el bloque que deseas eliminar del menú de abajo:`,
footer: { text: "Selecciona un bloque para eliminar • Timeout: 5 minutos" } footer: { text: "Selecciona un bloque para eliminar • Timeout: 5 minutos" },
}; };
} }
function createBlockSelectRow(blocks: BlockItem[]): ActionRowBuilder { function createBlockSelectRow(blocks: BlockItem[]): ActionRowBuilder {
const selectOptions = blocks.slice(0, 25).map((block, index) => ({ const selectOptions = blocks.slice(0, 25).map((block, index) => ({
label: block.name, label: block.name,
value: block.id, // Use ID instead of name for better uniqueness value: block.id, // Use ID instead of name for better uniqueness
description: `ID: ${block.id.slice(-8)}`, description: `ID: ${block.id.slice(-8)}`,
emoji: index < 10 ? { name: `${index + 1}️⃣` } : { name: "📄" } emoji: index < 10 ? { name: `${index + 1}️⃣` } : { name: "📄" },
})); }));
return { return {
type: ComponentType.ActionRow, type: ComponentType.ActionRow,
components: [ components: [
{ {
type: ComponentType.StringSelect, type: ComponentType.StringSelect,
custom_id: "delete_block_select", custom_id: "delete_block_select",
placeholder: "🗑️ Selecciona un bloque para eliminar...", placeholder: "🗑️ Selecciona uno o varios bloques para eliminar...",
min_values: 1, min_values: 1,
max_values: 1, // Allow multi-select up to how many options we provided (max 25)
options: selectOptions max_values: Math.min(25, blocks.length),
} options: selectOptions,
] },
}; ],
};
} }
function createCancelRow(): ActionRowBuilder { function createCancelRow(): ActionRowBuilder {
return { return {
type: ComponentType.ActionRow, type: ComponentType.ActionRow,
components: [ components: [
{ {
type: ComponentType.Button, type: ComponentType.Button,
style: ButtonStyle.Danger, style: ButtonStyle.Danger,
label: "❌ Cancelar", label: "❌ Cancelar",
custom_id: "cancel_delete" custom_id: "cancel_delete",
} },
] ],
}; };
} }
async function handlePanelInteractions( async function handlePanelInteractions(
panelMessage: Message, panelMessage: Message,
originalMessage: Message, originalMessage: Message,
client: Amayo, client: Amayo,
blocks: BlockItem[] blocks: BlockItem[]
): Promise<void> { ): Promise<void> {
const collector = panelMessage.createMessageComponentCollector({ const collector = panelMessage.createMessageComponentCollector({
time: 300000, // 5 minutes time: 300000, // 5 minutes
filter: (interaction: MessageComponentInteraction) => interaction.user.id === originalMessage.author.id filter: (interaction: MessageComponentInteraction) =>
}); interaction.user.id === originalMessage.author.id,
});
collector.on("collect", async (interaction: MessageComponentInteraction) => { collector.on("collect", async (interaction: MessageComponentInteraction) => {
try { try {
if (interaction.isButton() && interaction.customId === "cancel_delete") { if (interaction.isButton() && interaction.customId === "cancel_delete") {
await handleCancellation(interaction); await handleCancellation(interaction);
collector.stop(); collector.stop();
} else if (interaction.isStringSelectMenu() && interaction.customId === "delete_block_select") { } else if (
const selectedBlockId = interaction.values[0]; interaction.isStringSelectMenu() &&
const selectedBlock = blocks.find(b => b.id === selectedBlockId); interaction.customId === "delete_block_select"
) {
const selectedIds = interaction.values;
const selectedBlocks = blocks.filter((b) => selectedIds.includes(b.id));
if (selectedBlock) { if (selectedBlocks.length === 1) {
await handleBlockSelection(interaction, client, selectedBlock); await handleBlockSelection(interaction, client, selectedBlocks[0]);
collector.stop(); collector.stop();
} } else if (selectedBlocks.length > 1) {
} // Confirm batch deletion
} catch (error) { await handleMultipleBlockSelection(
console.error("Error handling deletion interaction:", error); interaction,
if (!interaction.replied && !interaction.deferred) { client,
await interaction.reply({ selectedBlocks
content: "❌ Ocurrió un error al procesar la interacción.", );
flags: 64 // Use flags instead of ephemeral collector.stop();
});
}
} }
}); }
} catch (error) {
console.error("Error handling deletion interaction:", error);
if (!interaction.replied && !interaction.deferred) {
await interaction.reply({
content: "❌ Ocurrió un error al procesar la interacción.",
flags: 64, // Use flags instead of ephemeral
});
}
}
});
collector.on("end", async (collected, reason) => { collector.on("end", async (collected, reason) => {
if (reason === "time") { if (reason === "time") {
await handlePanelTimeout(panelMessage); await handlePanelTimeout(panelMessage);
} }
}); });
} }
async function handleCancellation(interaction: ButtonInteraction): Promise<void> { async function handleCancellation(
const canceledEmbed: APIEmbed = { interaction: ButtonInteraction
color: 0x36393f, ): Promise<void> {
title: "❌ Operación Cancelada", const canceledEmbed: APIEmbed = {
description: "La eliminación de bloques ha sido cancelada.\nNingún bloque fue eliminado.", color: 0x36393f,
footer: { text: "Operación cancelada por el usuario" } title: "Operación Cancelada",
}; description:
"La eliminación de bloques ha sido cancelada.\nNingún bloque fue eliminado.",
footer: { text: "Operación cancelada por el usuario" },
};
await interaction.update({ await interaction.update({
embeds: [canceledEmbed], embeds: [canceledEmbed],
components: [] components: [],
}); });
} }
async function handleBlockSelection( async function handleBlockSelection(
interaction: StringSelectMenuInteraction, interaction: StringSelectMenuInteraction,
client: Amayo, client: Amayo,
selectedBlock: BlockItem selectedBlock: BlockItem
): Promise<void> { ): Promise<void> {
const confirmEmbed: APIEmbed = { const confirmEmbed: APIEmbed = {
color: 0xff4444, color: 0xff4444,
title: "⚠️ Confirmar Eliminación", title: "⚠️ Confirmar Eliminación",
description: `¿Estás seguro de que quieres **eliminar permanentemente** el bloque?\n\n📄 **Nombre:** \`${selectedBlock.name}\`\n🔑 **ID:** \`${selectedBlock.id}\`\n\n❗ **Esta acción NO se puede deshacer.**`, description: `¿Estás seguro de que quieres **eliminar permanentemente** el bloque?\n\n📄 **Nombre:** \`${selectedBlock.name}\`\n🔑 **ID:** \`${selectedBlock.id}\`\n\n❗ **Esta acción NO se puede deshacer.**`,
footer: { text: "Confirma tu decisión usando los botones" } footer: { text: "Confirma tu decisión usando los botones" },
};
const confirmRow: ActionRowBuilder = {
type: ComponentType.ActionRow,
components: [
{
type: ComponentType.Button,
style: ButtonStyle.Danger,
label: "🗑️ SÍ, ELIMINAR",
custom_id: `confirm_delete_${selectedBlock.id}`,
},
{
type: ComponentType.Button,
style: ButtonStyle.Secondary,
label: "❌ Cancelar",
custom_id: "cancel_delete_final",
},
],
};
await interaction.update({
embeds: [confirmEmbed],
components: [confirmRow],
});
// Handle final confirmation
const finalCollector = interaction.message.createMessageComponentCollector({
time: 60000, // 1 minute for final confirmation
filter: (i: MessageComponentInteraction) =>
i.user.id === interaction.user.id,
});
finalCollector.on(
"collect",
async (finalInteraction: MessageComponentInteraction) => {
try {
if (finalInteraction.isButton()) {
if (finalInteraction.customId === "cancel_delete_final") {
await handleCancellation(finalInteraction);
} else if (
finalInteraction.customId === `confirm_delete_${selectedBlock.id}`
) {
await executeBlockDeletion(finalInteraction, client, selectedBlock);
}
}
finalCollector.stop();
} catch (error) {
console.error("Error in final confirmation:", error);
}
}
);
finalCollector.on("end", async (collected, reason) => {
if (reason === "time") {
await handleConfirmationTimeout(interaction.message);
}
});
}
async function handleMultipleBlockSelection(
interaction: StringSelectMenuInteraction,
client: Amayo,
selectedBlocks: BlockItem[]
): Promise<void> {
const namesList = selectedBlocks
.map(
(b) => `${b.name} (
ID: ${b.id.slice(-8)})`
)
.join("\n");
const confirmEmbed: APIEmbed = {
color: 0xff4444,
title: `⚠️ Confirmar Eliminación de ${selectedBlocks.length} bloques`,
description: `¿Estás seguro de que quieres **eliminar permanentemente** los siguientes bloques?\n\n${namesList}\n\n❗ **Esta acción NO se puede deshacer.**`,
footer: { text: "Confirma la eliminación usando los botones" },
};
const confirmRow: ActionRowBuilder = {
type: ComponentType.ActionRow,
components: [
{
type: ComponentType.Button,
style: ButtonStyle.Danger,
label: `🗑️ ELIMINAR ${selectedBlocks.length}`,
custom_id: `confirm_batch_delete_${selectedBlocks
.map((b) => b.id)
.join("_")}`,
},
{
type: ComponentType.Button,
style: ButtonStyle.Secondary,
label: "❌ Cancelar",
custom_id: "cancel_delete_final",
},
],
};
await interaction.update({
embeds: [confirmEmbed],
components: [confirmRow],
});
const finalCollector = interaction.message.createMessageComponentCollector({
time: 60000,
filter: (i: MessageComponentInteraction) =>
i.user.id === interaction.user.id,
});
finalCollector.on(
"collect",
async (finalInteraction: MessageComponentInteraction) => {
try {
if (!finalInteraction.isButton()) return;
if (finalInteraction.customId === "cancel_delete_final") {
await handleCancellation(finalInteraction);
} else if (
finalInteraction.customId.startsWith("confirm_batch_delete_")
) {
await executeBlocksDeletion(finalInteraction, client, selectedBlocks);
}
finalCollector.stop();
} catch (err) {
console.error("Error in batch final confirmation:", err);
}
}
);
finalCollector.on("end", async (_collected, reason) => {
if (reason === "time") {
await handleConfirmationTimeout(interaction.message);
}
});
}
async function executeBlocksDeletion(
interaction: ButtonInteraction,
client: Amayo,
blocks: BlockItem[]
): Promise<void> {
try {
// Delete many by IDs inside a transaction
const ids = blocks.map((b) => b.id);
await client.prisma.blockV2Config.deleteMany({
where: { id: { in: ids } },
});
const successEmbed: APIEmbed = {
color: 0x57f287,
title: "✅ Bloques Eliminados",
description: `Se eliminaron ${blocks.length} bloque(s) correctamente.`,
footer: { text: "Operación completada" },
}; };
const confirmRow: ActionRowBuilder = { await interaction.update({ embeds: [successEmbed], components: [] });
type: ComponentType.ActionRow, } catch (error) {
components: [ console.error("Error deleting blocks batch:", error);
{ const errorEmbed: APIEmbed = {
type: ComponentType.Button, color: 0xf04747,
style: ButtonStyle.Danger, title: "❌ Error al eliminar bloques",
label: "🗑️ SÍ, ELIMINAR", description:
custom_id: `confirm_delete_${selectedBlock.id}` "Ocurrió un error al eliminar los bloques seleccionados. Intenta de nuevo más tarde.",
}, footer: { text: "Error en la eliminación" },
{
type: ComponentType.Button,
style: ButtonStyle.Secondary,
label: "❌ Cancelar",
custom_id: "cancel_delete_final"
}
]
}; };
try {
await interaction.update({ await interaction.update({ embeds: [errorEmbed], components: [] });
embeds: [confirmEmbed], } catch {}
components: [confirmRow] }
});
// Handle final confirmation
const finalCollector = interaction.message.createMessageComponentCollector({
time: 60000, // 1 minute for final confirmation
filter: (i: MessageComponentInteraction) => i.user.id === interaction.user.id
});
finalCollector.on("collect", async (finalInteraction: MessageComponentInteraction) => {
try {
if (finalInteraction.isButton()) {
if (finalInteraction.customId === "cancel_delete_final") {
await handleCancellation(finalInteraction);
} else if (finalInteraction.customId === `confirm_delete_${selectedBlock.id}`) {
await executeBlockDeletion(finalInteraction, client, selectedBlock);
}
}
finalCollector.stop();
} catch (error) {
console.error("Error in final confirmation:", error);
}
});
finalCollector.on("end", async (collected, reason) => {
if (reason === "time") {
await handleConfirmationTimeout(interaction.message);
}
});
} }
async function handleConfirmationInteraction( async function handleConfirmationInteraction(
confirmMessage: Message, confirmMessage: Message,
originalMessage: Message, originalMessage: Message,
client: Amayo, client: Amayo,
block: any block: any
): Promise<void> { ): Promise<void> {
const collector = confirmMessage.createMessageComponentCollector({ const collector = confirmMessage.createMessageComponentCollector({
time: 60000, // 1 minute time: 60000, // 1 minute
filter: (interaction: MessageComponentInteraction) => interaction.user.id === originalMessage.author.id filter: (interaction: MessageComponentInteraction) =>
}); interaction.user.id === originalMessage.author.id,
});
collector.on("collect", async (interaction: MessageComponentInteraction) => { collector.on("collect", async (interaction: MessageComponentInteraction) => {
try { try {
if (interaction.isButton()) { if (interaction.isButton()) {
if (interaction.customId === "cancel_delete") { if (interaction.customId === "cancel_delete") {
await handleCancellation(interaction); await handleCancellation(interaction);
} else if (interaction.customId === `confirm_delete_${block.id}`) { } else if (interaction.customId === `confirm_delete_${block.id}`) {
await executeBlockDeletion(interaction, client, { name: block.name, id: block.id }); await executeBlockDeletion(interaction, client, {
} name: block.name,
} id: block.id,
collector.stop(); });
} catch (error) {
console.error("Error in confirmation interaction:", error);
} }
}); }
collector.stop();
} catch (error) {
console.error("Error in confirmation interaction:", error);
}
});
collector.on("end", async (collected, reason) => { collector.on("end", async (collected, reason) => {
if (reason === "time") { if (reason === "time") {
await handleConfirmationTimeout(confirmMessage); await handleConfirmationTimeout(confirmMessage);
} }
}); });
} }
async function executeBlockDeletion( async function executeBlockDeletion(
interaction: ButtonInteraction, interaction: ButtonInteraction,
client: Amayo, client: Amayo,
block: BlockItem block: BlockItem
): Promise<void> { ): Promise<void> {
try { try {
// Delete the block from database // Delete the block from database
await client.prisma.blockV2Config.delete({ await client.prisma.blockV2Config.delete({
where: { id: block.id } where: { id: block.id },
}); });
const successEmbed: APIEmbed = { const successEmbed: APIEmbed = {
color: 0x57f287, color: 0x57f287,
title: "✅ Bloque Eliminado", title: "✅ Bloque Eliminado",
description: `El bloque \`${block.name}\` ha sido eliminado exitosamente.\n\n🗑 **Operación completada**\n📄 **Bloque:** \`${block.name}\`\n🔑 **ID:** \`${block.id}\``, description: `El bloque \`${block.name}\` ha sido eliminado exitosamente.\n\n🗑 **Operación completada**\n📄 **Bloque:** \`${block.name}\`\n🔑 **ID:** \`${block.id}\``,
footer: { text: "Bloque eliminado permanentemente" } footer: { text: "Bloque eliminado permanentemente" },
}; };
await interaction.update({ await interaction.update({
embeds: [successEmbed], embeds: [successEmbed],
components: [] components: [],
}); });
} catch (error) {
console.error("Error deleting block:", error);
} catch (error) { const errorEmbed: APIEmbed = {
console.error("Error deleting block:", error); color: 0xf04747,
title: "❌ Error al Eliminar",
description: `No se pudo eliminar el bloque \`${block.name}\`.\n\nPor favor, inténtalo de nuevo más tarde.`,
footer: { text: "Error en la eliminación" },
};
const errorEmbed: APIEmbed = { await interaction.update({
color: 0xf04747, embeds: [errorEmbed],
title: "❌ Error al Eliminar", components: [],
description: `No se pudo eliminar el bloque \`${block.name}\`.\n\nPor favor, inténtalo de nuevo más tarde.`, });
footer: { text: "Error en la eliminación" } }
};
await interaction.update({
embeds: [errorEmbed],
components: []
});
}
} }
async function handlePanelTimeout(panelMessage: Message): Promise<void> { async function handlePanelTimeout(panelMessage: Message): Promise<void> {
const timeoutEmbed: APIEmbed = { const timeoutEmbed: APIEmbed = {
color: 0x36393f, color: 0x36393f,
title: "⏰ Panel Expirado", title: "⏰ Panel Expirado",
description: "El panel de eliminación ha expirado por inactividad.\n\nUsa `!eliminar-embed` para abrir un nuevo panel.", description:
footer: { text: "Panel expirado por inactividad" } "El panel de eliminación ha expirado por inactividad.\n\nUsa `!eliminar-embed` para abrir un nuevo panel.",
}; footer: { text: "Panel expirado por inactividad" },
};
try { try {
await panelMessage.edit({ await panelMessage.edit({
embeds: [timeoutEmbed], embeds: [timeoutEmbed],
components: [] components: [],
}); });
} catch (error) { } catch (error) {
console.log("Could not edit message on timeout, likely deleted"); console.log("Could not edit message on timeout, likely deleted");
} }
} }
async function handleConfirmationTimeout(confirmMessage: Message): Promise<void> { async function handleConfirmationTimeout(
const timeoutEmbed: APIEmbed = { confirmMessage: Message
color: 0x36393f, ): Promise<void> {
title: "⏰ Confirmación Expirada", const timeoutEmbed: APIEmbed = {
description: "La confirmación ha expirado por inactividad.\nLa eliminación ha sido cancelada.", color: 0x36393f,
footer: { text: "Confirmación expirada" } title: "Confirmación Expirada",
}; description:
"La confirmación ha expirado por inactividad.\nLa eliminación ha sido cancelada.",
footer: { text: "Confirmación expirada" },
};
try { try {
await confirmMessage.edit({ await confirmMessage.edit({
embeds: [timeoutEmbed], embeds: [timeoutEmbed],
components: [] components: [],
}); });
} catch (error) { } catch (error) {
console.log("Could not edit confirmation message on timeout"); console.log("Could not edit confirmation message on timeout");
} }
} }