refactor(componentsV2): migrate all admin and game message commands to new display components API
This commit is contained in:
@@ -3,6 +3,7 @@ import type Amayo from '../../../core/client';
|
||||
import { hasManageGuildOrStaff } from '../../../core/lib/permissions';
|
||||
import { prisma } from '../../../core/database/prisma';
|
||||
import type { TextBasedChannel } from 'discord.js';
|
||||
import { buildDisplay, dividerBlock, textBlock } from '../../../core/lib/componentsV2';
|
||||
|
||||
export const command: CommandMessage = {
|
||||
name: 'area-eliminar',
|
||||
@@ -12,28 +13,18 @@ export const command: CommandMessage = {
|
||||
description: 'Eliminar un área del servidor',
|
||||
usage: 'area-eliminar <key>',
|
||||
run: async (message, args, client: Amayo) => {
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
const allowed = await hasManageGuildOrStaff(message.member, message.guild!.id, prisma);
|
||||
if (!allowed) {
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '❌ **Error de Permisos**\n└ No tienes permisos de ManageGuild ni rol de staff.'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
components: [
|
||||
buildDisplay(0xFF0000, [
|
||||
textBlock('❌ **Error de Permisos**\n└ No tienes permisos de ManageGuild ni rol de staff.')
|
||||
])
|
||||
],
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -42,26 +33,17 @@ export const command: CommandMessage = {
|
||||
const key = args[0]?.trim();
|
||||
|
||||
if (!key) {
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFFA500,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '⚠️ **Uso Incorrecto**\n└ Uso: `!area-eliminar <key>`\n└ Ejemplo: `!area-eliminar mine.cavern`'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
components: [
|
||||
buildDisplay(0xFFA500, [
|
||||
textBlock('⚠️ **Uso Incorrecto**'),
|
||||
dividerBlock(),
|
||||
textBlock('└ Uso: `!area-eliminar <key>`\n└ Ejemplo: `!area-eliminar mine.cavern`')
|
||||
])
|
||||
],
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -71,26 +53,17 @@ export const command: CommandMessage = {
|
||||
});
|
||||
|
||||
if (!area) {
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `❌ **Área No Encontrada**\n└ No se encontró el área local con key \`${key}\` en este servidor.`
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
components: [
|
||||
buildDisplay(0xFF0000, [
|
||||
textBlock(`❌ **Área No Encontrada**`),
|
||||
dividerBlock(),
|
||||
textBlock(`└ No se encontró el área local con key \`${key}\` en este servidor.`)
|
||||
])
|
||||
],
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -109,38 +82,23 @@ export const command: CommandMessage = {
|
||||
where: { id: area.id }
|
||||
});
|
||||
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0x00FF00,
|
||||
components: [
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `✅ **Área Eliminada Exitosamente**\n└ Key: \`${key}\``
|
||||
}]
|
||||
},
|
||||
...(levelsCount > 0 ? [{
|
||||
type: 14,
|
||||
divider: true
|
||||
}, {
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `⚠️ Se eliminaron ${levelsCount} nivel(es) asociado(s).`
|
||||
}]
|
||||
}] : [])
|
||||
buildDisplay(0x00FF00, [
|
||||
textBlock(`✅ **Área Eliminada Exitosamente**`),
|
||||
dividerBlock(),
|
||||
textBlock(`└ Key: \`${key}\``),
|
||||
...(levelsCount > 0
|
||||
? [
|
||||
dividerBlock(),
|
||||
textBlock(`⚠️ Se eliminaron ${levelsCount} nivel(es) asociado(s).`),
|
||||
]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
: []),
|
||||
])
|
||||
],
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import type Amayo from '../../../core/client';
|
||||
import { prisma } from '../../../core/database/prisma';
|
||||
import { ComponentType, ButtonStyle } from 'discord-api-types/v10';
|
||||
import type { MessageComponentInteraction, TextBasedChannel } from 'discord.js';
|
||||
import { buildDisplay, dividerBlock, textBlock } from '../../../core/lib/componentsV2';
|
||||
|
||||
export const command: CommandMessage = {
|
||||
name: 'areas-lista',
|
||||
@@ -34,29 +35,27 @@ export const command: CommandMessage = {
|
||||
|
||||
const totalPages = Math.ceil(total / perPage);
|
||||
|
||||
const display = {
|
||||
type: 17,
|
||||
accent_color: 0x00FF00,
|
||||
components: [
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**🗺️ Lista de Áreas**\nPágina ${page}/${totalPages} • Total: ${total}`
|
||||
}]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
...areas.map(area => ({
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**${area.name || area.key}**\n` +
|
||||
`└ Key: \`${area.key}\`\n` +
|
||||
`└ ${area.guildId === guildId ? '📍 Local' : '🌐 Global'}`
|
||||
}]
|
||||
}))
|
||||
]
|
||||
};
|
||||
const displayBlocks = [
|
||||
textBlock(`# 🗺️ Lista de Áreas`),
|
||||
dividerBlock(),
|
||||
textBlock(`Página ${page}/${totalPages} • Total: ${total}`),
|
||||
dividerBlock({ divider: false, spacing: 2 }),
|
||||
...areas.flatMap((area, index) => {
|
||||
const lines = [
|
||||
`**${area.name || area.key}**`,
|
||||
`└ Key: \`${area.key}\``,
|
||||
`└ ${area.guildId === guildId ? '📍 Local' : '🌐 Global'}`,
|
||||
].join('\n');
|
||||
|
||||
const blocks = [textBlock(lines)];
|
||||
if (index < areas.length - 1) {
|
||||
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
|
||||
}
|
||||
return blocks;
|
||||
})
|
||||
];
|
||||
|
||||
const display = buildDisplay(0x00FF00, displayBlocks);
|
||||
|
||||
const buttons: any[] = [];
|
||||
|
||||
@@ -80,7 +79,9 @@ export const command: CommandMessage = {
|
||||
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
const msg = await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
reply: { messageReference: message.id },
|
||||
components: [
|
||||
display,
|
||||
...(buttons.length > 0 ? [{
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { CommandMessage } from '../../../core/types/commands';
|
||||
import type Amayo from '../../../core/client';
|
||||
import { prisma } from '../../../core/database/prisma';
|
||||
import type { TextBasedChannel } from 'discord.js';
|
||||
import { buildDisplay, dividerBlock, textBlock } from '../../../core/lib/componentsV2';
|
||||
|
||||
export const command: CommandMessage = {
|
||||
name: 'item-ver',
|
||||
@@ -34,70 +35,42 @@ export const command: CommandMessage = {
|
||||
const props = item.props as any || {};
|
||||
const tags = item.tags || [];
|
||||
|
||||
const display = {
|
||||
type: 17,
|
||||
accent_color: 0x00D9FF,
|
||||
components: [
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**🛠️ ${item.name || item.key}**`
|
||||
}]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**Key:** \`${item.key}\`\n` +
|
||||
`**Nombre:** ${item.name || '*Sin nombre*'}\n` +
|
||||
`**Descripción:** ${item.description || '*Sin descripción*'}\n` +
|
||||
`**Categoría:** ${item.category || '*Sin categoría*'}\n` +
|
||||
`**Stackable:** ${item.stackable ? 'Sí' : 'No'}\n` +
|
||||
`**Máx. Inventario:** ${item.maxPerInventory || 'Ilimitado'}\n` +
|
||||
`**Ámbito:** ${item.guildId ? '📍 Local del servidor' : '🌐 Global'}`
|
||||
}]
|
||||
}
|
||||
]
|
||||
};
|
||||
const blocks = [
|
||||
textBlock(`# 🛠️ ${item.name || item.key}`),
|
||||
dividerBlock(),
|
||||
textBlock([
|
||||
`**Key:** \`${item.key}\``,
|
||||
`**Nombre:** ${item.name || '*Sin nombre*'}`,
|
||||
`**Descripción:** ${item.description || '*Sin descripción*'}`,
|
||||
`**Categoría:** ${item.category || '*Sin categoría*'}`,
|
||||
`**Stackable:** ${item.stackable ? 'Sí' : 'No'}`,
|
||||
`**Máx. Inventario:** ${item.maxPerInventory ?? 'Ilimitado'}`,
|
||||
`**Ámbito:** ${item.guildId ? '📍 Local del servidor' : '🌐 Global'}`,
|
||||
].join('\n')),
|
||||
];
|
||||
|
||||
if (tags.length > 0) {
|
||||
display.components.push({ type: 14, divider: true });
|
||||
display.components.push({
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**Tags:** ${tags.join(', ')}`
|
||||
}]
|
||||
});
|
||||
blocks.push(dividerBlock());
|
||||
blocks.push(textBlock(`**Tags:** ${tags.join(', ')}`));
|
||||
}
|
||||
|
||||
if (item.icon) {
|
||||
display.components.push({ type: 14, divider: true });
|
||||
display.components.push({
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**Icon URL:** ${item.icon}`
|
||||
}]
|
||||
});
|
||||
blocks.push(dividerBlock());
|
||||
blocks.push(textBlock(`**Icon URL:** ${item.icon}`));
|
||||
}
|
||||
|
||||
if (Object.keys(props).length > 0) {
|
||||
display.components.push({ type: 14, divider: true });
|
||||
display.components.push({
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**Props (JSON):**\n\`\`\`json\n${JSON.stringify(props, null, 2)}\n\`\`\``
|
||||
}]
|
||||
});
|
||||
blocks.push(dividerBlock());
|
||||
blocks.push(textBlock(`**Props (JSON):**\n\`\`\`json\n${JSON.stringify(props, null, 2)}\n\`\`\``));
|
||||
}
|
||||
|
||||
const display = buildDisplay(0x00D9FF, blocks);
|
||||
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
await (channel.send as any)({
|
||||
display,
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [display],
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import type Amayo from '../../../core/client';
|
||||
import { prisma } from '../../../core/database/prisma';
|
||||
import { ComponentType, ButtonStyle } from 'discord-api-types/v10';
|
||||
import type { MessageComponentInteraction, TextBasedChannel } from 'discord.js';
|
||||
import { buildDisplay, dividerBlock, textBlock } from '../../../core/lib/componentsV2';
|
||||
|
||||
export const command: CommandMessage = {
|
||||
name: 'items-lista',
|
||||
@@ -34,32 +35,28 @@ export const command: CommandMessage = {
|
||||
|
||||
const totalPages = Math.ceil(total / perPage);
|
||||
|
||||
const display = {
|
||||
type: 17,
|
||||
accent_color: 0x00D9FF,
|
||||
components: [
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**🛠️ Lista de Items**\nPágina ${page}/${totalPages} • Total: ${total}`
|
||||
}]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
...items.map(item => ({
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**${item.name || item.key}**\n` +
|
||||
`└ Key: \`${item.key}\`\n` +
|
||||
`└ Categoría: ${item.category || '*Sin categoría*'}\n` +
|
||||
`└ ${item.stackable ? '📚 Apilable' : '🔒 No apilable'}` +
|
||||
(item.maxPerInventory ? ` (Máx: ${item.maxPerInventory})` : '') +
|
||||
(item.guildId === guildId ? ' • 📍 Local' : ' • 🌐 Global')
|
||||
}]
|
||||
}))
|
||||
]
|
||||
};
|
||||
const displayBlocks = [
|
||||
textBlock(`# 🛠️ Lista de Items`),
|
||||
dividerBlock(),
|
||||
textBlock(`Página ${page}/${totalPages} • Total: ${total}`),
|
||||
dividerBlock({ divider: false, spacing: 2 }),
|
||||
...items.flatMap((item, index) => {
|
||||
const lines = [
|
||||
`**${item.name || item.key}**`,
|
||||
`└ Key: \`${item.key}\``,
|
||||
`└ Categoría: ${item.category || '*Sin categoría*'}`,
|
||||
`└ ${item.stackable ? '📚 Apilable' : '🔒 No apilable'}${item.maxPerInventory ? ` (Máx: ${item.maxPerInventory})` : ''}${item.guildId === guildId ? ' • 📍 Local' : ' • 🌐 Global'}`,
|
||||
].join('\n');
|
||||
|
||||
const blocks = [textBlock(lines)];
|
||||
if (index < items.length - 1) {
|
||||
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
|
||||
}
|
||||
return blocks;
|
||||
})
|
||||
];
|
||||
|
||||
const display = buildDisplay(0x00D9FF, displayBlocks);
|
||||
|
||||
const buttons: any[] = [];
|
||||
|
||||
@@ -90,7 +87,9 @@ export const command: CommandMessage = {
|
||||
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
const msg = await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
reply: { messageReference: message.id },
|
||||
components: [
|
||||
display,
|
||||
...(buttons.length > 0 ? [{
|
||||
|
||||
@@ -2,7 +2,8 @@ import type {CommandMessage} from '../../../core/types/commands';
|
||||
import type Amayo from '../../../core/client';
|
||||
import {hasManageGuildOrStaff} from '../../../core/lib/permissions';
|
||||
import {prisma} from '../../../core/database/prisma';
|
||||
import {ButtonStyle, ComponentType, MessageFlags, TextInputStyle} from 'discord-api-types/v10';
|
||||
import {ButtonStyle, ComponentType, TextInputStyle} from 'discord-api-types/v10';
|
||||
import {buildDisplay, dividerBlock, textBlock} from '../../../core/lib/componentsV2';
|
||||
import type {ButtonInteraction, MessageComponentInteraction, TextBasedChannel} from 'discord.js';
|
||||
|
||||
interface AchievementState {
|
||||
@@ -53,25 +54,12 @@ export const command: CommandMessage = {
|
||||
rewards: { coins: 100 }
|
||||
};
|
||||
|
||||
// Crear mensaje con DisplayComponents
|
||||
const displayMessage = createDisplay(state);
|
||||
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
const editorMsg = await channel.send({
|
||||
...displayMessage,
|
||||
flags: 32768, // MessageFlags.IsComponentsV2
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Primary, label: 'Base', custom_id: 'ach_base' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Secondary, label: 'Requisitos', custom_id: 'ach_req' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Secondary, label: 'Recompensas', custom_id: 'ach_reward' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'ach_save' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'ach_cancel' }
|
||||
]
|
||||
}
|
||||
]
|
||||
const editorMsg = await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
reply: { messageReference: message.id },
|
||||
components: buildEditorComponents(state)
|
||||
});
|
||||
|
||||
const collector = editorMsg.createMessageComponentCollector({
|
||||
@@ -87,19 +75,13 @@ export const command: CommandMessage = {
|
||||
case 'ach_cancel':
|
||||
await i.deferUpdate();
|
||||
await editorMsg.edit({
|
||||
display: {
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '**❌ Creación de logro cancelada.**'
|
||||
}]
|
||||
}]
|
||||
},
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: []
|
||||
components: [
|
||||
buildDisplay(0xFF0000, [
|
||||
textBlock('**❌ Creación de logro cancelada.**')
|
||||
])
|
||||
]
|
||||
});
|
||||
collector.stop('cancel');
|
||||
return;
|
||||
@@ -139,19 +121,13 @@ export const command: CommandMessage = {
|
||||
|
||||
await i.reply({ content: '✅ Logro creado exitosamente!', flags: 64 });
|
||||
await editorMsg.edit({
|
||||
display: {
|
||||
type: 17,
|
||||
accent_color: 0x00FF00,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**✅ Logro \`${state.key}\` creado exitosamente.**`
|
||||
}]
|
||||
}]
|
||||
},
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: []
|
||||
components: [
|
||||
buildDisplay(0x00FF00, [
|
||||
textBlock(`**✅ Logro \`${state.key}\` creado exitosamente.**`)
|
||||
])
|
||||
]
|
||||
});
|
||||
collector.stop('saved');
|
||||
return;
|
||||
@@ -168,19 +144,13 @@ export const command: CommandMessage = {
|
||||
if (r === 'time') {
|
||||
try {
|
||||
await editorMsg.edit({
|
||||
display: {
|
||||
type: 17,
|
||||
accent_color: 0xFFA500,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '**⏰ Editor expirado.**'
|
||||
}]
|
||||
}]
|
||||
},
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: []
|
||||
components: [
|
||||
buildDisplay(0xFFA500, [
|
||||
textBlock('**⏰ Editor expirado.**')
|
||||
])
|
||||
]
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
@@ -188,54 +158,41 @@ export const command: CommandMessage = {
|
||||
}
|
||||
};
|
||||
|
||||
function createDisplay(state: AchievementState) {
|
||||
return {
|
||||
display: {
|
||||
type: 17, // Container
|
||||
accent_color: 0xFFD700,
|
||||
components: [
|
||||
{
|
||||
type: 9, // Section
|
||||
components: [
|
||||
{
|
||||
type: 10, // Text Display
|
||||
content: `**🏆 Creando Logro: \`${state.key}\`**`
|
||||
function buildEditorDisplay(state: AchievementState) {
|
||||
const baseInfo = [
|
||||
`**Nombre:** ${state.name || '*Sin definir*'}`,
|
||||
`**Descripción:** ${state.description || '*Sin definir*'}`,
|
||||
`**Categoría:** ${state.category || 'economy'}`,
|
||||
`**Icono:** ${state.icon || '🏆'}`,
|
||||
`**Puntos:** ${state.points ?? 10}`,
|
||||
`**Oculto:** ${state.hidden ? 'Sí' : 'No'}`,
|
||||
].join('\n');
|
||||
|
||||
return buildDisplay(0xFFD700, [
|
||||
textBlock(`# 🏆 Creando Logro: \`${state.key}\``),
|
||||
dividerBlock(),
|
||||
textBlock(baseInfo),
|
||||
dividerBlock(),
|
||||
textBlock(`**Requisitos:**\n\`\`\`json\n${JSON.stringify(state.requirements, null, 2)}\n\`\`\``),
|
||||
dividerBlock(),
|
||||
textBlock(`**Recompensas:**\n\`\`\`json\n${JSON.stringify(state.rewards, null, 2)}\n\`\`\``),
|
||||
]);
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 14, divider: true }, // Separator
|
||||
|
||||
function buildEditorComponents(state: AchievementState) {
|
||||
return [
|
||||
buildEditorDisplay(state),
|
||||
{
|
||||
type: 9,
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**Nombre:** ${state.name || '*Sin definir*'}\n**Descripción:** ${state.description || '*Sin definir*'}\n**Categoría:** ${state.category || 'economy'}\n**Icono:** ${state.icon || '🏆'}\n**Puntos:** ${state.points || 10}\n**Oculto:** ${state.hidden ? 'Sí' : 'No'}`
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**Requisitos:**\n\`\`\`json\n${JSON.stringify(state.requirements, null, 2)}\n\`\`\``
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**Recompensas:**\n\`\`\`json\n${JSON.stringify(state.rewards, null, 2)}\n\`\`\``
|
||||
}
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Primary, label: 'Base', custom_id: 'ach_base' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Secondary, label: 'Requisitos', custom_id: 'ach_req' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Secondary, label: 'Recompensas', custom_id: 'ach_reward' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'ach_save' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'ach_cancel' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
async function showBaseModal(i: ButtonInteraction, state: AchievementState, editorMsg: any) {
|
||||
@@ -316,7 +273,11 @@ async function showBaseModal(i: ButtonInteraction, state: AchievementState, edit
|
||||
state.points = parseInt(submit.components.getTextInputValue('points')) || 10;
|
||||
|
||||
await submit.deferUpdate();
|
||||
await editorMsg.edit(createDisplay(state));
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: buildEditorComponents(state)
|
||||
});
|
||||
}
|
||||
|
||||
async function showRequirementsModal(i: ButtonInteraction, state: AchievementState, editorMsg: any) {
|
||||
@@ -351,7 +312,11 @@ async function showRequirementsModal(i: ButtonInteraction, state: AchievementSta
|
||||
try {
|
||||
state.requirements = JSON.parse(submit.components.getTextInputValue('requirements'));
|
||||
await submit.deferUpdate();
|
||||
await editorMsg.edit(createDisplay(state));
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: buildEditorComponents(state)
|
||||
});
|
||||
} catch (e) {
|
||||
await submit.reply({ content: '❌ JSON inválido en requisitos.', flags: 64 });
|
||||
}
|
||||
@@ -389,7 +354,11 @@ async function showRewardsModal(i: ButtonInteraction, state: AchievementState, e
|
||||
try {
|
||||
state.rewards = JSON.parse(submit.components.getTextInputValue('rewards'));
|
||||
await submit.deferUpdate();
|
||||
await editorMsg.edit(createDisplay(state));
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: buildEditorComponents(state)
|
||||
});
|
||||
} catch (e) {
|
||||
await submit.reply({ content: '❌ JSON inválido en recompensas.', flags: 64 });
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { CommandMessage } from '../../../core/types/commands';
|
||||
import type Amayo from '../../../core/client';
|
||||
import { prisma } from '../../../core/database/prisma';
|
||||
import type { TextBasedChannel } from 'discord.js';
|
||||
import { ComponentType, ButtonStyle } from 'discord-api-types/v10';
|
||||
import { buildDisplay, dividerBlock, textBlock } from '../../../core/lib/componentsV2';
|
||||
|
||||
export const command: CommandMessage = {
|
||||
name: 'logro-ver',
|
||||
@@ -50,78 +50,40 @@ export const command: CommandMessage = {
|
||||
const req = achievement.requirements as any;
|
||||
const rew = achievement.rewards as any;
|
||||
|
||||
const display = {
|
||||
type: 17,
|
||||
accent_color: 0xFFD700,
|
||||
components: [
|
||||
{
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `${achievement.icon || '🏆'} **${achievement.name}**`
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**Descripción:** ${achievement.description}\n` +
|
||||
`**Key:** \`${achievement.key}\`\n` +
|
||||
`**Categoría:** ${achievement.category}\n` +
|
||||
`**Puntos:** ${achievement.points} pts\n` +
|
||||
`**Visibilidad:** ${achievement.hidden ? '🔒 Oculto' : '👁️ Visible'}\n` +
|
||||
`**Ámbito:** ${achievement.guildId ? '📍 Local del servidor' : '🌐 Global'}\n` +
|
||||
`**Desbloqueados:** ${unlockedCount} jugadores`
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**📋 Requisitos:**\n\`\`\`json\n${JSON.stringify(req, null, 2)}\n\`\`\``
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**🎁 Recompensas:**\n\`\`\`json\n${JSON.stringify(rew, null, 2)}\n\`\`\``
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
const blocks = [
|
||||
textBlock(`${achievement.icon || '🏆'} **${achievement.name}**`),
|
||||
dividerBlock(),
|
||||
textBlock([
|
||||
`**Descripción:** ${achievement.description}`,
|
||||
`**Key:** \`${achievement.key}\``,
|
||||
`**Categoría:** ${achievement.category}`,
|
||||
`**Puntos:** ${achievement.points} pts`,
|
||||
`**Visibilidad:** ${achievement.hidden ? '🔒 Oculto' : '👁️ Visible'}`,
|
||||
`**Ámbito:** ${achievement.guildId ? '📍 Local del servidor' : '🌐 Global'}`,
|
||||
`**Desbloqueados:** ${unlockedCount} jugadores`,
|
||||
].join('\n')),
|
||||
dividerBlock(),
|
||||
textBlock(`**📋 Requisitos:**\n\`\`\`json\n${JSON.stringify(req, null, 2)}\n\`\`\``),
|
||||
dividerBlock(),
|
||||
textBlock(`**🎁 Recompensas:**\n\`\`\`json\n${JSON.stringify(rew, null, 2)}\n\`\`\``),
|
||||
];
|
||||
|
||||
if (achievement.unlocked.length > 0) {
|
||||
display.components.push({ type: 14, divider: true });
|
||||
display.components.push({
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**🏆 Últimos Desbloqueados:**\n` +
|
||||
achievement.unlocked.slice(0, 5).map(pa =>
|
||||
`• <@${pa.userId}> - ${pa.unlockedAt ? new Date(pa.unlockedAt).toLocaleDateString() : 'N/A'}`
|
||||
).join('\n')
|
||||
}
|
||||
]
|
||||
});
|
||||
const unlockedLines = achievement.unlocked.slice(0, 5)
|
||||
.map(pa => `• <@${pa.userId}> - ${pa.unlockedAt ? new Date(pa.unlockedAt).toLocaleDateString() : 'N/A'}`)
|
||||
.join('\n');
|
||||
blocks.push(dividerBlock());
|
||||
blocks.push(textBlock(`**🏆 Últimos Desbloqueados:**\n${unlockedLines}`));
|
||||
}
|
||||
|
||||
const display = buildDisplay(0xFFD700, blocks);
|
||||
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [display]
|
||||
components: [display],
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import { hasManageGuildOrStaff } from '../../../core/lib/permissions';
|
||||
import { prisma } from '../../../core/database/prisma';
|
||||
import { ComponentType, ButtonStyle } from 'discord-api-types/v10';
|
||||
import type { MessageComponentInteraction, TextBasedChannel } from 'discord.js';
|
||||
import { buildDisplay, dividerBlock, textBlock } from '../../../core/lib/componentsV2';
|
||||
|
||||
export const command: CommandMessage = {
|
||||
name: 'logros-lista',
|
||||
@@ -35,36 +36,29 @@ export const command: CommandMessage = {
|
||||
|
||||
const totalPages = Math.ceil(total / perPage);
|
||||
|
||||
const display = {
|
||||
type: 17,
|
||||
accent_color: 0xFFD700,
|
||||
components: [
|
||||
{
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**🏆 Lista de Logros**\nPágina ${page}/${totalPages} • Total: ${total}`
|
||||
const displayBlocks = [
|
||||
textBlock(`# 🏆 Lista de Logros`),
|
||||
dividerBlock(),
|
||||
textBlock(`Página ${page}/${totalPages} • Total: ${total}`),
|
||||
dividerBlock({ divider: false, spacing: 2 }),
|
||||
...achievements.flatMap((ach, index) => {
|
||||
const lines = [
|
||||
`${ach.icon || '🏆'} **${ach.name}** (${ach.points} pts)`,
|
||||
`└ Key: \`${ach.key}\``,
|
||||
`└ Categoría: ${ach.category}`,
|
||||
`└ ${ach.description}`,
|
||||
`└ ${ach.hidden ? '🔒 Oculto' : '👁️ Visible'}${ach.guildId === guildId ? ' • 📍 Local' : ' • 🌐 Global'}`,
|
||||
].join('\n');
|
||||
|
||||
const blocks = [textBlock(lines)];
|
||||
if (index < achievements.length - 1) {
|
||||
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
...achievements.map(ach => ({
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `${ach.icon || '🏆'} **${ach.name}** (${ach.points} pts)\n` +
|
||||
`└ Key: \`${ach.key}\`\n` +
|
||||
`└ Categoría: ${ach.category}\n` +
|
||||
`└ ${ach.description}\n` +
|
||||
`└ ${ach.hidden ? '🔒 Oculto' : '👁️ Visible'}` +
|
||||
(ach.guildId === guildId ? ' • 📍 Local' : ' • 🌐 Global')
|
||||
}
|
||||
]
|
||||
}))
|
||||
]
|
||||
};
|
||||
return blocks;
|
||||
})
|
||||
];
|
||||
|
||||
const display = buildDisplay(0xFFD700, displayBlocks);
|
||||
|
||||
const buttons: any[] = [];
|
||||
|
||||
@@ -95,7 +89,9 @@ export const command: CommandMessage = {
|
||||
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
const msg = await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
reply: { messageReference: message.id },
|
||||
components: [
|
||||
display,
|
||||
...(buttons.length > 0 ? [{
|
||||
|
||||
@@ -3,6 +3,7 @@ import type Amayo from '../../../core/client';
|
||||
import { hasManageGuildOrStaff } from '../../../core/lib/permissions';
|
||||
import { prisma } from '../../../core/database/prisma';
|
||||
import { ComponentType, TextInputStyle, ButtonStyle } from 'discord-api-types/v10';
|
||||
import { buildDisplay, dividerBlock, textBlock } from '../../../core/lib/componentsV2';
|
||||
import type { ButtonInteraction, MessageComponentInteraction, TextBasedChannel } from 'discord.js';
|
||||
|
||||
interface QuestState {
|
||||
@@ -53,24 +54,12 @@ export const command: CommandMessage = {
|
||||
rewards: { coins: 500 }
|
||||
};
|
||||
|
||||
const displayMessage = createDisplay(state);
|
||||
|
||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||
const editorMsg = await channel.send({
|
||||
...displayMessage,
|
||||
const editorMsg = await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Primary, label: 'Base', custom_id: 'quest_base' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Secondary, label: 'Requisitos', custom_id: 'quest_req' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Secondary, label: 'Recompensas', custom_id: 'quest_reward' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'quest_save' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'quest_cancel' }
|
||||
]
|
||||
}
|
||||
]
|
||||
reply: { messageReference: message.id },
|
||||
components: buildEditorComponents(state)
|
||||
});
|
||||
|
||||
const collector = editorMsg.createMessageComponentCollector({
|
||||
@@ -86,19 +75,13 @@ export const command: CommandMessage = {
|
||||
case 'quest_cancel':
|
||||
await i.deferUpdate();
|
||||
await editorMsg.edit({
|
||||
display: {
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '**❌ Creación de misión cancelada.**'
|
||||
}]
|
||||
}]
|
||||
},
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: []
|
||||
components: [
|
||||
buildDisplay(0xFF0000, [
|
||||
textBlock('**❌ Creación de misión cancelada.**')
|
||||
])
|
||||
]
|
||||
});
|
||||
collector.stop('cancel');
|
||||
return;
|
||||
@@ -139,19 +122,13 @@ export const command: CommandMessage = {
|
||||
|
||||
await i.reply({ content: '✅ Misión creada exitosamente.', flags: 64 });
|
||||
await editorMsg.edit({
|
||||
display: {
|
||||
type: 17,
|
||||
accent_color: 0x00FF00,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**✅ Misión \`${state.key}\` creada exitosamente.**`
|
||||
}]
|
||||
}]
|
||||
},
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: []
|
||||
components: [
|
||||
buildDisplay(0x00FF00, [
|
||||
textBlock(`**✅ Misión \`${state.key}\` creada exitosamente.**`)
|
||||
])
|
||||
]
|
||||
});
|
||||
collector.stop('saved');
|
||||
return;
|
||||
@@ -168,19 +145,13 @@ export const command: CommandMessage = {
|
||||
if (r === 'time') {
|
||||
try {
|
||||
await editorMsg.edit({
|
||||
display: {
|
||||
type: 17,
|
||||
accent_color: 0xFFA500,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '**⏰ Editor expirado.**'
|
||||
}]
|
||||
}]
|
||||
},
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: []
|
||||
components: [
|
||||
buildDisplay(0xFFA500, [
|
||||
textBlock('**⏰ Editor expirado.**')
|
||||
])
|
||||
]
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
@@ -188,7 +159,7 @@ export const command: CommandMessage = {
|
||||
}
|
||||
};
|
||||
|
||||
function createDisplay(state: QuestState) {
|
||||
function buildEditorDisplay(state: QuestState) {
|
||||
const typeEmojis: Record<string, string> = {
|
||||
daily: '📅',
|
||||
weekly: '📆',
|
||||
@@ -196,53 +167,40 @@ function createDisplay(state: QuestState) {
|
||||
event: '🎉'
|
||||
};
|
||||
|
||||
return {
|
||||
display: {
|
||||
type: 17, // Container
|
||||
accent_color: 0x5865F2,
|
||||
components: [
|
||||
{
|
||||
type: 9, // Section
|
||||
components: [
|
||||
{
|
||||
type: 10, // Text Display
|
||||
content: `**📜 Creando Misión: \`${state.key}\`**`
|
||||
const baseInfo = [
|
||||
`**Nombre:** ${state.name || '*Sin definir*'}`,
|
||||
`**Descripción:** ${state.description || '*Sin definir*'}`,
|
||||
`**Categoría:** ${state.category || 'mining'}`,
|
||||
`**Tipo:** ${typeEmojis[state.type || 'daily']} ${state.type || 'daily'}`,
|
||||
`**Icono:** ${state.icon || '📋'}`,
|
||||
`**Repetible:** ${state.repeatable ? 'Sí' : 'No'}`
|
||||
].join('\n');
|
||||
|
||||
return buildDisplay(0x5865F2, [
|
||||
textBlock(`# 📜 Creando Misión: \`${state.key}\``),
|
||||
dividerBlock(),
|
||||
textBlock(baseInfo),
|
||||
dividerBlock(),
|
||||
textBlock(`**Requisitos:**\n\`\`\`json\n${JSON.stringify(state.requirements, null, 2)}\n\`\`\``),
|
||||
dividerBlock(),
|
||||
textBlock(`**Recompensas:**\n\`\`\`json\n${JSON.stringify(state.rewards, null, 2)}\n\`\`\``)
|
||||
]);
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 14, divider: true }, // Separator
|
||||
|
||||
function buildEditorComponents(state: QuestState) {
|
||||
return [
|
||||
buildEditorDisplay(state),
|
||||
{
|
||||
type: 9,
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**Nombre:** ${state.name || '*Sin definir*'}\n**Descripción:** ${state.description || '*Sin definir*'}\n**Categoría:** ${state.category || 'mining'}\n**Tipo:** ${typeEmojis[state.type || 'daily']} ${state.type || 'daily'}\n**Icono:** ${state.icon || '📋'}\n**Repetible:** ${state.repeatable ? 'Sí' : 'No'}`
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**Requisitos:**\n\`\`\`json\n${JSON.stringify(state.requirements, null, 2)}\n\`\`\``
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content: `**Recompensas:**\n\`\`\`json\n${JSON.stringify(state.rewards, null, 2)}\n\`\`\``
|
||||
}
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Primary, label: 'Base', custom_id: 'quest_base' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Secondary, label: 'Requisitos', custom_id: 'quest_req' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Secondary, label: 'Recompensas', custom_id: 'quest_reward' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'quest_save' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'quest_cancel' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
async function showBaseModal(i: ButtonInteraction, state: QuestState, editorMsg: any) {
|
||||
@@ -323,7 +281,11 @@ async function showBaseModal(i: ButtonInteraction, state: QuestState, editorMsg:
|
||||
state.icon = submit.components.getTextInputValue('icon') || '📋';
|
||||
|
||||
await submit.deferUpdate();
|
||||
await editorMsg.edit(createDisplay(state));
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: buildEditorComponents(state)
|
||||
});
|
||||
}
|
||||
|
||||
async function showRequirementsModal(i: ButtonInteraction, state: QuestState, editorMsg: any) {
|
||||
@@ -358,7 +320,11 @@ async function showRequirementsModal(i: ButtonInteraction, state: QuestState, ed
|
||||
try {
|
||||
state.requirements = JSON.parse(submit.components.getTextInputValue('requirements'));
|
||||
await submit.deferUpdate();
|
||||
await editorMsg.edit(createDisplay(state));
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: buildEditorComponents(state)
|
||||
});
|
||||
} catch (e) {
|
||||
await submit.reply({ content: '❌ JSON inválido en requisitos.', flags: 64 });
|
||||
}
|
||||
@@ -396,7 +362,11 @@ async function showRewardsModal(i: ButtonInteraction, state: QuestState, editorM
|
||||
try {
|
||||
state.rewards = JSON.parse(submit.components.getTextInputValue('rewards'));
|
||||
await submit.deferUpdate();
|
||||
await editorMsg.edit(createDisplay(state));
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: buildEditorComponents(state)
|
||||
});
|
||||
} catch (e) {
|
||||
await submit.reply({ content: '❌ JSON inválido en recompensas.', flags: 64 });
|
||||
}
|
||||
|
||||
@@ -13,48 +13,61 @@ interface AreaState {
|
||||
metadata?: any;
|
||||
}
|
||||
|
||||
function createAreaDisplay(state: AreaState, editing: boolean = false) {
|
||||
function buildAreaDisplay(state: AreaState, editing: boolean = false) {
|
||||
const title = editing ? 'Editando Área' : 'Creando Área';
|
||||
const statusText = [
|
||||
'**📋 Estado Actual:**',
|
||||
`**Nombre:** ${state.name || '❌ No configurado'}`,
|
||||
`**Tipo:** ${state.type || '❌ No configurado'}`,
|
||||
`**Config:** ${Object.keys(state.config || {}).length} campos`,
|
||||
`**Metadata:** ${Object.keys(state.metadata || {}).length} campos`
|
||||
].join('\n');
|
||||
|
||||
const instructionsText = [
|
||||
'**🎮 Instrucciones:**',
|
||||
'• **Base**: Configura nombre y tipo',
|
||||
'• **Config (JSON)**: Configuración técnica',
|
||||
'• **Meta (JSON)**: Metadatos adicionales',
|
||||
'• **Guardar**: Confirma los cambios',
|
||||
'• **Cancelar**: Descarta los cambios'
|
||||
].join('\n');
|
||||
|
||||
return {
|
||||
type: 17,
|
||||
accent_color: 0x00FF00,
|
||||
components: [
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `🗺️ **${title}: \`${state.key}\`**`
|
||||
}]
|
||||
content: `# 🗺️ ${title}: \`${state.key}\``
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**📋 Estado Actual:**\n` +
|
||||
`**Nombre:** ${state.name || '❌ No configurado'}\n` +
|
||||
`**Tipo:** ${state.type || '❌ No configurado'}\n` +
|
||||
`**Config:** ${Object.keys(state.config || {}).length} campos\n` +
|
||||
`**Metadata:** ${Object.keys(state.metadata || {}).length} campos`
|
||||
}]
|
||||
content: statusText
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**🎮 Instrucciones:**\n` +
|
||||
`• **Base**: Configura nombre y tipo\n` +
|
||||
`• **Config (JSON)**: Configuración técnica\n` +
|
||||
`• **Meta (JSON)**: Metadatos adicionales\n` +
|
||||
`• **Guardar**: Confirma los cambios\n` +
|
||||
`• **Cancelar**: Descarta los cambios`
|
||||
}]
|
||||
content: instructionsText
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
const buildEditorComponents = (state: AreaState, editing: boolean = false) => [
|
||||
buildAreaDisplay(state, editing),
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
{ type: 2, style: ButtonStyle.Primary, label: 'Base', custom_id: 'ga_base' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Config (JSON)', custom_id: 'ga_config' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Meta (JSON)', custom_id: 'ga_meta' },
|
||||
{ type: 2, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'ga_save' },
|
||||
{ type: 2, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'ga_cancel' },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export const command: CommandMessage = {
|
||||
name: 'area-crear',
|
||||
type: 'message',
|
||||
@@ -67,24 +80,17 @@ export const command: CommandMessage = {
|
||||
const allowed = await hasManageGuildOrStaff(message.member, message.guild!.id, prisma);
|
||||
if (!allowed) {
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '❌ **Error de Permisos**\n└ No tienes permisos de ManageGuild ni rol de staff.'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -92,24 +98,17 @@ export const command: CommandMessage = {
|
||||
const key = args[0]?.trim();
|
||||
if (!key) {
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFFA500,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '⚠️ **Uso Incorrecto**\n└ Uso: `!area-crear <key-única>`'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -118,47 +117,28 @@ export const command: CommandMessage = {
|
||||
const exists = await prisma.gameArea.findFirst({ where: { key, guildId } });
|
||||
if (exists) {
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '❌ **Área Ya Existe**\n└ Ya existe un área con esa key en este servidor.'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const state: AreaState = { key, config: {}, metadata: {} };
|
||||
|
||||
const display = createAreaDisplay(state, false);
|
||||
|
||||
const editorMsg = await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [
|
||||
display,
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
{ type: 2, style: ButtonStyle.Primary, label: 'Base', custom_id: 'ga_base' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Config (JSON)', custom_id: 'ga_config' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Meta (JSON)', custom_id: 'ga_meta' },
|
||||
{ type: 2, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'ga_save' },
|
||||
{ type: 2, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'ga_cancel' },
|
||||
]
|
||||
}
|
||||
]
|
||||
components: buildEditorComponents(state, false),
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
|
||||
const collector = editorMsg.createMessageComponentCollector({ time: 30*60_000, filter: (i)=> i.user.id === message.author.id });
|
||||
@@ -169,18 +149,16 @@ export const command: CommandMessage = {
|
||||
case 'ga_cancel':
|
||||
await i.deferUpdate();
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '**❌ Editor de Área cancelado.**'
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
collector.stop('cancel');
|
||||
return;
|
||||
@@ -198,18 +176,16 @@ export const command: CommandMessage = {
|
||||
await prisma.gameArea.create({ data: { guildId, key: state.key, name: state.name!, type: state.type!, config: state.config ?? {}, metadata: state.metadata ?? {} } });
|
||||
await i.reply({ content: '✅ Área guardada.', flags: MessageFlags.Ephemeral });
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0x00FF00,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**✅ Área \`${state.key}\` creada exitosamente.**`
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
collector.stop('saved');
|
||||
return;
|
||||
@@ -223,18 +199,16 @@ export const command: CommandMessage = {
|
||||
if (r==='time') {
|
||||
try {
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFFA500,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '**⏰ Editor expirado.**'
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
@@ -255,22 +229,10 @@ async function showBaseModal(i: ButtonInteraction, state: AreaState, editorMsg:
|
||||
await sub.reply({ content: '✅ Base actualizada.', flags: MessageFlags.Ephemeral });
|
||||
|
||||
// Actualizar display
|
||||
const newDisplay = createAreaDisplay(state, editing);
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [
|
||||
newDisplay,
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
{ type: 2, style: ButtonStyle.Primary, label: 'Base', custom_id: 'ga_base' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Config (JSON)', custom_id: 'ga_config' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Meta (JSON)', custom_id: 'ga_meta' },
|
||||
{ type: 2, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'ga_save' },
|
||||
{ type: 2, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'ga_cancel' },
|
||||
]
|
||||
}
|
||||
]
|
||||
components: buildEditorComponents(state, editing)
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
@@ -298,22 +260,10 @@ async function showJsonModal(i: ButtonInteraction, state: AreaState, field: 'con
|
||||
}
|
||||
|
||||
// Actualizar display
|
||||
const newDisplay = createAreaDisplay(state, editing);
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [
|
||||
newDisplay,
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
{ type: 2, style: ButtonStyle.Primary, label: 'Base', custom_id: 'ga_base' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Config (JSON)', custom_id: 'ga_config' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Meta (JSON)', custom_id: 'ga_meta' },
|
||||
{ type: 2, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'ga_save' },
|
||||
{ type: 2, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'ga_cancel' },
|
||||
]
|
||||
}
|
||||
]
|
||||
components: buildEditorComponents(state, editing)
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
@@ -13,48 +13,61 @@ interface AreaState {
|
||||
metadata?: any;
|
||||
}
|
||||
|
||||
function createAreaDisplay(state: AreaState, editing: boolean = false) {
|
||||
function buildAreaDisplay(state: AreaState, editing: boolean = false) {
|
||||
const title = editing ? 'Editando Área' : 'Creando Área';
|
||||
const statusText = [
|
||||
'**📋 Estado Actual:**',
|
||||
`**Nombre:** ${state.name || '❌ No configurado'}`,
|
||||
`**Tipo:** ${state.type || '❌ No configurado'}`,
|
||||
`**Config:** ${Object.keys(state.config || {}).length} campos`,
|
||||
`**Metadata:** ${Object.keys(state.metadata || {}).length} campos`
|
||||
].join('\n');
|
||||
|
||||
const instructionsText = [
|
||||
'**🎮 Instrucciones:**',
|
||||
'• **Base**: Configura nombre y tipo',
|
||||
'• **Config (JSON)**: Configuración técnica',
|
||||
'• **Meta (JSON)**: Metadatos adicionales',
|
||||
'• **Guardar**: Confirma los cambios',
|
||||
'• **Cancelar**: Descarta los cambios'
|
||||
].join('\n');
|
||||
|
||||
return {
|
||||
type: 17,
|
||||
accent_color: 0x00FF00,
|
||||
components: [
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `🗺️ **${title}: \`${state.key}\`**`
|
||||
}]
|
||||
content: `# 🗺️ ${title}: \`${state.key}\``
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**📋 Estado Actual:**\n` +
|
||||
`**Nombre:** ${state.name || '❌ No configurado'}\n` +
|
||||
`**Tipo:** ${state.type || '❌ No configurado'}\n` +
|
||||
`**Config:** ${Object.keys(state.config || {}).length} campos\n` +
|
||||
`**Metadata:** ${Object.keys(state.metadata || {}).length} campos`
|
||||
}]
|
||||
content: statusText
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**🎮 Instrucciones:**\n` +
|
||||
`• **Base**: Configura nombre y tipo\n` +
|
||||
`• **Config (JSON)**: Configuración técnica\n` +
|
||||
`• **Meta (JSON)**: Metadatos adicionales\n` +
|
||||
`• **Guardar**: Confirma los cambios\n` +
|
||||
`• **Cancelar**: Descarta los cambios`
|
||||
}]
|
||||
content: instructionsText
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
const buildEditorComponents = (state: AreaState, editing: boolean = false) => [
|
||||
buildAreaDisplay(state, editing),
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
{ type: 2, style: ButtonStyle.Primary, label: 'Base', custom_id: 'ga_base' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Config (JSON)', custom_id: 'ga_config' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Meta (JSON)', custom_id: 'ga_meta' },
|
||||
{ type: 2, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'ga_save' },
|
||||
{ type: 2, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'ga_cancel' },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export const command: CommandMessage = {
|
||||
name: 'area-editar',
|
||||
type: 'message',
|
||||
@@ -67,24 +80,17 @@ export const command: CommandMessage = {
|
||||
const allowed = await hasManageGuildOrStaff(message.member, message.guild!.id, prisma);
|
||||
if (!allowed) {
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '❌ **Error de Permisos**\n└ No tienes permisos de ManageGuild ni rol de staff.'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -92,24 +98,17 @@ export const command: CommandMessage = {
|
||||
const key = args[0]?.trim();
|
||||
if (!key) {
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFFA500,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '⚠️ **Uso Incorrecto**\n└ Uso: `!area-editar <key-única>`'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -118,47 +117,28 @@ export const command: CommandMessage = {
|
||||
const area = await prisma.gameArea.findFirst({ where: { key, guildId } });
|
||||
if (!area) {
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '❌ **Área No Encontrada**\n└ No existe un área con esa key en este servidor.'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const state: AreaState = { key, name: area.name, type: area.type, config: area.config ?? {}, metadata: area.metadata ?? {} };
|
||||
|
||||
const display = createAreaDisplay(state, true);
|
||||
|
||||
const editorMsg = await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [
|
||||
display,
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
{ type: 2, style: ButtonStyle.Primary, label: 'Base', custom_id: 'ga_base' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Config (JSON)', custom_id: 'ga_config' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Meta (JSON)', custom_id: 'ga_meta' },
|
||||
{ type: 2, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'ga_save' },
|
||||
{ type: 2, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'ga_cancel' },
|
||||
]
|
||||
}
|
||||
]
|
||||
components: buildEditorComponents(state, true),
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
|
||||
const collector = editorMsg.createMessageComponentCollector({ time: 30*60_000, filter: (i)=> i.user.id === message.author.id });
|
||||
@@ -169,18 +149,16 @@ export const command: CommandMessage = {
|
||||
case 'ga_cancel':
|
||||
await i.deferUpdate();
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '**❌ Editor de Área cancelado.**'
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
collector.stop('cancel');
|
||||
return;
|
||||
@@ -198,18 +176,16 @@ export const command: CommandMessage = {
|
||||
await prisma.gameArea.update({ where: { id: area.id }, data: { name: state.name!, type: state.type!, config: state.config ?? {}, metadata: state.metadata ?? {} } });
|
||||
await i.reply({ content: '✅ Área actualizada.', flags: MessageFlags.Ephemeral });
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0x00FF00,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**✅ Área \`${state.key}\` actualizada exitosamente.**`
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
collector.stop('saved');
|
||||
return;
|
||||
@@ -223,18 +199,16 @@ export const command: CommandMessage = {
|
||||
if (r==='time') {
|
||||
try {
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFFA500,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '**⏰ Editor expirado.**'
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
@@ -255,22 +229,10 @@ async function showBaseModal(i: ButtonInteraction, state: AreaState, editorMsg:
|
||||
await sub.reply({ content: '✅ Base actualizada.', flags: MessageFlags.Ephemeral });
|
||||
|
||||
// Actualizar display
|
||||
const newDisplay = createAreaDisplay(state, editing);
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [
|
||||
newDisplay,
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
{ type: 2, style: ButtonStyle.Primary, label: 'Base', custom_id: 'ga_base' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Config (JSON)', custom_id: 'ga_config' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Meta (JSON)', custom_id: 'ga_meta' },
|
||||
{ type: 2, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'ga_save' },
|
||||
{ type: 2, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'ga_cancel' },
|
||||
]
|
||||
}
|
||||
]
|
||||
components: buildEditorComponents(state, editing)
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
@@ -298,22 +260,10 @@ async function showJsonModal(i: ButtonInteraction, state: AreaState, field: 'con
|
||||
}
|
||||
|
||||
// Actualizar display
|
||||
const newDisplay = createAreaDisplay(state, editing);
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [
|
||||
newDisplay,
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
{ type: 2, style: ButtonStyle.Primary, label: 'Base', custom_id: 'ga_base' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Config (JSON)', custom_id: 'ga_config' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Meta (JSON)', custom_id: 'ga_meta' },
|
||||
{ type: 2, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'ga_save' },
|
||||
{ type: 2, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'ga_cancel' },
|
||||
]
|
||||
}
|
||||
]
|
||||
components: buildEditorComponents(state, editing)
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
@@ -30,24 +30,17 @@ export const command: CommandMessage = {
|
||||
const allowed = await hasManageGuildOrStaff(message.member, message.guild!.id, client.prisma);
|
||||
if (!allowed) {
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '❌ **Error de Permisos**\n└ No tienes permisos de ManageGuild ni rol de staff.'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -55,24 +48,17 @@ export const command: CommandMessage = {
|
||||
const key = args[0]?.trim();
|
||||
if (!key) {
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFFA500,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '⚠️ **Uso Incorrecto**\n└ Uso: `!item-editar <key-única>`'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -82,24 +68,17 @@ export const command: CommandMessage = {
|
||||
const existing = await client.prisma.economyItem.findFirst({ where: { key, guildId } });
|
||||
if (!existing) {
|
||||
await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '❌ **Item No Encontrado**\n└ No existe un item con esa key en este servidor.'
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
message_reference: {
|
||||
message_id: message.id,
|
||||
channel_id: message.channel.id,
|
||||
guild_id: message.guild!.id,
|
||||
fail_if_not_exists: false
|
||||
}
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -116,64 +95,65 @@ export const command: CommandMessage = {
|
||||
props: existing.props || {},
|
||||
};
|
||||
|
||||
// Función para crear display
|
||||
const createDisplay = () => ({
|
||||
display: {
|
||||
const buildEditorDisplay = () => {
|
||||
const baseInfo = [
|
||||
`**Nombre:** ${state.name || '*Sin definir*'}`,
|
||||
`**Descripción:** ${state.description || '*Sin definir*'}`,
|
||||
`**Categoría:** ${state.category || '*Sin definir*'}`,
|
||||
`**Icon URL:** ${state.icon || '*Sin definir*'}`,
|
||||
`**Stackable:** ${state.stackable ? 'Sí' : 'No'}`,
|
||||
`**Máx. Inventario:** ${state.maxPerInventory ?? 'Ilimitado'}`,
|
||||
].join('\n');
|
||||
|
||||
const tagsInfo = `**Tags:** ${state.tags.length > 0 ? state.tags.join(', ') : '*Ninguno*'}`;
|
||||
const propsJson = JSON.stringify(state.props ?? {}, null, 2);
|
||||
|
||||
return {
|
||||
type: 17,
|
||||
accent_color: 0x00D9FF,
|
||||
components: [
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**🛠️ Editando Item: \`${key}\`**`
|
||||
}]
|
||||
content: `# 🛠️ Editando Item: \`${key}\``
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**Nombre:** ${state.name || '*Sin definir*'}\n` +
|
||||
`**Descripción:** ${state.description || '*Sin definir*'}\n` +
|
||||
`**Categoría:** ${state.category || '*Sin definir*'}\n` +
|
||||
`**Icon URL:** ${state.icon || '*Sin definir*'}\n` +
|
||||
`**Stackable:** ${state.stackable ? 'Sí' : 'No'}\n` +
|
||||
`**Máx. Inventario:** ${state.maxPerInventory || 'Ilimitado'}`
|
||||
}]
|
||||
content: baseInfo
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**Tags:** ${state.tags.length > 0 ? state.tags.join(', ') : '*Ninguno*'}`
|
||||
}]
|
||||
content: tagsInfo
|
||||
},
|
||||
{ type: 14, divider: true },
|
||||
{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `**Props (JSON):**\n\`\`\`json\n${JSON.stringify(state.props, null, 2)}\n\`\`\``
|
||||
}]
|
||||
content: `**Props (JSON):**\n\`\`\`json\n${propsJson}\n\`\`\``
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const editorMsg = await (channel.send as any)({
|
||||
flags: 32768,
|
||||
const buildEditorComponents = () => [
|
||||
buildEditorDisplay(),
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
createDisplay().display,
|
||||
{ type: 1, components: [
|
||||
{ type: 2, style: ButtonStyle.Primary, label: 'Base', custom_id: 'it_base' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Tags', custom_id: 'it_tags' },
|
||||
{ type: 2, style: ButtonStyle.Secondary, label: 'Props (JSON)', custom_id: 'it_props' },
|
||||
{ type: 2, style: ButtonStyle.Success, label: 'Guardar', custom_id: 'it_save' },
|
||||
{ type: 2, style: ButtonStyle.Danger, label: 'Cancelar', custom_id: 'it_cancel' },
|
||||
]},
|
||||
],
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const editorMsg = await (channel.send as any)({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: buildEditorComponents(),
|
||||
reply: { messageReference: message.id }
|
||||
});
|
||||
|
||||
const collector = editorMsg.createMessageComponentCollector({ time: 30 * 60_000, filter: (i) => i.user.id === message.author.id });
|
||||
@@ -184,32 +164,30 @@ export const command: CommandMessage = {
|
||||
if (i.customId === 'it_cancel') {
|
||||
await i.deferUpdate();
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFF0000,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '**❌ Editor cancelado.**'
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
collector.stop('cancel');
|
||||
return;
|
||||
}
|
||||
if (i.customId === 'it_base') {
|
||||
await showBaseModal(i as ButtonInteraction, state, editorMsg, createDisplay);
|
||||
await showBaseModal(i as ButtonInteraction, state, editorMsg, buildEditorComponents);
|
||||
return;
|
||||
}
|
||||
if (i.customId === 'it_tags') {
|
||||
await showTagsModal(i as ButtonInteraction, state, editorMsg, createDisplay);
|
||||
await showTagsModal(i as ButtonInteraction, state, editorMsg, buildEditorComponents);
|
||||
return;
|
||||
}
|
||||
if (i.customId === 'it_props') {
|
||||
await showPropsModal(i as ButtonInteraction, state, editorMsg, createDisplay);
|
||||
await showPropsModal(i as ButtonInteraction, state, editorMsg, buildEditorComponents);
|
||||
return;
|
||||
}
|
||||
if (i.customId === 'it_save') {
|
||||
@@ -234,18 +212,16 @@ export const command: CommandMessage = {
|
||||
});
|
||||
await i.reply({ content: '✅ Item actualizado!', flags: MessageFlags.Ephemeral });
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0x00FF00,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: `✅ **Item Actualizado**\n└ Item \`${state.key}\` actualizado exitosamente.`
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
collector.stop('saved');
|
||||
return;
|
||||
@@ -259,25 +235,23 @@ export const command: CommandMessage = {
|
||||
collector.on('end', async (_c, r) => {
|
||||
if (r === 'time') {
|
||||
try { await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [{
|
||||
type: 17,
|
||||
accent_color: 0xFFA500,
|
||||
components: [{
|
||||
type: 9,
|
||||
components: [{
|
||||
type: 10,
|
||||
content: '**⏰ Editor expirado.**'
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}); } catch {}
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
async function showBaseModal(i: ButtonInteraction, state: ItemEditorState, editorMsg: any, createDisplay: Function) {
|
||||
async function showBaseModal(i: ButtonInteraction, state: ItemEditorState, editorMsg: any, buildComponents: () => any[]) {
|
||||
const modal = {
|
||||
title: 'Configuración base del Item',
|
||||
customId: 'it_base_modal',
|
||||
@@ -313,13 +287,14 @@ async function showBaseModal(i: ButtonInteraction, state: ItemEditorState, edito
|
||||
|
||||
await sub.deferUpdate();
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [createDisplay().display]
|
||||
components: buildComponents()
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function showTagsModal(i: ButtonInteraction, state: ItemEditorState, editorMsg: any, createDisplay: Function) {
|
||||
async function showTagsModal(i: ButtonInteraction, state: ItemEditorState, editorMsg: any, buildComponents: () => any[]) {
|
||||
const modal = {
|
||||
title: 'Tags del Item (separados por coma)',
|
||||
customId: 'it_tags_modal',
|
||||
@@ -334,13 +309,14 @@ async function showTagsModal(i: ButtonInteraction, state: ItemEditorState, edito
|
||||
state.tags = tags ? tags.split(',').map((t) => t.trim()).filter(Boolean) : [];
|
||||
await sub.deferUpdate();
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [createDisplay().display]
|
||||
components: buildComponents()
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function showPropsModal(i: ButtonInteraction, state: ItemEditorState, editorMsg: any, createDisplay: Function) {
|
||||
async function showPropsModal(i: ButtonInteraction, state: ItemEditorState, editorMsg: any, buildComponents: () => any[]) {
|
||||
const template = state.props && Object.keys(state.props).length ? JSON.stringify(state.props) : JSON.stringify({
|
||||
tool: undefined,
|
||||
breakable: undefined,
|
||||
@@ -371,8 +347,9 @@ async function showPropsModal(i: ButtonInteraction, state: ItemEditorState, edit
|
||||
state.props = parsed;
|
||||
await sub.deferUpdate();
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: [createDisplay().display]
|
||||
components: buildComponents()
|
||||
});
|
||||
} catch (e) {
|
||||
await sub.reply({ content: '❌ JSON inválido.', flags: MessageFlags.Ephemeral });
|
||||
@@ -380,6 +357,13 @@ async function showPropsModal(i: ButtonInteraction, state: ItemEditorState, edit
|
||||
} else {
|
||||
state.props = {};
|
||||
await sub.reply({ content: 'ℹ️ Props limpiados.', flags: MessageFlags.Ephemeral });
|
||||
try {
|
||||
await editorMsg.edit({
|
||||
content: null,
|
||||
flags: 32768,
|
||||
components: buildComponents()
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user