feat: implement admin point management system with user selection and modal input
This commit is contained in:
196
LEADERBOARD_ADMIN_SYSTEM.md
Normal file
196
LEADERBOARD_ADMIN_SYSTEM.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# Sistema de Gestión de Puntos del Leaderboard
|
||||
|
||||
## 📋 Descripción
|
||||
|
||||
Se ha implementado un sistema completo de gestión de puntos administrativos para el comando `leaderboard`. Los administradores ahora pueden modificar los puntos de cualquier usuario directamente desde el leaderboard.
|
||||
|
||||
## 🎯 Características Implementadas
|
||||
|
||||
### 1. **Botón de Gestión de Puntos** (Solo para Administradores)
|
||||
- Aparece únicamente para usuarios con permiso `ManageGuild`
|
||||
- Se muestra junto al botón "Refrescar" en el leaderboard
|
||||
- Emoji: ⚙️
|
||||
- Label: "Gestionar Puntos"
|
||||
|
||||
### 2. **Select Menu de Usuarios**
|
||||
- Muestra hasta 25 usuarios con más puntos en el servidor
|
||||
- Cada opción muestra:
|
||||
- Nombre del usuario
|
||||
- Puntos totales, semanales y mensuales actuales
|
||||
- Ordenado por puntos totales (descendente)
|
||||
|
||||
### 3. **Modal de Modificación de Puntos**
|
||||
- Tres campos de entrada opcionales:
|
||||
- **Puntos Totales**
|
||||
- **Puntos Semanales**
|
||||
- **Puntos Mensuales**
|
||||
|
||||
#### Sintaxis de Modificación:
|
||||
- `+50` → Añade 50 puntos
|
||||
- `-25` → Quita 25 puntos
|
||||
- `=100` → Establece exactamente 100 puntos
|
||||
- `100` → Establece exactamente 100 puntos (sin símbolo)
|
||||
|
||||
### 4. **Confirmación Visual**
|
||||
- Embed con código de color verde
|
||||
- Muestra los valores antes y después del cambio
|
||||
- Incluye timestamp y nombre del administrador que hizo el cambio
|
||||
- Mensaje efímero (solo visible para el administrador)
|
||||
|
||||
## 📁 Archivos Creados
|
||||
|
||||
```
|
||||
src/components/
|
||||
├── buttons/
|
||||
│ ├── ldManagePoints.ts ← Botón principal de gestión
|
||||
│ └── ldRefresh.ts ← Actualizado para mostrar botón admin
|
||||
├── selectmenus/
|
||||
│ └── ldSelectUser.ts ← Select menu para elegir usuario
|
||||
└── modals/
|
||||
└── ldPointsModal.ts ← Modal para modificar puntos
|
||||
```
|
||||
|
||||
## 🔒 Seguridad
|
||||
|
||||
### Verificaciones de Permisos:
|
||||
1. **En el leaderboard**: Solo muestra el botón si el usuario tiene `ManageGuild`
|
||||
2. **En el botón**: Verifica permisos antes de mostrar el select menu
|
||||
3. **En el modal**: Verifica permisos antes de modificar la base de datos
|
||||
|
||||
### Validaciones:
|
||||
- Los puntos no pueden ser negativos (mínimo: 0)
|
||||
- Se requiere al menos un campo con valor para procesar
|
||||
- Manejo de errores en todas las etapas
|
||||
- Logs detallados de errores
|
||||
|
||||
## 🚀 Cómo Usar
|
||||
|
||||
### Para Administradores:
|
||||
|
||||
1. **Ejecuta el comando leaderboard:**
|
||||
```
|
||||
!leaderboard
|
||||
```
|
||||
o
|
||||
```
|
||||
!ld
|
||||
```
|
||||
|
||||
2. **Verás el botón "⚙️ Gestionar Puntos"**
|
||||
- Click en el botón
|
||||
|
||||
3. **Selecciona el usuario del menú desplegable**
|
||||
- Muestra nombre y estadísticas actuales
|
||||
|
||||
4. **Ingresa los cambios en el modal:**
|
||||
- Ejemplos:
|
||||
- Puntos Totales: `+100` (añade 100)
|
||||
- Puntos Semanales: `-50` (quita 50)
|
||||
- Puntos Mensuales: `=75` (establece a 75)
|
||||
|
||||
5. **Confirma el cambio**
|
||||
- Verás un embed con los valores actualizados
|
||||
- El leaderboard se puede refrescar para ver los cambios
|
||||
|
||||
### Para Usuarios Normales:
|
||||
- Solo verán el botón "Refrescar"
|
||||
- No tienen acceso a la gestión de puntos
|
||||
|
||||
## 🔄 Flujo del Sistema
|
||||
|
||||
```
|
||||
Usuario Admin presiona "Gestionar Puntos"
|
||||
↓
|
||||
Sistema verifica permisos
|
||||
↓
|
||||
Muestra lista de usuarios con puntos (Select Menu)
|
||||
↓
|
||||
Admin selecciona un usuario
|
||||
↓
|
||||
Se abre modal con 3 campos de entrada
|
||||
↓
|
||||
Admin ingresa modificaciones (+/-/=)
|
||||
↓
|
||||
Sistema actualiza la base de datos
|
||||
↓
|
||||
Muestra embed de confirmación
|
||||
↓
|
||||
Admin puede refrescar el leaderboard para ver cambios
|
||||
```
|
||||
|
||||
## 💾 Cambios en Base de Datos
|
||||
|
||||
### Modelo `PartnershipStats`:
|
||||
- Se modifica directamente el registro existente
|
||||
- Si no existe, se crea uno nuevo con valores base en 0
|
||||
- Campos modificables:
|
||||
- `totalPoints`
|
||||
- `weeklyPoints`
|
||||
- `monthlyPoints`
|
||||
|
||||
## 📊 Ejemplo de Uso
|
||||
|
||||
### Caso 1: Añadir puntos de bonificación
|
||||
```
|
||||
Usuario: "Juan"
|
||||
Puntos actuales: 150
|
||||
Acción: +50 en Puntos Totales
|
||||
Resultado: 200 puntos totales
|
||||
```
|
||||
|
||||
### Caso 2: Corregir error de conteo
|
||||
```
|
||||
Usuario: "María"
|
||||
Puntos semanales: 85
|
||||
Acción: =80 en Puntos Semanales
|
||||
Resultado: 80 puntos semanales
|
||||
```
|
||||
|
||||
### Caso 3: Penalización
|
||||
```
|
||||
Usuario: "Pedro"
|
||||
Puntos mensuales: 120
|
||||
Acción: -30 en Puntos Mensuales
|
||||
Resultado: 90 puntos mensuales
|
||||
```
|
||||
|
||||
## ⚠️ Notas Importantes
|
||||
|
||||
1. **Los cambios son inmediatos** y afectan todas las tablas del leaderboard
|
||||
2. **No hay sistema de deshacer** - confirma antes de aplicar cambios
|
||||
3. **Los puntos mínimos son 0** - no pueden ser negativos
|
||||
4. **Límite de 25 usuarios** en el select menu (limitación de Discord)
|
||||
5. **Todos los mensajes son efímeros** - solo el admin los ve
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
Para probar el sistema:
|
||||
1. Asegúrate de tener permisos de `ManageGuild`
|
||||
2. Ejecuta `!leaderboard`
|
||||
3. Verifica que aparezca el botón de gestión
|
||||
4. Prueba modificar puntos de un usuario de prueba
|
||||
5. Refresca el leaderboard para ver los cambios
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
**Problema:** No veo el botón de gestión
|
||||
- **Solución:** Verifica que tengas permisos de administrador del servidor
|
||||
|
||||
**Problema:** El select menu está vacío
|
||||
- **Solución:** Asegúrate de que haya al menos un usuario con puntos en el servidor
|
||||
|
||||
**Problema:** Los cambios no se reflejan
|
||||
- **Solución:** Presiona el botón "Refrescar" para actualizar el leaderboard
|
||||
|
||||
## 📝 Logs
|
||||
|
||||
Todos los errores se registran con:
|
||||
```typescript
|
||||
logger.error({ err: e }, 'Descripción del error')
|
||||
```
|
||||
|
||||
Los logs incluyen:
|
||||
- Errores al cargar usuarios
|
||||
- Errores al procesar selecciones
|
||||
- Errores al actualizar puntos en la base de datos
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { CommandMessage } from "../../../core/types/commands";
|
||||
import { prisma } from "../../../core/database/prisma";
|
||||
import type { Message } from "discord.js";
|
||||
import { PermissionFlagsBits } from "discord.js";
|
||||
|
||||
const MAX_ENTRIES = 10;
|
||||
|
||||
@@ -40,7 +41,7 @@ function codeBlock(lines: string[]): string {
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
export async function buildLeaderboardPanel(message: Message) {
|
||||
export async function buildLeaderboardPanel(message: Message, isAdmin: boolean = false) {
|
||||
const guild = message.guild!;
|
||||
const guildId = guild.id;
|
||||
const userId = message.author.id;
|
||||
@@ -99,6 +100,18 @@ export async function buildLeaderboardPanel(message: Message) {
|
||||
const now = new Date();
|
||||
const ts = now.toISOString().replace('T', ' ').split('.')[0];
|
||||
|
||||
// Botón base que todos ven
|
||||
const buttons: any[] = [
|
||||
{ type: 2, style: 2, emoji: '1420539242643193896', label: 'Refrescar', custom_id: 'ld_refresh' }
|
||||
];
|
||||
|
||||
// Si es admin, añadir botón de gestión
|
||||
if (isAdmin) {
|
||||
buttons.push(
|
||||
{ type: 2, style: 1, emoji: '⚙️', label: 'Gestionar Puntos', custom_id: 'ld_manage_points' }
|
||||
);
|
||||
}
|
||||
|
||||
// @ts-ignore - estructura de Display Components V2
|
||||
const panel = {
|
||||
type: 17,
|
||||
@@ -126,9 +139,7 @@ export async function buildLeaderboardPanel(message: Message) {
|
||||
{ type: 14, divider: false, spacing: 1 },
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
{ type: 2, style: 2, emoji: '1420539242643193896', label: 'Refrescar', custom_id: 'ld_refresh' }
|
||||
]
|
||||
components: buttons
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -150,7 +161,11 @@ export const command: CommandMessage = {
|
||||
return;
|
||||
}
|
||||
|
||||
const panel = await buildLeaderboardPanel(message);
|
||||
// Verificar si el usuario es administrador
|
||||
const member = await message.guild.members.fetch(message.author.id);
|
||||
const isAdmin = member.permissions.has(PermissionFlagsBits.ManageGuild);
|
||||
|
||||
const panel = await buildLeaderboardPanel(message, isAdmin);
|
||||
await message.reply({
|
||||
// @ts-ignore Flag de componentes V2
|
||||
flags: 32768,
|
||||
|
||||
90
src/components/buttons/ldManagePoints.ts
Normal file
90
src/components/buttons/ldManagePoints.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import logger from "../../core/lib/logger";
|
||||
import {
|
||||
ButtonInteraction,
|
||||
MessageFlags,
|
||||
PermissionFlagsBits,
|
||||
StringSelectMenuBuilder,
|
||||
ActionRowBuilder
|
||||
} from 'discord.js';
|
||||
import { prisma } from '../../core/database/prisma';
|
||||
|
||||
export default {
|
||||
customId: 'ld_manage_points',
|
||||
run: async (interaction: ButtonInteraction) => {
|
||||
if (!interaction.guild) {
|
||||
return interaction.reply({
|
||||
content: '❌ Solo disponible en servidores.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
// Verificar permisos de administrador
|
||||
const member = await interaction.guild.members.fetch(interaction.user.id);
|
||||
if (!member.permissions.has(PermissionFlagsBits.ManageGuild)) {
|
||||
return interaction.reply({
|
||||
content: '❌ Solo los administradores pueden gestionar puntos.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// Obtener todos los usuarios con puntos en este servidor
|
||||
const stats = await prisma.partnershipStats.findMany({
|
||||
where: { guildId: interaction.guild.id },
|
||||
orderBy: { totalPoints: 'desc' },
|
||||
take: 25 // Discord limita a 25 opciones en select menus
|
||||
});
|
||||
|
||||
if (stats.length === 0) {
|
||||
return interaction.reply({
|
||||
content: '❌ No hay usuarios con puntos en este servidor todavía.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
// Construir opciones del select menu
|
||||
const options = await Promise.all(
|
||||
stats.map(async (stat) => {
|
||||
let displayName = 'Usuario desconocido';
|
||||
try {
|
||||
const member = await interaction.guild!.members.fetch(stat.userId);
|
||||
displayName = member.displayName || member.user.username;
|
||||
} catch {
|
||||
try {
|
||||
const user = await interaction.client.users.fetch(stat.userId);
|
||||
displayName = user.username;
|
||||
} catch {
|
||||
// Mantener el nombre por defecto
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
label: displayName,
|
||||
description: `Total: ${stat.totalPoints} | Semanal: ${stat.weeklyPoints} | Mensual: ${stat.monthlyPoints}`,
|
||||
value: stat.userId
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const selectMenu = new StringSelectMenuBuilder()
|
||||
.setCustomId('ld_select_user')
|
||||
.setPlaceholder('Selecciona un usuario para gestionar sus puntos')
|
||||
.addOptions(options);
|
||||
|
||||
const row = new ActionRowBuilder<StringSelectMenuBuilder>()
|
||||
.addComponents(selectMenu);
|
||||
|
||||
await interaction.reply({
|
||||
content: '### ⚙️ Gestión de Puntos\nSelecciona el usuario al que deseas modificar los puntos:',
|
||||
components: [row],
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error({ err: e }, 'Error en ldManagePoints');
|
||||
await interaction.reply({
|
||||
content: '❌ Error al cargar la lista de usuarios.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import logger from "../../core/lib/logger";
|
||||
import { ButtonInteraction, MessageFlags } from 'discord.js';
|
||||
import { ButtonInteraction, MessageFlags, PermissionFlagsBits } from 'discord.js';
|
||||
import { buildLeaderboardPanel } from '../../commands/messages/alliaces/leaderboard';
|
||||
|
||||
export default {
|
||||
@@ -10,9 +10,14 @@ export default {
|
||||
}
|
||||
try {
|
||||
await interaction.deferUpdate();
|
||||
|
||||
// Verificar si el usuario es administrador
|
||||
const member = await interaction.guild.members.fetch(interaction.user.id);
|
||||
const isAdmin = member.permissions.has(PermissionFlagsBits.ManageGuild);
|
||||
|
||||
// Reusar el builder esperando un objeto con guild y author
|
||||
const fakeMessage: any = { guild: interaction.guild, author: interaction.user };
|
||||
const panel = await buildLeaderboardPanel(fakeMessage);
|
||||
const panel = await buildLeaderboardPanel(fakeMessage, isAdmin);
|
||||
await interaction.message.edit({ components: [panel] });
|
||||
} catch (e) {
|
||||
// @ts-ignore
|
||||
|
||||
167
src/components/modals/ldPointsModal.ts
Normal file
167
src/components/modals/ldPointsModal.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import logger from "../../core/lib/logger";
|
||||
import {
|
||||
ModalSubmitInteraction,
|
||||
MessageFlags,
|
||||
PermissionFlagsBits,
|
||||
EmbedBuilder
|
||||
} from 'discord.js';
|
||||
import { prisma } from '../../core/database/prisma';
|
||||
|
||||
export default {
|
||||
customId: 'ld_points_modal',
|
||||
run: async (interaction: ModalSubmitInteraction) => {
|
||||
if (!interaction.guild) {
|
||||
return interaction.reply({
|
||||
content: '❌ Solo disponible en servidores.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
// Verificar permisos
|
||||
const member = await interaction.guild.members.fetch(interaction.user.id);
|
||||
if (!member.permissions.has(PermissionFlagsBits.ManageGuild)) {
|
||||
return interaction.reply({
|
||||
content: '❌ Solo los administradores pueden gestionar puntos.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// Extraer el userId del customId (formato: ld_points_modal:userId)
|
||||
const userId = interaction.customId.split(':')[1];
|
||||
if (!userId) {
|
||||
return interaction.reply({
|
||||
content: '❌ Error al identificar el usuario.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
// Obtener valores del modal
|
||||
const totalInput = interaction.fields.getTextInputValue('total_points').trim();
|
||||
const weeklyInput = interaction.fields.getTextInputValue('weekly_points').trim();
|
||||
const monthlyInput = interaction.fields.getTextInputValue('monthly_points').trim();
|
||||
|
||||
// Si no se ingresó nada, retornar
|
||||
if (!totalInput && !weeklyInput && !monthlyInput) {
|
||||
return interaction.reply({
|
||||
content: '❌ Debes ingresar al menos un valor para modificar.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
// Obtener o crear el registro de stats del usuario
|
||||
let stats = await prisma.partnershipStats.findUnique({
|
||||
where: {
|
||||
userId_guildId: {
|
||||
userId,
|
||||
guildId: interaction.guild.id
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!stats) {
|
||||
// Crear nuevo registro si no existe
|
||||
stats = await prisma.partnershipStats.create({
|
||||
data: {
|
||||
userId,
|
||||
guildId: interaction.guild.id,
|
||||
totalPoints: 0,
|
||||
weeklyPoints: 0,
|
||||
monthlyPoints: 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Función para parsear el input y calcular el nuevo valor
|
||||
const calculateNewValue = (input: string, currentValue: number): number => {
|
||||
if (!input) return currentValue;
|
||||
|
||||
const firstChar = input[0];
|
||||
const numValue = parseInt(input.substring(1)) || 0;
|
||||
|
||||
if (firstChar === '+') {
|
||||
return Math.max(0, currentValue + numValue);
|
||||
} else if (firstChar === '-') {
|
||||
return Math.max(0, currentValue - numValue);
|
||||
} else if (firstChar === '=') {
|
||||
return Math.max(0, numValue);
|
||||
} else {
|
||||
// Si no tiene símbolo, tratar como valor absoluto
|
||||
const parsedValue = parseInt(input);
|
||||
return isNaN(parsedValue) ? currentValue : Math.max(0, parsedValue);
|
||||
}
|
||||
};
|
||||
|
||||
// Calcular nuevos valores
|
||||
const newTotalPoints = calculateNewValue(totalInput, stats.totalPoints);
|
||||
const newWeeklyPoints = calculateNewValue(weeklyInput, stats.weeklyPoints);
|
||||
const newMonthlyPoints = calculateNewValue(monthlyInput, stats.monthlyPoints);
|
||||
|
||||
// Actualizar en base de datos
|
||||
const updatedStats = await prisma.partnershipStats.update({
|
||||
where: {
|
||||
userId_guildId: {
|
||||
userId,
|
||||
guildId: interaction.guild.id
|
||||
}
|
||||
},
|
||||
data: {
|
||||
totalPoints: newTotalPoints,
|
||||
weeklyPoints: newWeeklyPoints,
|
||||
monthlyPoints: newMonthlyPoints
|
||||
}
|
||||
});
|
||||
|
||||
// Obtener nombre del usuario
|
||||
let userName = 'Usuario';
|
||||
try {
|
||||
const targetMember = await interaction.guild.members.fetch(userId);
|
||||
userName = targetMember.displayName || targetMember.user.username;
|
||||
} catch {
|
||||
try {
|
||||
const user = await interaction.client.users.fetch(userId);
|
||||
userName = user.username;
|
||||
} catch {
|
||||
userName = userId;
|
||||
}
|
||||
}
|
||||
|
||||
// Crear embed de confirmación
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(0x00ff00)
|
||||
.setTitle('✅ Puntos Actualizados')
|
||||
.setDescription(`Se han actualizado los puntos de **${userName}**`)
|
||||
.addFields(
|
||||
{
|
||||
name: '📊 Puntos Totales',
|
||||
value: `${stats.totalPoints} → **${newTotalPoints}**`,
|
||||
inline: true
|
||||
},
|
||||
{
|
||||
name: '📅 Puntos Semanales',
|
||||
value: `${stats.weeklyPoints} → **${newWeeklyPoints}**`,
|
||||
inline: true
|
||||
},
|
||||
{
|
||||
name: '🗓️ Puntos Mensuales',
|
||||
value: `${stats.monthlyPoints} → **${newMonthlyPoints}**`,
|
||||
inline: true
|
||||
}
|
||||
)
|
||||
.setFooter({ text: `Modificado por ${interaction.user.username}` })
|
||||
.setTimestamp();
|
||||
|
||||
await interaction.reply({
|
||||
embeds: [embed],
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
logger.error({ err: e }, 'Error en ldPointsModal');
|
||||
await interaction.reply({
|
||||
content: '❌ Error al actualizar los puntos.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
83
src/components/selectmenus/ldSelectUser.ts
Normal file
83
src/components/selectmenus/ldSelectUser.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import logger from "../../core/lib/logger";
|
||||
import {
|
||||
StringSelectMenuInteraction,
|
||||
MessageFlags,
|
||||
ModalBuilder,
|
||||
TextInputBuilder,
|
||||
TextInputStyle,
|
||||
ActionRowBuilder
|
||||
} from 'discord.js';
|
||||
|
||||
export default {
|
||||
customId: 'ld_select_user',
|
||||
run: async (interaction: StringSelectMenuInteraction) => {
|
||||
if (!interaction.guild) {
|
||||
return interaction.reply({
|
||||
content: '❌ Solo disponible en servidores.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const selectedUserId = interaction.values[0];
|
||||
|
||||
// Obtener información del usuario seleccionado para mostrar en el modal
|
||||
let userName = 'Usuario';
|
||||
try {
|
||||
const member = await interaction.guild.members.fetch(selectedUserId);
|
||||
userName = member.displayName || member.user.username;
|
||||
} catch {
|
||||
try {
|
||||
const user = await interaction.client.users.fetch(selectedUserId);
|
||||
userName = user.username;
|
||||
} catch {
|
||||
userName = selectedUserId;
|
||||
}
|
||||
}
|
||||
|
||||
// Crear modal para ingresar la cantidad de puntos
|
||||
const modal = new ModalBuilder()
|
||||
.setCustomId(`ld_points_modal:${selectedUserId}`)
|
||||
.setTitle(`Gestionar puntos de ${userName}`);
|
||||
|
||||
// Input para puntos totales
|
||||
const totalInput = new TextInputBuilder()
|
||||
.setCustomId('total_points')
|
||||
.setLabel('Puntos Totales (+ para añadir, - para quitar)')
|
||||
.setPlaceholder('Ejemplo: +50 o -25 o =100 (para establecer)')
|
||||
.setStyle(TextInputStyle.Short)
|
||||
.setRequired(false);
|
||||
|
||||
// Input para puntos semanales
|
||||
const weeklyInput = new TextInputBuilder()
|
||||
.setCustomId('weekly_points')
|
||||
.setLabel('Puntos Semanales (+ para añadir, - para quitar)')
|
||||
.setPlaceholder('Ejemplo: +10 o -5 o =50 (para establecer)')
|
||||
.setStyle(TextInputStyle.Short)
|
||||
.setRequired(false);
|
||||
|
||||
// Input para puntos mensuales
|
||||
const monthlyInput = new TextInputBuilder()
|
||||
.setCustomId('monthly_points')
|
||||
.setLabel('Puntos Mensuales (+ para añadir, - para quitar)')
|
||||
.setPlaceholder('Ejemplo: +20 o -10 o =75 (para establecer)')
|
||||
.setStyle(TextInputStyle.Short)
|
||||
.setRequired(false);
|
||||
|
||||
// Añadir los inputs al modal
|
||||
modal.addComponents(
|
||||
new ActionRowBuilder<TextInputBuilder>().addComponents(totalInput),
|
||||
new ActionRowBuilder<TextInputBuilder>().addComponents(weeklyInput),
|
||||
new ActionRowBuilder<TextInputBuilder>().addComponents(monthlyInput)
|
||||
);
|
||||
|
||||
await interaction.showModal(modal);
|
||||
} catch (e) {
|
||||
logger.error({ err: e }, 'Error en ldSelectUser');
|
||||
await interaction.reply({
|
||||
content: '❌ Error al procesar la selección.',
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user