diff --git a/src/commands/user/about.ts b/src/commands/user/about.ts index d62a426..f94fb24 100644 --- a/src/commands/user/about.ts +++ b/src/commands/user/about.ts @@ -2,12 +2,13 @@ import { LoadingEmbed } from "./../../utils/defaultEmbeds.js"; import Discord, { CommandInteraction, GuildMember, - Message, ActionRowBuilder, - Component, ButtonBuilder, MessageComponentInteraction, - ButtonStyle + ButtonStyle, + PermissionResolvable, + APISelectMenuOption, + StringSelectMenuBuilder } from "discord.js"; import type { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import EmojiEmbed from "../../utils/generateEmojiEmbed.js"; @@ -25,11 +26,12 @@ const command = (builder: SlashCommandSubcommandBuilder) => ); class Embed { - embed: Discord.EmbedBuilder; - title: string; + embed: EmojiEmbed = new EmojiEmbed(); + title: string = ""; description = ""; pageId = 0; - setEmbed(embed: Discord.EmbedBuilder) { + + setEmbed(embed: EmojiEmbed) { this.embed = embed; return this; } @@ -48,9 +50,20 @@ class Embed { } const callback = async (interaction: CommandInteraction): Promise => { - if (!interaction.guild) return; - const { renderUser, renderDelta } = client.logger; + const guild = interaction.guild!; const member = (interaction.options.getMember("user") ?? interaction.member) as Discord.GuildMember; + await userAbout(guild, member, interaction); +} + +async function userAbout(guild: Discord.Guild, member: Discord.GuildMember, interaction: Discord.CommandInteraction | Discord.ContextMenuCommandInteraction) { + await member.user.fetch() + await member.fetch() + await interaction.reply({ + embeds: LoadingEmbed, + fetchReply: true, + ephemeral: true + }); + const { renderUser, renderDelta } = client.logger; const flags: string[] = []; if ( [ @@ -70,33 +83,32 @@ const callback = async (interaction: CommandInteraction): Promise => { ) { flags.push("CLICKSDEVELOPER"); } - member.user.flags.toArray().map((flag) => { - flags.push(flag.toString()); - }); - if (member.user.bot) { - flags.push("BOT"); - } + if (member.user.flags) { member.user.flags.toArray().map((flag) => { flags.push(flag.toString()); }); } + if (member.user.bot) { flags.push("BOT"); } // Check if they are boosting the server - if (member.premiumSince) { - flags.push("BOOSTER"); - } - const nameReplacements = { + if (member.premiumSince) { flags.push("BOOSTER"); } + const nameReplacements: Record = { NUCLEUSDEVELOPER: "**Nucleus Developer**", CLICKSDEVELOPER: "Clicks Developer", - HOUSE_BRAVERY: "Hypesquad Bravery", - HOUSE_BRILLIANCE: "Hypesquad Brilliance", - HOUSE_BALANCE: "Hypesquad Balance", - HYPESQUAD_EVENTS: "Hypesquad Events", - EARLY_SUPPORTER: "Early Supporter", - BUGHUNTER_LEVEL_1: "Bug Hunter Level 1", - BUGHUNTER_LEVEL_2: "Bug Hunter Level 2", - PARTNERED_SERVER_OWNER: "Partnered Server Owner", - DISCORD_EMPLOYEE: "Discord Staff", - EARLY_VERIFIED_BOT_DEVELOPER: "Verified Bot Developer", BOT: "Bot", - BOOSTER: "Server Booster" + BOOSTER: "Server Booster", + HypeSquadOnlineHouse1: "Hypesquad Bravery", + HypeSquadOnlineHouse2: "Hypesquad Brilliance", + HypeSquadOnlineHouse3: "Hypesquad Balance", + Hypesquad: "Hypesquad Events", + PremiumEarlySupporter: "Early Supporter", + BugHunterLevel1: "Bug Hunter Level 1", + BugHunterLevel2: "Bug Hunter Level 2", + Partner: "Partnered Server Owner", + Staff: "Discord Staff", + VerifiedDeveloper: "Verified Bot Developer" + // ActiveDeveloper + // CertifiedModerator + // Quarantined https://discord-api-types.dev/api/discord-api-types-v10/enum/UserFlags#Quarantined + // Spammer https://discord-api-types.dev/api/discord-api-types-v10/enum/UserFlags#Spammer + // VerifiedBot }; - const members = await interaction.guild.members.fetch(); + const members = await guild.members.fetch(); const membersArray = [...members.values()]; membersArray.sort((a, b) => { if (a.joinedTimestamp === null) return 1; @@ -105,7 +117,7 @@ const callback = async (interaction: CommandInteraction): Promise => { }); const joinPos = membersArray.findIndex((m) => m.id === member.user.id); - const roles = member.roles.cache.filter((r) => r.id !== interaction.guild!.id).sort(); + const roles = member.roles.cache.filter((r) => r.id !== guild.id).sort(); let s = ""; let count = 0; let ended = false; @@ -122,22 +134,22 @@ const callback = async (interaction: CommandInteraction): Promise => { if (s.length > 0 && !ended) s = s.slice(0, -2); let perms = ""; - const permsArray = { - ADMINISTRATOR: "Administrator", - MANAGE_GUILD: "Manage Server", - MANAGE_ROLES: "Manage Roles", - MANAGE_CHANNELS: "Manage Channels", - KICK_MEMBERS: "Kick Members", - BAN_MEMBERS: "Ban Members", - MODERATE_MEMBERS: "Moderate Members", - MANAGE_NICKNAMES: "Manage Nicknames", - MANAGE_WEBHOOKS: "Manage Webhooks", - MANAGE_MESSAGES: "Manage Messages", - VIEW_AUDIT_LOG: "View Audit Log", - MENTION_EVERYONE: "Mention Everyone" + const permsArray: Record = { + Administrator: "Administrator", + ManageGuild: "Manage Server", + ManageRoles: "Manage Roles", + ManageChannels: "Manage Channels", + KickMembers: "Kick Members", + BanMembers: "Ban Members", + ModerateMembers: "Moderate Members", + ManageNicknames: "Manage Nicknames", + ManageWebhooks: "Manage Webhooks", + ManageMessages: "Manage Messages", + ViewAuditLog: "View Audit Log", + MentionEveryone: "Mention Everyone" }; Object.keys(permsArray).map((perm) => { - const hasPerm = member.permissions.has(perm as Discord.PermissionString); + const hasPerm = member.permissions.has(perm as PermissionResolvable); perms += `${getEmojiByName("CONTROL." + (hasPerm ? "TICK" : "CROSS"))} ${permsArray[perm]}\n`; }); @@ -151,28 +163,26 @@ const callback = async (interaction: CommandInteraction): Promise => { .setStatus("Success") .setEmoji("MEMBER.JOIN") .setDescription( - flags - .map((flag) => { - if (nameReplacements[flag]) { - return getEmojiByName(`BADGES.${flag}`) + " " + nameReplacements[flag]; - } - }) - .join("\n") + - "\n\n" + - generateKeyValueList({ - member: renderUser(member.user), - nickname: member.nickname ?? "*None set*", - id: `\`${member.id}\``, - "joined the server": renderDelta(member.joinedTimestamp), - "joined discord": renderDelta(member.user.createdTimestamp), - "boost status": member.premiumSince - ? `Started boosting ${renderDelta(member.premiumSinceTimestamp)}` - : "*Not boosting*", - "join position": `${joinPos + 1}` - }) + flags.map((flag) => { + if (nameReplacements[flag]) { + const emoji = getEmojiByName(`BADGES.${flag}`) + if (emoji) return (emoji + " " + nameReplacements[flag] + "\n"); + else return nameReplacements[flag] + "\n"; + } + }).join("") + "\n" + + generateKeyValueList({ + member: renderUser(member.user), + nickname: member.nickname ?? "*None set*", + id: `\`${member.id}\``, + "joined the server": renderDelta(member.joinedTimestamp!), + "joined discord": renderDelta(member.user.createdTimestamp), + "boost status": member.premiumSince + ? `Started boosting ${renderDelta(member.premiumSinceTimestamp!)}` + : "*Not boosting*", + "join position": `${joinPos + 1}` + }) ) - .setThumbnail(member.user.displayAvatarURL({ dynamic: true })) - .setImage((await member.user.fetch()).bannerURL({ format: "gif" })) + .setThumbnail(member.user.displayAvatarURL()) ) .setTitle("General") .setDescription("General information about the user") @@ -187,13 +197,12 @@ const callback = async (interaction: CommandInteraction): Promise => { generateKeyValueList({ member: renderUser(member.user), id: `\`${member.id}\``, - roles: `${member.roles.cache.size - 1}` + roles: `${member.roles.cache.size - 1}` // FIXME }) + "\n" + (s.length > 0 ? s : "*None*") + "\n" ) - .setThumbnail(member.user.displayAvatarURL({ dynamic: true })) ) .setTitle("Roles") .setDescription("Roles the user has") @@ -212,26 +221,24 @@ const callback = async (interaction: CommandInteraction): Promise => { "\n" + perms ) - .setThumbnail(member.user.displayAvatarURL({ dynamic: true })) ) .setTitle("Key Permissions") .setDescription("Key permissions the user has") .setPageId(2) ]; - const m = (await interaction.reply({ - embeds: LoadingEmbed, - fetchReply: true, - ephemeral: true - })) as Message; + if (member.user.bannerURL() ) { embeds[0]!.embed.setImage(member.user.bannerURL()!); } let page = 0; let timedOut = false; + for (const embed of embeds) { + embed.embed.setDescription(embed.embed.description + "\n" + createPageIndicator(embeds.length, embed.pageId)); + } while (!timedOut) { - const em = new Discord.EmbedBuilder(embeds[page].embed); - em.setDescription(em.description + "\n" + createPageIndicator(embeds.length, page)); - let selectPane = []; + const em = embeds[page]!.embed; + + let selectPane: ActionRowBuilder[] = []; if (selectPaneOpen) { - const options: MessageSelectOptionData[] = []; + const options: APISelectMenuOption[] = []; embeds.forEach((embed) => { options.push({ label: embed.title, @@ -240,19 +247,19 @@ const callback = async (interaction: CommandInteraction): Promise => { }); }); selectPane = [ - new ActionRowBuilder().addComponents([ - new Discord.SelectMenuBuilder() + new ActionRowBuilder().addComponents( + new Discord.StringSelectMenuBuilder() .addOptions(options) .setCustomId("page") .setMaxValues(1) .setPlaceholder("Choose a page...") - ]) + ) ]; } - await interaction.editReply({ + const m = await interaction.editReply({ embeds: [em], components: selectPane.concat([ - new ActionRowBuilder().addComponents([ + new ActionRowBuilder().addComponents([ new ButtonBuilder() .setEmoji(getEmojiByName("CONTROL.LEFT", "id")) .setStyle(ButtonStyle.Secondary) @@ -279,21 +286,21 @@ const callback = async (interaction: CommandInteraction): Promise => { continue; } i.deferUpdate(); - if ((i.component as Component).customId === "left") { + if (i.customId === "left") { if (page > 0) page--; selectPaneOpen = false; - } else if ((i.component as Component).customId === "right") { + } else if (i.customId === "right") { if (page < embeds.length - 1) page++; selectPaneOpen = false; - } else if ((i.component as Component).customId === "select") { + } else if (i.customId === "select") { selectPaneOpen = !selectPaneOpen; - } else if ((i.component as Component).customId === "page") { - page = parseInt((i as SelectMenuInteraction).values[0]); + } else if (i.customId === "page" && i.isStringSelectMenu()) { + page = parseInt(i.values[0]!); selectPaneOpen = false; } } - const em = new Discord.EmbedBuilder(embeds[page].embed); - em.setDescription(em.description + "\n" + createPageIndicator(embeds.length, page) + " | Message closed"); + const em = embeds[page]!.embed; + em.setDescription(em.description + " | Message closed"); await interaction.editReply({ embeds: [em], components: [] @@ -307,3 +314,4 @@ const check = () => { export { command }; export { callback }; export { check }; +export { userAbout }; \ No newline at end of file diff --git a/src/config/emojis.json b/src/config/emojis.json index fc90ce4..f29f383 100644 --- a/src/config/emojis.json +++ b/src/config/emojis.json @@ -179,18 +179,18 @@ "BADGES": { "NUCLEUSDEVELOPER": "957722888360853595", "CLICKSDEVELOPER": "957722888314683462", - "HOUSE_BRAVERY": "775783765930016789", - "HOUSE_BRILLIANCE": "775783766152577095", - "HOUSE_BALANCE": "775783766303440937", - "HYPESQUAD_EVENTS": "775783766194126908", - "EARLY_SUPPORTER": "775783766055452693", - "BUGHUNTER_LEVEL_1": "775783766252847154", - "BUGHUNTER_LEVEL_2": "775783766130950234", - "PARTNERED_SERVER_OWNER": "775783766178005033", - "DISCORD_EMPLOYEE": "775783766383788082", - "EARLY_VERIFIED_BOT_DEVELOPER": "775783766425600060", "BOT": "776375959108190239", - "BOOSTER": "775783766131605545" + "BOOSTER": "775783766131605545", + "HypeSquadOnlineHouse1": "775783765930016789", + "HypeSquadOnlineHouse2": "775783766152577095", + "HypeSquadOnlineHouse3": "775783766303440937", + "Hypesquad": "775783766194126908", + "PremiumEarlySupporter": "775783766055452693", + "BugHunterLevel1": "775783766252847154", + "BugHunterLevel2": "775783766130950234", + "Partner": "775783766178005033", + "Staff": "775783766383788082", + "VerifiedDeveloper": "775783766425600060" }, "VOICE": { "CONNECT": "784785219391193138", diff --git a/src/utils/commandRegistration/register.ts b/src/utils/commandRegistration/register.ts index 1f2241c..0193f6c 100644 --- a/src/utils/commandRegistration/register.ts +++ b/src/utils/commandRegistration/register.ts @@ -119,10 +119,10 @@ async function registerContextMenus() { client.commands["contextCommands/user/" + context.command.name] = context; - console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.green}Loaded ${file.name} [${i} / ${userFiles.length}]${colours.none}`) + console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.green}Loaded ${file.name} [${i} / ${totalFiles}]${colours.none}`) } catch (e) { errors++; - console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.red}Failed to load ${file.name} [${i} / ${userFiles.length}]${colours.none}`) + console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.red}Failed to load ${file.name} [${i} / ${totalFiles}]${colours.none}`) } } @@ -187,7 +187,7 @@ export default async function register() { } await registerCommandHandler(); await registerEvents(); - console.log(`${colours.green}Registered commands and events${colours.none}`) + console.log(`${colours.green}Registered commands, events and context menus${colours.none}`) console.log( (config.enableDevelopment ? `${colours.purple}Bot started in Development mode` : `${colours.blue}Bot started in Production mode`) + colours.none) diff --git a/src/utils/generateEmojiEmbed.ts b/src/utils/generateEmojiEmbed.ts index e1b481a..c0f17ae 100644 --- a/src/utils/generateEmojiEmbed.ts +++ b/src/utils/generateEmojiEmbed.ts @@ -10,6 +10,7 @@ const colors = { class EmojiEmbed extends EmbedBuilder { _title = ""; _emoji: string | null = null; + description = ""; _generateTitle() { if (this._emoji) { return `${getEmojiByName(this._emoji)} ${this._title}`; } @@ -21,6 +22,11 @@ class EmojiEmbed extends EmbedBuilder { super.setTitle(this._generateTitle()); return this; } + override setDescription(description: string) { + this.description = description; + super.setDescription(description); + return this; + } setEmoji(emoji: string) { this._emoji = emoji; super.setTitle(this._generateTitle());