diff --git a/src/components/buttons/ldManagePoints.ts b/src/components/buttons/ldManagePoints.ts index 4496f33..009a331 100644 --- a/src/components/buttons/ldManagePoints.ts +++ b/src/components/buttons/ldManagePoints.ts @@ -83,8 +83,8 @@ export default { await interaction.showModal(modal); } catch (e) { - //@ts-ignore - logger.error('Error en ldManagePoints:', e); + // @ts-ignore + logger.error('Error en ldManagePoints:', e as Error); await interaction.reply({ content: '❌ Error al abrir el modal de gestión.', flags: MessageFlags.Ephemeral diff --git a/src/components/modals/ldPointsModal.ts b/src/components/modals/ldPointsModal.ts index 3e86a79..2ebc13c 100644 --- a/src/components/modals/ldPointsModal.ts +++ b/src/components/modals/ldPointsModal.ts @@ -3,10 +3,27 @@ import { ModalSubmitInteraction, MessageFlags, PermissionFlagsBits, - EmbedBuilder + EmbedBuilder, + User, + Collection, + Snowflake } from 'discord.js'; import { prisma } from '../../core/database/prisma'; +interface UserSelectComponent { + custom_id: string; + type: number; + values: string[]; +} + +interface ComponentData { + components?: ComponentData[]; + component?: ComponentData; + custom_id?: string; + type?: number; + values?: string[]; +} + export default { customId: 'ld_points_modal', run: async (interaction: ModalSubmitInteraction) => { @@ -30,15 +47,16 @@ export default { try { // Obtener valores del modal con manejo seguro de errores - let totalInput: string; - let selectedUsers: any; - let userId: string; - let userName: string; + let totalInput: string = ''; + let selectedUsers: ReturnType = null; + let userId: string | undefined = undefined; + let userName: string | undefined = undefined; try { totalInput = interaction.components.getTextInputValue('points_input').trim(); } catch (error) { - logger.error('Error obteniendo points_input:', error); + // @ts-ignore + logger.error('Error obteniendo points_input:', String(error)); return interaction.reply({ content: '❌ Error al obtener el valor de puntos del modal.', flags: MessageFlags.Ephemeral @@ -51,10 +69,10 @@ export default { if (!selectedUsers || selectedUsers.size === 0) { // Fallback: intentar obtener los IDs directamente de los datos raw - const rawData = (interaction as any).data?.components; + const rawData = (interaction as any).data?.components as ComponentData[] | undefined; if (rawData) { - const userSelectComponent = this.findUserSelectComponent(rawData, 'user_select'); - if (userSelectComponent?.values?.length > 0) { + const userSelectComponent = findUserSelectComponent(rawData, 'user_select'); + if (userSelectComponent?.values?.length && userSelectComponent.values.length > 0) { userId = userSelectComponent.values[0]; logger.info(`🔄 Fallback: UserId extraído de datos raw: ${userId}`); } @@ -67,26 +85,30 @@ export default { }); } } else { - const selectedUser = Array.from(selectedUsers.values())[0]; - userId = selectedUser?.id; - userName = selectedUser?.tag ?? selectedUser?.username ?? userId; + const selectedUser = Array.from(selectedUsers.values())[0] as User; + if (selectedUser) { + userId = selectedUser.id; + userName = selectedUser.tag ?? selectedUser.username ?? userId; + } } } catch (error) { - logger.error('Error procesando UserSelect, intentando fallback:', error); + // @ts-ignore + logger.error('Error procesando UserSelect, intentando fallback:', String(error)); // Fallback más agresivo: obtener directamente de los datos raw try { - const rawData = (interaction as any).data?.components; - const userSelectComponent = this.findUserSelectComponent(rawData, 'user_select'); + const rawData = (interaction as any).data?.components as ComponentData[] | undefined; + const userSelectComponent = findUserSelectComponent(rawData, 'user_select'); - if (userSelectComponent?.values?.length > 0) { + if (userSelectComponent?.values?.length && userSelectComponent.values.length > 0) { userId = userSelectComponent.values[0]; logger.info(`🔄 Fallback agresivo: UserId extraído: ${userId}`); } else { throw new Error('No se pudo extraer userId de los datos raw'); } } catch (fallbackError) { - logger.error('Falló el fallback:', fallbackError); + // @ts-ignore + logger.error('Falló el fallback:', String(fallbackError)); return interaction.reply({ content: '❌ Error procesando la selección de usuario. Inténtalo de nuevo.', flags: MessageFlags.Ephemeral @@ -117,7 +139,8 @@ export default { const targetMember = await interaction.guild.members.fetch(userId); userName = targetMember.displayName || targetMember.user.username; } catch (error) { - logger.warn(`No se pudo obtener info del usuario ${userId}:`, error); + // @ts-ignore + logger.warn(`No se pudo obtener info del usuario ${userId}:`, String(error)); userName = `Usuario ${userId}`; } } @@ -273,8 +296,9 @@ export default { }); } catch (error) { - //@ts-ignore - logger.error('❌ Error en ldPointsModal:', error); + // @ts-ignore + // @ts-ignore + logger.error('❌ Error en ldPointsModal:', String(error)); if (!interaction.replied && !interaction.deferred) { await interaction.reply({ @@ -283,31 +307,31 @@ export default { }); } } - }, - - // Función auxiliar para buscar componentes UserSelect en datos raw - findUserSelectComponent(components: any[], customId: string): any { - if (!components) return null; - - for (const comp of components) { - if (comp.components) { - const found = this.findUserSelectComponent(comp.components, customId); - if (found) return found; - } - - if (comp.component) { - if (comp.component.custom_id === customId) { - return comp.component; - } - const found = this.findUserSelectComponent([comp.component], customId); - if (found) return found; - } - - if (comp.custom_id === customId) { - return comp; - } - } - - return null; } }; + +// Función auxiliar para buscar componentes UserSelect en datos raw +function findUserSelectComponent(components: ComponentData[] | undefined, customId: string): UserSelectComponent | null { + if (!components) return null; + + for (const comp of components) { + if (comp.components) { + const found = findUserSelectComponent(comp.components, customId); + if (found) return found; + } + + if (comp.component) { + if (comp.component.custom_id === customId) { + return comp.component as UserSelectComponent; + } + const found = findUserSelectComponent([comp.component], customId); + if (found) return found; + } + + if (comp.custom_id === customId) { + return comp as UserSelectComponent; + } + } + + return null; +} diff --git a/src/events/ready.ts b/src/events/ready.ts index 2e12957..3d2d813 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -8,17 +8,13 @@ bot.on(Events.ClientReady, () => { // ============================================ // 🛡️ HANDLER GLOBAL PARA ERRORES DE DISCORD.JS // ============================================ - // Interceptar errores específicos de ModalSubmitInteraction con UserSelect - process.on('uncaughtException', (error) => { + process.on('uncaughtException', (error: Error) => { // Interceptar errores específicos de Discord.js GuildMemberManager if (error.message?.includes("Cannot read properties of undefined (reading 'id')") && error.stack?.includes('GuildMemberManager._add')) { logger.warn('🔧 Discord.js bug interceptado: GuildMemberManager error con UserSelect en modal'); - // @ts-ignore - logger.warn('Stack trace:', error.stack); - // NO terminar el proceso, solo logear el error return; } @@ -29,24 +25,23 @@ bot.on(Events.ClientReady, () => { process.exit(1); }); - process.on('unhandledRejection', (reason, promise) => { + process.on('unhandledRejection', (reason: unknown) => { // Interceptar rechazos relacionados con el mismo bug - if (reason && typeof reason === 'object' && + if (reason && + typeof reason === 'object' && + reason !== null && 'message' in reason && - // @ts-ignore - reason.message?.includes("Cannot read properties of undefined (reading 'id')")) { + typeof (reason as any).message === 'string' && + (reason as any).message.includes("Cannot read properties of undefined (reading 'id')")) { logger.warn('🔧 Discord.js promise rejection interceptada: GuildMemberManager error'); - // @ts-ignore - logger.warn('Reason:', reason); - // NO terminar el proceso return; } // Para otras promesas rechazadas, logear pero continuar // @ts-ignore - logger.error('🚨 UnhandledRejection:', reason); + logger.error('🚨 UnhandledRejection:', reason as Error); }); // ============================================