From f742ab862ebaa1006add2c6a6d5e82529bcce5cb Mon Sep 17 00:00:00 2001 From: shnimlz Date: Sat, 20 Sep 2025 03:15:16 -0500 Subject: [PATCH] Comando para eliminar y ver los canales agregados al modelo channel alliace --- .../messages/alliaces/listChannels.ts | 340 +++++++++++++++++ .../messages/alliaces/removeChannel.ts | 357 ++++++++++++++++++ src/commands/messages/help.ts | 14 +- 3 files changed, 710 insertions(+), 1 deletion(-) create mode 100644 src/commands/messages/alliaces/listChannels.ts create mode 100644 src/commands/messages/alliaces/removeChannel.ts diff --git a/src/commands/messages/alliaces/listChannels.ts b/src/commands/messages/alliaces/listChannels.ts new file mode 100644 index 0000000..83620cc --- /dev/null +++ b/src/commands/messages/alliaces/listChannels.ts @@ -0,0 +1,340 @@ +import { CommandMessage } from "../../../core/types/commands"; +// @ts-ignore +import { EmbedBuilder, ButtonStyle, MessageFlags, ChannelType } from "discord.js"; + +export const command: CommandMessage = { + name: "listchannels-alliance", + type: "message", + aliases: ["listalchannel", "channelsally", "alliancechannels"], + cooldown: 5, + // @ts-ignore + run: async (message, args, client) => { + // Obtener canales configurados existentes con estadísticas + const existingChannels = await client.prisma.allianceChannel.findMany({ + where: { guildId: message.guildId! }, + include: { + _count: { + select: { + pointsHistory: true + } + } + }, + orderBy: { + createdAt: 'desc' + } + }); + + // Obtener estadísticas generales + const totalPointsHistory = await client.prisma.pointHistory.count({ + where: { guildId: message.guildId! } + }); + + const availableBlocks = await client.prisma.blockV2Config.count({ + where: { guildId: message.guildId! } + }); + + if (existingChannels.length === 0) { + // Embed cuando no hay canales configurados + const noChannelsEmbed = new EmbedBuilder() + .setTitle("📋 Canales de Alianza Configurados") + .setDescription("```\n🗂️ Lista vacía\n```\n\n📭 **No hay canales configurados** para alianzas en este servidor.\n\n🚀 **¿Quieres empezar?**\n• Usa `!setchannel-alliance` para configurar tu primer canal\n• Crea bloques con `!blockcreate `") + .setColor(0x36393f) + .addFields([ + { + name: "📊 Estadísticas Generales", + value: `🧩 **Bloques disponibles:** ${availableBlocks}\n📈 **Puntos totales otorgados:** ${totalPointsHistory}`, + inline: false + } + ]) + .setFooter({ + text: `📅 ${new Date().toLocaleDateString('es-ES', { + year: 'numeric', + month: 'long', + day: 'numeric' + })}` + }) + .setTimestamp(); + + const helpRow = { + type: 1, + components: [ + { + type: 2, + style: ButtonStyle.Success, + label: "➕ Configurar Canal", + custom_id: "setup_first_channel", + emoji: { name: "🔧" } + }, + { + type: 2, + style: ButtonStyle.Secondary, + label: "📖 Ayuda", + custom_id: "show_setup_help", + emoji: { name: "❓" } + } + ] + }; + + const response = await message.reply({ + embeds: [noChannelsEmbed], + components: [helpRow] + }); + + // Collector para botones de ayuda + const collector = response.createMessageComponentCollector({ + time: 300000, + filter: (i) => i.user.id === message.author.id + }); + + collector.on("collect", async (interaction) => { + if (interaction.customId === "setup_first_channel") { + await interaction.reply({ + content: "🔧 **Configurar Canal**\n\nUsa el comando: `!setchannel-alliance`\n\nEste comando te guiará paso a paso para configurar tu primer canal de alianzas.", + flags: 64 // Ephemeral + }); + } else if (interaction.customId === "show_setup_help") { + await interaction.reply({ + content: "📖 **Guía de Configuración**\n\n**Paso 1:** Crear un bloque\n`!blockcreate mi-alianza`\n\n**Paso 2:** Configurar canal\n`!setchannel-alliance`\n\n**Paso 3:** ¡Listo!\nLos usuarios ganarán puntos automáticamente.", + flags: 64 // Ephemeral + }); + } + }); + + return; + } + + // Crear descripción detallada de canales + let channelListDescription = "```\n📋 Lista de Canales Configurados\n```\n\n"; + + const channelDetails = await Promise.all( + existingChannels.map(async (config: any, index: number) => { + const channel = message.guild!.channels.cache.get(config.channelId); + const channelName = channel ? `#${channel.name}` : "❌ *Canal Eliminado*"; + const status = config.isActive ? "🟢 **Activo**" : "🔴 **Inactivo**"; + const pointsCount = config._count.pointsHistory; + + // Obtener información del bloque + const blockInfo = await client.prisma.blockV2Config.findFirst({ + where: { + guildId: message.guildId!, + name: config.blockConfigName + }, + select: { name: true, id: true } + }); + + const blockStatus = blockInfo ? "✅ Válido" : "⚠️ Bloque Eliminado"; + + const createdDate = new Date(config.createdAt).toLocaleDateString('es-ES', { + day: '2-digit', + month: '2-digit', + year: 'numeric' + }); + + return { + index: index + 1, + channelName, + status, + pointsCount, + blockName: config.blockConfigName, + blockStatus, + createdDate, + isValid: !!channel && !!blockInfo + }; + }) + ); + + // Agrupar por estado + const activeChannels = channelDetails.filter(c => c.status.includes("Activo")); + const inactiveChannels = channelDetails.filter(c => c.status.includes("Inactivo")); + + // Construir embed principal + const mainEmbed = new EmbedBuilder() + .setTitle("📋 Canales de Alianza Configurados") + .setDescription(`${channelListDescription}📊 **Resumen:** ${existingChannels.length} canal(es) configurado(s)\n🟢 **Activos:** ${activeChannels.length} • 🔴 **Inactivos:** ${inactiveChannels.length}`) + .setColor(0x5865f2) + .setThumbnail(message.guild!.iconURL({ size: 128 }) || null) + .setFooter({ + text: `📅 Actualizado • ${message.guild!.name}`, + iconURL: message.guild!.iconURL({ size: 32 }) || undefined + }) + .setTimestamp(); + + // Añadir campos de canales activos + if (activeChannels.length > 0) { + const activeList = activeChannels.slice(0, 10).map(c => + `**${c.index}.** ${c.channelName}\n` + + `└ \`${c.blockName}\` • ${c.blockStatus}\n` + + `└ 📈 **${c.pointsCount}** puntos otorgados\n` + + `└ 📅 Desde: ${c.createdDate}` + ).join('\n\n'); + + mainEmbed.addFields([ + { + name: `🟢 Canales Activos (${activeChannels.length})`, + value: activeList || "Ninguno", + inline: false + } + ]); + } + + // Añadir campos de canales inactivos (si los hay) + if (inactiveChannels.length > 0) { + const inactiveList = inactiveChannels.slice(0, 5).map(c => + `**${c.index}.** ${c.channelName}\n` + + `└ \`${c.blockName}\` • ${c.blockStatus}` + ).join('\n\n'); + + mainEmbed.addFields([ + { + name: `🔴 Canales Inactivos (${inactiveChannels.length})`, + value: inactiveList || "Ninguno", + inline: false + } + ]); + } + + // Añadir estadísticas generales + mainEmbed.addFields([ + { + name: "📊 Estadísticas del Servidor", + value: `🧩 **Bloques disponibles:** ${availableBlocks}\n📈 **Total puntos otorgados:** ${totalPointsHistory}\n⚡ **Canales más activos:** ${channelDetails.sort((a, b) => b.pointsCount - a.pointsCount).slice(0, 3).map((c, i) => `${i + 1}. ${c.channelName.replace(/[#❌*]/g, '').trim()}`).join(', ') || 'N/A'}`, + inline: false + } + ]); + + // Botones de acción + const actionRow1 = { + type: 1, + components: [ + { + type: 2, + style: ButtonStyle.Success, + label: "➕ Añadir Canal", + custom_id: "add_channel", + emoji: { name: "🔧" } + }, + { + type: 2, + style: ButtonStyle.Danger, + label: "🗑️ Eliminar Canal", + custom_id: "remove_channel", + emoji: { name: "🗑️" } + }, + { + type: 2, + style: ButtonStyle.Primary, + label: "🔄 Actualizar", + custom_id: "refresh_list", + emoji: { name: "🔄" } + } + ] + }; + + const actionRow2 = { + type: 1, + components: [ + { + type: 2, + style: ButtonStyle.Secondary, + label: "📊 Estadísticas", + custom_id: "show_stats", + emoji: { name: "📈" } + }, + { + type: 2, + style: ButtonStyle.Secondary, + label: "🧩 Ver Bloques", + custom_id: "show_blocks", + emoji: { name: "🧩" } + }, + { + type: 2, + style: ButtonStyle.Secondary, + label: "❓ Ayuda", + custom_id: "show_help", + emoji: { name: "📖" } + } + ] + }; + + const response = await message.reply({ + embeds: [mainEmbed], + components: [actionRow1, actionRow2] + }); + + // Collector para manejar interacciones + const collector = response.createMessageComponentCollector({ + time: 600000, // 10 minutos + filter: (i) => i.user.id === message.author.id + }); + + collector.on("collect", async (interaction) => { + switch (interaction.customId) { + case "add_channel": + await interaction.reply({ + content: "➕ **Añadir Canal**\n\nUsa el comando: `!setchannel-alliance`\n\nEste comando te guiará para configurar un nuevo canal de alianzas.", + flags: 64 // Ephemeral + }); + break; + + case "remove_channel": + await interaction.reply({ + content: "🗑️ **Eliminar Canal**\n\nUsa el comando: `!removechannel-alliance`\n\nEste comando te permitirá eliminar canales de la configuración de alianzas.", + flags: 64 // Ephemeral + }); + break; + + case "refresh_list": + await interaction.reply({ + content: "🔄 **Lista Actualizada**\n\nUsa el comando nuevamente: `!listchannels-alliance`\n\nEsto mostrará la información más reciente.", + flags: 64 // Ephemeral + }); + break; + + case "show_stats": + const detailedStats = channelDetails.map(c => + `• ${c.channelName}: **${c.pointsCount}** puntos` + ).join('\n'); + + await interaction.reply({ + content: `📊 **Estadísticas Detalladas**\n\n**Puntos por Canal:**\n${detailedStats}\n\n**Total del Servidor:** ${totalPointsHistory} puntos`, + flags: 64 // Ephemeral + }); + break; + + case "show_blocks": + const blocksList = await client.prisma.blockV2Config.findMany({ + where: { guildId: message.guildId! }, + select: { name: true, id: true } + }); + + const blocksText = blocksList.length > 0 + ? blocksList.map((block: any, i: number) => `${i + 1}. \`${block.name}\``).join('\n') + : "No hay bloques configurados"; + + await interaction.reply({ + content: `🧩 **Bloques Disponibles (${blocksList.length})**\n\n${blocksText}\n\n💡 Crea bloques con: \`!blockcreate \``, + flags: 64 // Ephemeral + }); + break; + + case "show_help": + await interaction.reply({ + content: `📖 **Ayuda - Sistema de Alianzas**\n\n**Comandos principales:**\n• \`!setchannel-alliance\` - Configurar canal\n• \`!removechannel-alliance\` - Eliminar canal\n• \`!listchannels-alliance\` - Ver configurados\n\n**Comandos de bloques:**\n• \`!blockcreate \` - Crear bloque\n• \`!blockeditv2 \` - Editar bloque\n• \`!embedlist\` - Ver todos los bloques`, + flags: 64 // Ephemeral + }); + break; + } + }); + + collector.on("end", async () => { + try { + await response.edit({ + components: [] // Remover botones cuando expire + }); + } catch (error) { + // Ignorar errores si el mensaje fue eliminado + } + }); + } +} diff --git a/src/commands/messages/alliaces/removeChannel.ts b/src/commands/messages/alliaces/removeChannel.ts new file mode 100644 index 0000000..a3e9bc5 --- /dev/null +++ b/src/commands/messages/alliaces/removeChannel.ts @@ -0,0 +1,357 @@ +import { CommandMessage } from "../../../core/types/commands"; +// @ts-ignore +import { ComponentType, ButtonStyle, MessageFlags, ChannelType } from "discord.js"; + +export const command: CommandMessage = { + name: "removechannel-alliance", + type: "message", + aliases: ["removealchannel", "removechannelally", "delalchannel"], + cooldown: 10, + // @ts-ignore + run: async (message, args, client) => { + if (!message.member?.permissions.has("Administrator")) { + return message.reply("❌ No tienes permisos de Administrador."); + } + + // Obtener canales configurados existentes + const existingChannels = await client.prisma.allianceChannel.findMany({ + where: { guildId: message.guildId! }, + include: { blockConfig: true } + }); + + if (existingChannels.length === 0) { + const noChannelsPanel = { + type: 17, + accent_color: 0xf04747, + components: [ + { + type: 10, + content: "# 🗑️ **Eliminar Canal de Alianzas**" + }, + { + type: 14, + spacing: 2, + divider: true + }, + { + type: 10, + content: "📭 **No hay canales configurados**\n\nNo existen canales de alianza configurados en este servidor para eliminar.\n\n💡 **Sugerencia:** Usa `!setchannel-alliance` para configurar canales primero." + } + ] + }; + + return message.reply({ + flags: MessageFlags.SuppressEmbeds, + components: [noChannelsPanel] + }); + } + + // Panel principal de eliminación + const removePanel = { + type: 17, + accent_color: 0xf04747, // Rojo para eliminación + components: [ + { + type: 10, + content: "# 🗑️ **Eliminar Canal de Alianzas**" + }, + { + type: 14, + spacing: 2, + divider: true + }, + { + type: 10, + content: `⚠️ **Atención:** Estás a punto de eliminar la configuración de alianzas de un canal.\n\n📊 **Estado actual:**\n• **${existingChannels.length}** canal(es) configurado(s)\n• **${existingChannels.filter((c: any) => c.isActive).length}** canal(es) activo(s)\n\n🎯 Selecciona el canal que deseas eliminar de la configuración:` + } + ] + }; + + // Crear opciones para el selector de canales + const channelOptions = existingChannels.map((config: any) => { + const channel = message.guild!.channels.cache.get(config.channelId); + const channelName = channel ? `#${channel.name}` : `Canal Eliminado`; + const status = config.isActive ? "🟢 Activo" : "🔴 Inactivo"; + + return { + label: channelName, + value: config.channelId, + description: `${config.blockConfigName} • ${status}`, + emoji: { name: channel ? "💬" : "⚠️" } + }; + }).slice(0, 25); + + const channelSelectRow = { + type: 1, + components: [ + { + type: 3, + custom_id: "channel_remove_select", + placeholder: "🗑️ Selecciona el canal a eliminar...", + options: channelOptions + } + ] + }; + + const cancelRow = { + type: 1, + components: [ + { + type: 2, + style: ButtonStyle.Secondary, + label: "❌ Cancelar", + custom_id: "cancel_removal" + }, + { + type: 2, + style: ButtonStyle.Primary, + label: "📋 Ver Configurados", + custom_id: "view_all_channels" + } + ] + }; + + const panelMessage = await message.reply({ + flags: MessageFlags.SuppressEmbeds, + components: [removePanel, channelSelectRow, cancelRow] + }); + + const collector = panelMessage.createMessageComponentCollector({ + time: 300000, // 5 minutos + filter: (i) => i.user.id === message.author.id + }); + + collector.on("collect", async (interaction) => { + switch (interaction.customId) { + case "channel_remove_select": + if (interaction.isStringSelectMenu()) { + const selectedChannelId = interaction.values[0]; + const selectedConfig = existingChannels.find((c: any) => c.channelId === selectedChannelId); + const selectedChannel = message.guild!.channels.cache.get(selectedChannelId); + const channelName = selectedChannel ? `#${selectedChannel.name}` : "Canal Eliminado"; + + // Panel de confirmación + const confirmPanel = { + type: 17, + accent_color: 0xff6b6b, + components: [ + { + type: 10, + content: "⚠️ **Confirmar Eliminación**" + }, + { + type: 14, + divider: true, + spacing: 2 + }, + { + type: 10, + content: `🎯 **Canal seleccionado:** ${channelName}\n` + + `🧩 **Configuración:** \`${selectedConfig?.blockConfigName}\`\n` + + `📊 **Estado:** ${selectedConfig?.isActive ? "🟢 Activo" : "🔴 Inactivo"}\n\n` + + `❗ **¿Estás seguro de eliminar esta configuración?**\n\n` + + `📝 **Efectos:**\n` + + `• Los usuarios ya no ganarán puntos en este canal\n` + + `• El historial de puntos se mantendrá\n` + + `• Esta acción NO se puede deshacer` + } + ] + }; + + const confirmRow = { + type: 1, + components: [ + { + type: 2, + style: ButtonStyle.Danger, + label: "✅ Sí, Eliminar", + custom_id: `confirm_remove_${selectedChannelId}`, + emoji: { name: "🗑️" } + }, + { + type: 2, + style: ButtonStyle.Secondary, + label: "❌ Cancelar", + custom_id: "cancel_removal" + } + ] + }; + + await interaction.update({ + components: [confirmPanel, confirmRow] + }); + } + break; + + case "cancel_removal": + const cancelPanel = { + type: 17, + accent_color: 0x36393f, + components: [ + { + type: 10, + content: "❌ **Operación Cancelada**" + }, + { + type: 14, + divider: true, + spacing: 1 + }, + { + type: 10, + content: "La eliminación ha sido cancelada.\nNingún canal fue modificado." + } + ] + }; + + await interaction.update({ + components: [cancelPanel] + }); + collector.stop(); + break; + + case "view_all_channels": + await interaction.reply({ + content: `📋 **Canales Configurados**\n\n${existingChannels.map((config: any, index: number) => { + const channel = message.guild!.channels.cache.get(config.channelId); + const channelName = channel ? `#${channel.name}` : "Canal Eliminado"; + const status = config.isActive ? "🟢 Activo" : "🔴 Inactivo"; + return `**${index + 1}.** ${channelName} - \`${config.blockConfigName}\` • ${status}`; + }).join('\n')}`, + flags: 64 // Ephemeral + }); + break; + + default: + // Manejo de confirmación de eliminación + if (interaction.customId.startsWith("confirm_remove_")) { + const channelId = interaction.customId.replace("confirm_remove_", ""); + const channelConfig = existingChannels.find((c: any) => c.channelId === channelId); + const channel = message.guild!.channels.cache.get(channelId); + const channelName = channel ? `#${channel.name}` : "Canal Eliminado"; + + try { + // Eliminar la configuración del canal + await client.prisma.allianceChannel.delete({ + where: { + guildId_channelId: { + guildId: message.guildId!, + channelId: channelId + } + } + }); + + const successPanel = { + type: 17, + accent_color: 0x57f287, + components: [ + { + type: 10, + content: "✅ **Eliminación Exitosa**" + }, + { + type: 14, + divider: true, + spacing: 2 + }, + { + type: 10, + content: `🗑️ **Canal eliminado de la configuración:**\n\n` + + `📺 **Canal:** ${channelName}\n` + + `🧩 **Configuración eliminada:** \`${channelConfig?.blockConfigName}\`\n\n` + + `✅ **Completado:** Los usuarios ya no ganarán puntos de alianza en este canal.\n\n` + + `💡 **Nota:** El historial de puntos anterior se mantiene intacto.` + } + ] + }; + + const successActionsRow = { + type: 1, + components: [ + { + type: 2, + style: ButtonStyle.Success, + label: "🏠 Finalizar", + custom_id: "finish_removal" + }, + { + type: 2, + style: ButtonStyle.Danger, + label: "🗑️ Eliminar Otro", + custom_id: "remove_another" + } + ] + }; + + await interaction.update({ + components: [successPanel, successActionsRow] + }); + + } catch (error) { + const errorPanel = { + type: 17, + accent_color: 0xf04747, + components: [ + { + type: 10, + content: "❌ **Error de Eliminación**" + }, + { + type: 14, + divider: true, + spacing: 2 + }, + { + type: 10, + content: `💥 **Error al eliminar el canal:**\n\n` + + `📺 Canal: ${channelName}\n` + + `🧩 Configuración: \`${channelConfig?.blockConfigName}\`\n\n` + + `🔍 **Posibles causas:**\n` + + `• El canal ya fue eliminado\n` + + `• Error de base de datos\n` + + `• Permisos insuficientes\n\n` + + `🔄 Intenta nuevamente.` + } + ] + }; + + await interaction.update({ components: [errorPanel] }); + } + } + break; + } + }); + + collector.on("end", async (collected, reason) => { + if (reason === "time") { + const timeoutPanel = { + type: 17, + accent_color: 0x36393f, + components: [ + { + type: 10, + content: "⏰ **Sesión Expirada**" + }, + { + type: 14, + divider: true, + spacing: 1 + }, + { + type: 10, + content: "El panel de eliminación ha expirado.\nUsa el comando nuevamente para continuar." + } + ] + }; + + try { + await panelMessage.edit({ + components: [timeoutPanel] + }); + } catch (error) { + // Mensaje eliminado o error de edición + } + } + }); + } +} diff --git a/src/commands/messages/help.ts b/src/commands/messages/help.ts index dc147d3..0f6b4cf 100644 --- a/src/commands/messages/help.ts +++ b/src/commands/messages/help.ts @@ -46,6 +46,18 @@ export const command: CommandMessage = { description: "Configurar canales para sistema de alianzas", usage: `${prefix}canal-alianza` }, + { + name: "eliminar-canal-alianza", + aliases: ["removechannel-alliance", "removealchannel", "delalchannel"], + description: "Eliminar canales de la configuración de alianzas", + usage: `${prefix}removechannel-alliance` + }, + { + name: "listar-canales-alianza", + aliases: ["listchannels-alliance", "listalchannel", "channelsally"], + description: "Ver lista detallada de canales configurados para alianzas", + usage: `${prefix}listchannels-alliance` + }, { name: "demo-componentes", aliases: ["demo", "prueba-componentes"], @@ -307,7 +319,7 @@ export const command: CommandMessage = { case "category_network": const networkPanel = { type: 17, - accent_color: 0x5865f2, + accent_color: 05865f2, components: [ { type: 10,