mirror of
https://github.com/ahmadk953/poixpixel-discord-bot.git
synced 2025-05-10 02:33:06 +00:00
167 lines
4.8 KiB
TypeScript
167 lines
4.8 KiB
TypeScript
import {
|
|
SlashCommandBuilder,
|
|
EmbedBuilder,
|
|
ActionRowBuilder,
|
|
StringSelectMenuBuilder,
|
|
APIEmbed,
|
|
JSONEncodable,
|
|
} from 'discord.js';
|
|
|
|
import { OptionsCommand } from '@/types/CommandTypes.js';
|
|
import { getLevelLeaderboard } from '@/db/db.js';
|
|
import { createPaginationButtons } from '@/util/helpers.js';
|
|
|
|
const command: OptionsCommand = {
|
|
data: new SlashCommandBuilder()
|
|
.setName('leaderboard')
|
|
.setDescription('Shows the server XP leaderboard')
|
|
.addIntegerOption((option) =>
|
|
option
|
|
.setName('limit')
|
|
.setDescription('Number of users per page (default: 10)')
|
|
.setRequired(false),
|
|
),
|
|
execute: async (interaction) => {
|
|
if (!interaction.isChatInputCommand() || !interaction.guild) return;
|
|
|
|
await interaction.deferReply();
|
|
|
|
try {
|
|
const usersPerPage = interaction.options.getInteger('limit') || 10;
|
|
|
|
const allUsers = await getLevelLeaderboard(100);
|
|
|
|
if (allUsers.length === 0) {
|
|
const embed = new EmbedBuilder()
|
|
.setTitle('🏆 Server Leaderboard')
|
|
.setColor(0x5865f2)
|
|
.setDescription('No users found on the leaderboard yet.')
|
|
.setTimestamp();
|
|
|
|
await interaction.editReply({ embeds: [embed] });
|
|
}
|
|
|
|
const pages: (APIEmbed | JSONEncodable<APIEmbed>)[] = [];
|
|
|
|
for (let i = 0; i < allUsers.length; i += usersPerPage) {
|
|
const pageUsers = allUsers.slice(i, i + usersPerPage);
|
|
let leaderboardText = '';
|
|
|
|
for (let j = 0; j < pageUsers.length; j++) {
|
|
const user = pageUsers[j];
|
|
const position = i + j + 1;
|
|
|
|
try {
|
|
const member = await interaction.guild.members.fetch(
|
|
user.discordId,
|
|
);
|
|
leaderboardText += `**${position}.** ${member} - Level ${user.level} (${user.xp} XP)\n`;
|
|
} catch (error) {
|
|
leaderboardText += `**${position}.** <@${user.discordId}> - Level ${user.level} (${user.xp} XP)\n`;
|
|
}
|
|
}
|
|
|
|
const embed = new EmbedBuilder()
|
|
.setTitle('🏆 Server Leaderboard')
|
|
.setColor(0x5865f2)
|
|
.setDescription(leaderboardText)
|
|
.setTimestamp()
|
|
.setFooter({
|
|
text: `Page ${Math.floor(i / usersPerPage) + 1} of ${Math.ceil(allUsers.length / usersPerPage)}`,
|
|
});
|
|
|
|
pages.push(embed);
|
|
}
|
|
|
|
let currentPage = 0;
|
|
|
|
const getButtonActionRow = () =>
|
|
createPaginationButtons(pages.length, currentPage);
|
|
|
|
const getSelectMenuRow = () => {
|
|
const options = pages.map((_, index) => ({
|
|
label: `Page ${index + 1}`,
|
|
value: index.toString(),
|
|
default: index === currentPage,
|
|
}));
|
|
|
|
const select = new StringSelectMenuBuilder()
|
|
.setCustomId('select_page')
|
|
.setPlaceholder('Jump to a page')
|
|
.addOptions(options);
|
|
|
|
return new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
|
|
select,
|
|
);
|
|
};
|
|
|
|
const components =
|
|
pages.length > 1 ? [getButtonActionRow(), getSelectMenuRow()] : [];
|
|
|
|
const message = await interaction.editReply({
|
|
embeds: [pages[currentPage]],
|
|
components,
|
|
});
|
|
|
|
if (pages.length <= 1) return;
|
|
|
|
const collector = message.createMessageComponentCollector({
|
|
time: 300000,
|
|
});
|
|
|
|
collector.on('collect', async (i) => {
|
|
if (i.user.id !== interaction.user.id) {
|
|
await i.reply({
|
|
content: 'These controls are not for you!',
|
|
flags: ['Ephemeral'],
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (i.isButton()) {
|
|
switch (i.customId) {
|
|
case 'first':
|
|
currentPage = 0;
|
|
break;
|
|
case 'prev':
|
|
if (currentPage > 0) currentPage--;
|
|
break;
|
|
case 'next':
|
|
if (currentPage < pages.length - 1) currentPage++;
|
|
break;
|
|
case 'last':
|
|
currentPage = pages.length - 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i.isStringSelectMenu()) {
|
|
const selected = parseInt(i.values[0]);
|
|
if (!isNaN(selected) && selected >= 0 && selected < pages.length) {
|
|
currentPage = selected;
|
|
}
|
|
}
|
|
|
|
await i.update({
|
|
embeds: [pages[currentPage]],
|
|
components: [getButtonActionRow(), getSelectMenuRow()],
|
|
});
|
|
});
|
|
|
|
collector.on('end', async () => {
|
|
if (message) {
|
|
try {
|
|
await interaction.editReply({ components: [] });
|
|
} catch (error) {
|
|
console.error('Error removing components:', error);
|
|
}
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Error getting leaderboard:', error);
|
|
await interaction.editReply('Failed to get leaderboard information.');
|
|
}
|
|
},
|
|
};
|
|
|
|
export default command;
|