Refactor el comando 'items-lista' para mejorar la gestión de paginación y la estructura del mensaje, añadiendo botones de navegación y optimizando la construcción del payload.
This commit is contained in:
@@ -1,130 +1,146 @@
|
|||||||
import type { CommandMessage } from '../../../core/types/commands';
|
import type { CommandMessage } from "../../../core/types/commands";
|
||||||
import type Amayo from '../../../core/client';
|
import type Amayo from "../../../core/client";
|
||||||
import { prisma } from '../../../core/database/prisma';
|
import { prisma } from "../../../core/database/prisma";
|
||||||
import { ComponentType, ButtonStyle } from 'discord-api-types/v10';
|
import { ComponentType, ButtonStyle } from "discord-api-types/v10";
|
||||||
import type { MessageComponentInteraction, TextBasedChannel } from 'discord.js';
|
import type { MessageComponentInteraction, TextBasedChannel } from "discord.js";
|
||||||
import { buildDisplay, dividerBlock, textBlock } from '../../../core/lib/componentsV2';
|
import {
|
||||||
|
buildDisplay,
|
||||||
|
dividerBlock,
|
||||||
|
textBlock,
|
||||||
|
} from "../../../core/lib/componentsV2";
|
||||||
|
|
||||||
export const command: CommandMessage = {
|
export const command: CommandMessage = {
|
||||||
name: 'items-lista',
|
name: "items-lista",
|
||||||
type: 'message',
|
type: "message",
|
||||||
aliases: ['lista-items', 'items-list'],
|
aliases: ["lista-items", "items-list"],
|
||||||
cooldown: 5,
|
cooldown: 5,
|
||||||
description: 'Ver lista de todos los items del servidor',
|
description: "Ver lista de todos los items del servidor",
|
||||||
usage: 'items-lista [pagina]',
|
usage: "items-lista [pagina]",
|
||||||
run: async (message, args, client: Amayo) => {
|
run: async (message, args, client: Amayo) => {
|
||||||
const guildId = message.guild!.id;
|
const guildId = message.guild!.id;
|
||||||
const page = parseInt(args[0]) || 1;
|
|
||||||
const perPage = 8;
|
const perPage = 8;
|
||||||
|
|
||||||
const total = await prisma.economyItem.count({
|
async function buildPayload(page: number) {
|
||||||
where: { OR: [{ guildId }, { guildId: null }] }
|
const total = await prisma.economyItem.count({
|
||||||
});
|
where: { OR: [{ guildId }, { guildId: null }] },
|
||||||
|
});
|
||||||
|
const items = await prisma.economyItem.findMany({
|
||||||
|
where: { OR: [{ guildId }, { guildId: null }] },
|
||||||
|
orderBy: [{ category: "asc" }, { name: "asc" }],
|
||||||
|
skip: (page - 1) * perPage,
|
||||||
|
take: perPage,
|
||||||
|
});
|
||||||
|
|
||||||
const items = await prisma.economyItem.findMany({
|
const totalPages = Math.max(1, Math.ceil(total / perPage));
|
||||||
where: { OR: [{ guildId }, { guildId: null }] },
|
|
||||||
orderBy: [{ category: 'asc' }, { name: 'asc' }],
|
|
||||||
skip: (page - 1) * perPage,
|
|
||||||
take: perPage
|
|
||||||
});
|
|
||||||
|
|
||||||
if (items.length === 0) {
|
const displayBlocks = [
|
||||||
await message.reply('No hay items configurados en este servidor.');
|
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[] = [];
|
||||||
|
if (page > 1) {
|
||||||
|
buttons.push({
|
||||||
|
type: ComponentType.Button,
|
||||||
|
style: ButtonStyle.Secondary,
|
||||||
|
label: "◀ Anterior",
|
||||||
|
custom_id: `items_prev_${page}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (page < totalPages) {
|
||||||
|
buttons.push({
|
||||||
|
type: ComponentType.Button,
|
||||||
|
style: ButtonStyle.Secondary,
|
||||||
|
label: "Siguiente ▶",
|
||||||
|
custom_id: `items_next_${page}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
buttons.push({
|
||||||
|
type: ComponentType.Button,
|
||||||
|
style: ButtonStyle.Primary,
|
||||||
|
label: "Ver Detalle",
|
||||||
|
custom_id: "items_detail",
|
||||||
|
});
|
||||||
|
|
||||||
|
const components: any[] = [display];
|
||||||
|
if (buttons.length > 0)
|
||||||
|
components.push({ type: ComponentType.ActionRow, components: buttons });
|
||||||
|
return { components, total, totalPages };
|
||||||
|
}
|
||||||
|
|
||||||
|
const page = parseInt(args[0]) || 1;
|
||||||
|
const channel = message.channel as TextBasedChannel & { send: Function };
|
||||||
|
const initial = await buildPayload(page);
|
||||||
|
if (initial.total === 0) {
|
||||||
|
await message.reply("No hay items configurados en este servidor.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalPages = Math.ceil(total / perPage);
|
|
||||||
|
|
||||||
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[] = [];
|
|
||||||
|
|
||||||
if (page > 1) {
|
|
||||||
buttons.push({
|
|
||||||
type: ComponentType.Button,
|
|
||||||
style: ButtonStyle.Secondary,
|
|
||||||
label: '◀ Anterior',
|
|
||||||
custom_id: `items_prev_${page}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (page < totalPages) {
|
|
||||||
buttons.push({
|
|
||||||
type: ComponentType.Button,
|
|
||||||
style: ButtonStyle.Secondary,
|
|
||||||
label: 'Siguiente ▶',
|
|
||||||
custom_id: `items_next_${page}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
buttons.push({
|
|
||||||
type: ComponentType.Button,
|
|
||||||
style: ButtonStyle.Primary,
|
|
||||||
label: 'Ver Detalle',
|
|
||||||
custom_id: 'items_detail'
|
|
||||||
});
|
|
||||||
|
|
||||||
const channel = message.channel as TextBasedChannel & { send: Function };
|
|
||||||
const msg = await (channel.send as any)({
|
const msg = await (channel.send as any)({
|
||||||
content: null,
|
content: null,
|
||||||
flags: 32768,
|
flags: 32768,
|
||||||
reply: { messageReference: message.id },
|
reply: { messageReference: message.id },
|
||||||
components: [
|
components: initial.components,
|
||||||
display,
|
|
||||||
...(buttons.length > 0 ? [{
|
|
||||||
type: ComponentType.ActionRow,
|
|
||||||
components: buttons
|
|
||||||
}] : [])
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const collector = msg.createMessageComponentCollector({
|
let collector = msg.createMessageComponentCollector({
|
||||||
time: 5 * 60_000,
|
time: 5 * 60_000,
|
||||||
filter: (i) => i.user.id === message.author.id
|
filter: (i) => i.user.id === message.author.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
collector.on('collect', async (i: MessageComponentInteraction) => {
|
collector.on("collect", async (i: MessageComponentInteraction) => {
|
||||||
if (!i.isButton()) return;
|
if (!i.isButton()) return;
|
||||||
|
|
||||||
if (i.customId.startsWith('items_prev_')) {
|
if (
|
||||||
const currentPage = parseInt(i.customId.split('_')[2]);
|
i.customId.startsWith("items_prev_") ||
|
||||||
|
i.customId.startsWith("items_next_")
|
||||||
|
) {
|
||||||
|
const parts = i.customId.split("_");
|
||||||
|
const currentPage = parseInt(parts[2]);
|
||||||
|
const newPage = i.customId.startsWith("items_prev_")
|
||||||
|
? currentPage - 1
|
||||||
|
: currentPage + 1;
|
||||||
await i.deferUpdate();
|
await i.deferUpdate();
|
||||||
args[0] = String(currentPage - 1);
|
// rebuild payload and edit message
|
||||||
await command.run!(message, args, client);
|
try {
|
||||||
collector.stop();
|
const p = await buildPayload(newPage);
|
||||||
} else if (i.customId.startsWith('items_next_')) {
|
await msg.edit({ content: null, components: p.components });
|
||||||
const currentPage = parseInt(i.customId.split('_')[2]);
|
} catch (e) {
|
||||||
await i.deferUpdate();
|
await i.followUp({
|
||||||
args[0] = String(currentPage + 1);
|
content: `❌ Error actualizando página: ${(e as any).message || e}`,
|
||||||
await command.run!(message, args, client);
|
flags: 64,
|
||||||
collector.stop();
|
});
|
||||||
} else if (i.customId === 'items_detail') {
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === "items_detail") {
|
||||||
await i.reply({
|
await i.reply({
|
||||||
content: '💡 Usa `!item-ver <key>` para ver detalles de un item específico.',
|
content:
|
||||||
flags: 64
|
"💡 Usa `!item-ver <key>` para ver detalles de un item específico.",
|
||||||
|
flags: 64,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user