diff --git a/src/commands/information/roles.ts b/src/commands/information/roles.ts index 71d59ad0..a33b980d 100644 --- a/src/commands/information/roles.ts +++ b/src/commands/information/roles.ts @@ -3,6 +3,14 @@ import { CommandContext } from '../../structures/addons/CommandAddons'; import { Command } from '../../structures/Command'; import { getRoleListEmbed } from '../../handlers/locale'; +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + ComponentType, + EmbedBuilder +} from 'discord.js'; + class RolesCommand extends Command { constructor() { super({ @@ -15,8 +23,63 @@ class RolesCommand extends Command { async run(ctx: CommandContext) { const roles = await robloxGroup.getRoles(); - return ctx.reply({ embeds: [ getRoleListEmbed(roles) ] }); + const embeds = getRoleListEmbed(roles); + + // Set page + embeds.forEach((embed, index) => { + embed.setFooter({ text: `Page ${index + 1} of ${embeds.length}` }); + }); + + let currentPage = 0; + + const getButtons = () => + new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId('prev') + .setLabel('◀') + .setStyle(ButtonStyle.Secondary) + .setDisabled(currentPage === 0), + new ButtonBuilder() + .setCustomId('next') + .setLabel('▶') + .setStyle(ButtonStyle.Secondary) + .setDisabled(currentPage === embeds.length - 1) + ); + + const message = await ctx.reply({ + embeds: [embeds[currentPage]], + components: embeds.length > 1 ? [getButtons()] : [] + }); + + if (embeds.length <= 1) return; + + const collector = message.createMessageComponentCollector({ + componentType: ComponentType.Button, + time: 120000 // Active for 2 minutes + }); + + collector.on('collect', async interaction => { + if (interaction.user.id !== ctx.user.id) { + void interaction.reply({ + content: 'Only the command creator can scroll.', + ephemeral: true + }); + return; + } + + if (interaction.customId === 'next' && currentPage < embeds.length - 1) currentPage++; + else if (interaction.customId === 'prev' && currentPage > 0) currentPage--; + + await interaction.update({ + embeds: [embeds[currentPage]], + components: [getButtons()] + }); + }); + + collector.on('end', () => { + message.edit({ components: [] }).catch(() => null); + }); } } -export default RolesCommand; \ No newline at end of file +export default RolesCommand; diff --git a/src/commands/information/session.ts b/src/commands/information/session.ts new file mode 100644 index 00000000..8e313f1e --- /dev/null +++ b/src/commands/information/session.ts @@ -0,0 +1,64 @@ +import { CommandContext } from '../../structures/addons/CommandAddons'; +import { Command } from '../../structures/Command'; +import { discordClient, robloxGroup } from '../../main'; +import { checkIconUrl, quoteIconUrl, mainColor } from '../../handlers/locale'; +import { config } from '../../config'; +import { TextChannel } from 'discord.js'; + +class SessionCommand extends Command { + constructor() { + super({ + trigger: 'session', + description: 'Announces a session in both this server and the group.', + type: 'ChatInput', + module: 'sessions', + permissions: [ + { + type: 'role', + ids: config.permissions.users, + value: true, + } + ], + args: [], + }); + } + + async run(ctx: CommandContext) { + // Sending message to the specific Discord channel + const channel = await discordClient.channels.fetch('[CHANNEL ID GOES HERE]') as TextChannel; + channel.send({ + embeds: [ + { + author: { + name: 'Shift Announcement', + icon_url: quoteIconUrl, + }, + description: 'Discord text here', + color: parseInt(mainColor.substring(1), 16), + } + ], + allowedMentions: { + parse: ['roles'] + } + }); + + // Updating the Roblox group shout + robloxGroup.updateShout('Roblox shout text here'); + + // Sending a confirmation message back to the user + return ctx.reply({ + embeds: [ + { + author: { + name: 'Success!', + icon_url: checkIconUrl, + }, + description: 'This has been posted as a group shout and a message in the shift announcements ( <#CHANNEL ID GOES HERE> ) channel.', + color: parseInt(checkIconUrl.substring(1), 16), + } + ] + }); + } +} + +export default SessionCommand; diff --git a/src/commands/information/uptime.ts b/src/commands/information/uptime.ts new file mode 100644 index 00000000..9ba9d21d --- /dev/null +++ b/src/commands/information/uptime.ts @@ -0,0 +1,68 @@ +import { CommandContext } from '../../structures/addons/CommandAddons'; +import { Command } from '../../structures/Command'; +import { discordClient } from '../../main'; + +import { mainColor, infoIconUrl } from '../../handlers/locale'; +import { EmbedBuilder } from 'discord.js'; // Geändert von MessageEmbed zu EmbedBuilder + +class UptimeCommand extends Command { + constructor() { + super({ + trigger: "uptime", + description: "Gets the uptime of the bot", + type: "ChatInput", + module: "information", + }); + } + + convertMilliseconds(milliseconds) { + let days = 0; + let hours = 0; + let minutes = 0; + let seconds = 0; + + while(milliseconds >= 86400000) { + days++; + milliseconds -= 86400000; + } + + while(milliseconds >= 3600000) { + hours++; + milliseconds -= 3600000; + } + + while(milliseconds >= 60000) { + minutes++; + milliseconds -= 60000; + } + + while(milliseconds >= 1000) { + seconds++; + milliseconds -= 1000; + } + + return { + days: days, + hours: hours, + minutes: minutes, + seconds: seconds, + milliseconds: milliseconds + } + } + + async run(ctx: CommandContext) { + let data = this.convertMilliseconds(discordClient.uptime); + let uptime = `The bot has been running for ${data.days} days, ${data.hours} hours, ${data.minutes} minutes, ${data.seconds} seconds, and ${data.milliseconds} milliseconds`; + + let embed = new EmbedBuilder(); // Geändert von MessageEmbed zu EmbedBuilder + embed.setAuthor({ name: "Uptime", iconURL: infoIconUrl }); // setAuthor benötigt jetzt ein Objekt + embed.setColor(mainColor); + embed.setDescription(uptime); + + ctx.reply({ + embeds: [embed] + }) + } +} + +export default UptimeCommand; diff --git a/src/handlers/locale.ts b/src/handlers/locale.ts index d9b73028..02b17876 100644 --- a/src/handlers/locale.ts +++ b/src/handlers/locale.ts @@ -504,22 +504,31 @@ export const getUserInfoEmbed = async (user: User | PartialUser, member: GroupMe return embed; } -export const getRoleListEmbed = (roles: GroupRole[]): EmbedBuilder => { - const embed = new EmbedBuilder() - .setAuthor({ name: 'Group Roles', iconURL: infoIconUrl }) - .setColor(mainColor) - .setDescription('Here is a list of all roles on the group.'); +export const getRoleListEmbed = (roles: GroupRole[]): EmbedBuilder[] => { + const embeds: EmbedBuilder[] = []; - roles.forEach((role) => { - embed.addFields({ - name: role.name, - value: `Rank: \`${role.rank || '0'}\``, - inline: true + for (let i = 0; i < roles.length; i += 25) { + const chunk = roles.slice(i, i + 25); + + const embed = new EmbedBuilder() + .setAuthor({ name: 'Group Roles', iconURL: infoIconUrl }) + .setColor(mainColor) + .setDescription('Here is a list of all roles on the group.'); + + chunk.forEach((role) => { + embed.addFields({ + name: role.name, + value: `Rank: \`${role.rank || '0'}\``, + inline: true + }); }); - }); - return embed; -} + embeds.push(embed); + } + + return embeds; +}; + export const getNotSuspendedEmbed = (): EmbedBuilder => { const embed = new EmbedBuilder() @@ -620,4 +629,4 @@ export const getSuccessfulGroupUnbanEmbed = (user: User | PartialUser) : EmbedBu .setDescription(`**${user.name}** has successfully been unbanned from the group.`); return embed; -} \ No newline at end of file +}