blob: 7214799a9b75b007001469283421cd0b7a8572f5 [file] [log] [blame]
TheCodedProff86ba092023-01-27 17:10:07 -05001import {
2 ActionRowBuilder,
3 CommandInteraction,
4 StringSelectMenuBuilder,
5 ApplicationCommandOptionType,
6 ApplicationCommandType,
7 StringSelectMenuOptionBuilder,
8 SlashCommandBuilder,
9 StringSelectMenuInteraction,
10 ComponentType,
11 APIMessageComponentEmoji,
12 ApplicationCommandSubGroup,
13 PermissionsBitField,
14 Interaction,
15 ApplicationCommandOption,
16 ApplicationCommandSubCommand
17} from "discord.js";
TheCodedProf1c3ad3c2023-01-25 17:58:36 -050018import client from "../utils/client.js";
19import EmojiEmbed from "../utils/generateEmojiEmbed.js";
20import { LoadingEmbed } from "../utils/defaults.js";
TheCodedProff86ba092023-01-27 17:10:07 -050021import { capitalize } from "../utils/generateKeyValueList.js";
22import { getCommandByName, getCommandMentionByName } from "../utils/getCommandDataByName.js";
23import getEmojiByName from "../utils/getEmojiByName.js";
pineafan4f164f32022-02-26 22:07:12 +000024
PineaFan752af462022-12-31 21:59:38 +000025const command = new SlashCommandBuilder()
26 .setName("help")
27 .setDescription("Shows help for commands");
pineafan4f164f32022-02-26 22:07:12 +000028
TheCodedProff86ba092023-01-27 17:10:07 -050029const styles: Record<string, {emoji: string}> = {
30 "help": {emoji: "NUCLEUS.LOGO"},
31 "mod": {emoji: "PUNISH.BAN.RED"},
32 "nucleus": {emoji: "NUCLEUS.LOGO"},
33 "privacy": {emoji: "NUCLEUS.LOGO"},
34 "role": {emoji: "GUILD.ROLES.DELETE"},
35 "rolemenu": {emoji: "GUILD.ROLES.DELETE"},
36 "server": {emoji: "GUILD.RED"},
37 "settings": {emoji: "GUILD.SETTINGS.RED"},
38 "tag": {emoji: "PUNISH.NICKNAME.RED"},
39 "tags": {emoji: "PUNISH.NICKNAME.RED"},
40 "ticket": {emoji: "GUILD.TICKET.CLOSE"},
41 "user": {emoji: "MEMBER.LEAVE"},
42 "verify": {emoji: "CONTROL.BLOCKTICK"}
43}
44
pineafan63fc5e22022-08-04 22:04:10 +010045const callback = async (interaction: CommandInteraction): Promise<void> => {
TheCodedProff86ba092023-01-27 17:10:07 -050046 const m = await interaction.reply({ embeds: LoadingEmbed, ephemeral: true, fetchReply: true });
TheCodedProf1c3ad3c2023-01-25 17:58:36 -050047 const commands = client.fetchedCommands;
48
TheCodedProf1c3ad3c2023-01-25 17:58:36 -050049 let closed = false;
TheCodedProff86ba092023-01-27 17:10:07 -050050 let currentPath: [string, string, string] = ["","",""]
TheCodedProf1c3ad3c2023-01-25 17:58:36 -050051 do {
TheCodedProff86ba092023-01-27 17:10:07 -050052 const commandRow = new ActionRowBuilder<StringSelectMenuBuilder>()
53 .addComponents(
54 new StringSelectMenuBuilder()
55 .setCustomId("commandRow")
56 .setPlaceholder("Select a command")
57 .addOptions(
58 ...commands.filter(command => command.type === ApplicationCommandType.ChatInput).map((command) => {
59 const builder = new StringSelectMenuOptionBuilder()
60 .setLabel(capitalize(command.name))
61 .setValue(command.name)
62 .setDescription(command.description)
63 .setDefault(currentPath[0] === command.name)
64 if (styles[command.name]) builder.setEmoji(getEmojiByName(styles[command.name]!.emoji, "id") as APIMessageComponentEmoji)
65 return builder
66 })
67 )
68 );
TheCodedProf1c3ad3c2023-01-25 17:58:36 -050069 const subcommandGroupRow = new ActionRowBuilder<StringSelectMenuBuilder>()
70 .addComponents(
71 new StringSelectMenuBuilder()
72 .setCustomId("subcommandGroupRow")
73 );
74 const subcommandRow = new ActionRowBuilder<StringSelectMenuBuilder>()
75 .addComponents(
76 new StringSelectMenuBuilder()
77 .setCustomId("subcommandRow")
78 );
79 const embed = new EmojiEmbed()
80 .setTitle("Help")
TheCodedProff86ba092023-01-27 17:10:07 -050081 .setStatus("Danger")
82 .setEmoji("NUCLEUS.LOGO")
TheCodedProf1c3ad3c2023-01-25 17:58:36 -050083
TheCodedProff86ba092023-01-27 17:10:07 -050084 if(currentPath[0] === "" || currentPath[0] === "help") {
TheCodedProf1c3ad3c2023-01-25 17:58:36 -050085 embed.setDescription(
TheCodedProff86ba092023-01-27 17:10:07 -050086 `Welcome to Nucleus\n\n` +
87 `Select a command to get started${(interaction.member?.permissions as PermissionsBitField).has("ManageGuild") ? `, or run ${getCommandMentionByName("nucleus/guide")} for commands to set up your server` : ``}` // FIXME
TheCodedProf1c3ad3c2023-01-25 17:58:36 -050088 )
89 } else {
TheCodedProff86ba092023-01-27 17:10:07 -050090 let currentData = getCommandByName(currentPath.filter(value => value !== "" && value !== "none").join('/'));
91 let current = commands.find((command) => command.name === currentPath[0])!;
92
93 let optionString = ``
94 let options: (ApplicationCommandOption & {
95 nameLocalized?: string;
96 descriptionLocalized?: string;
97 })[] = [];
98 //options
99 for(const option of options) {
100 optionString += `> ${option.name} (${option.type})- ${option.description}\n`
101 }
102 const APICommand = client.commands["commands/" + currentPath.filter(value => value !== "" && value !== "none").join("/")]![0]
103 let allowedToRun = true;
104 if(APICommand?.check) {
105 APICommand?.check(interaction as Interaction, true)
106 }
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500107 embed.setDescription(
TheCodedProff86ba092023-01-27 17:10:07 -0500108 `${getEmojiByName(styles[currentPath[0]]!.emoji)} **${capitalize(currentData.name)}**\n> ${currentData.mention}\n\n` +
109 `> ${currentData.description}\n\n` +
110 (APICommand ? (`${getEmojiByName(allowedToRun ? "CONTROL.TICK" : "CONTROL.CROSS")} You ${allowedToRun ? "" : "don't "}` +
111 `have permission to use this command\n\n`) : "") +
112 ((optionString.length > 0) ? "**Options:**\n" + optionString : "")
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500113 )
TheCodedProf92a003c2023-01-25 18:01:21 -0500114 const subcommands = current.options.filter((option) => option.type === ApplicationCommandOptionType.Subcommand);
115 const subcommandGroups = current.options.filter((option) => option.type === ApplicationCommandOptionType.SubcommandGroup);
TheCodedProff86ba092023-01-27 17:10:07 -0500116
TheCodedProf92a003c2023-01-25 18:01:21 -0500117 if(subcommandGroups.length > 0) {
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500118 subcommandGroupRow.components[0]!
119 .addOptions(
TheCodedProff86ba092023-01-27 17:10:07 -0500120 new StringSelectMenuOptionBuilder().setLabel("Select a subcommand").setValue("none").setDefault(currentPath[1] === "none"),
121 ...subcommandGroups.map((option) => new StringSelectMenuOptionBuilder().setLabel(capitalize(option.name)).setValue(option.name).setDefault(currentPath[1] === option.name))
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500122 )
TheCodedProffe0a7862023-01-27 20:36:35 -0500123 if(subcommandGroupRow.components[0]!.options.find((option) => option.data.default && option.data.value !== "none")) {
TheCodedProff86ba092023-01-27 17:10:07 -0500124 let subsubcommands = (subcommandGroups.find((option) => option.name === currentPath[1])! as ApplicationCommandSubGroup).options?.filter((option) => option.type === ApplicationCommandOptionType.Subcommand) || [];
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500125 subcommandRow.components[0]!
126 .addOptions(
TheCodedProff86ba092023-01-27 17:10:07 -0500127 new StringSelectMenuOptionBuilder().setLabel("Select a subcommand").setValue("none").setDefault(currentPath[2] === "none"),
128 ...subsubcommands.map((option) => new StringSelectMenuOptionBuilder().setLabel(capitalize(option.name)).setValue(option.name).setDefault(currentPath[2] === option.name))
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500129 )
130 }
131 }
TheCodedProff86ba092023-01-27 17:10:07 -0500132 if(subcommands.length > 0) {
133 subcommandGroupRow.components[0]!
134 .addOptions(
135 ...subcommands.map((option) => new StringSelectMenuOptionBuilder().setLabel(capitalize(option.name)).setValue(option.name).setDefault(currentPath[1] === option.name))
136 )
137 }
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500138 }
TheCodedProff86ba092023-01-27 17:10:07 -0500139
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500140 let cmps = [commandRow];
141 if(subcommandGroupRow.components[0]!.options.length > 0) cmps.push(subcommandGroupRow);
142 if(subcommandRow.components[0]!.options.length > 0) cmps.push(subcommandRow);
143
144 await interaction.editReply({ embeds: [embed], components: cmps });
145
TheCodedProff86ba092023-01-27 17:10:07 -0500146 let i: StringSelectMenuInteraction;
147 try {
148 i = await m.awaitMessageComponent<ComponentType.StringSelect>({filter: (newInteraction) => interaction.user.id === newInteraction.user.id,time: 300000})
149 } catch (e) {
150 closed = true;
151 break;
152 }
153 await i.deferUpdate();
154 let value = i.values[0]!;
155 switch(i.customId) {
156 case "commandRow":
157 currentPath = [value, "", ""];
158 break;
159 case "subcommandGroupRow":
160 currentPath = [currentPath[0], value , ""];
161 break;
162 case "subcommandRow":
163 currentPath[2] = value;
164 break;
165 }
TheCodedProff86ba092023-01-27 17:10:07 -0500166
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500167 } while (!closed);
pineafan63fc5e22022-08-04 22:04:10 +0100168};
pineafan4f164f32022-02-26 22:07:12 +0000169
pineafan4f164f32022-02-26 22:07:12 +0000170
TheCodedProff86ba092023-01-27 17:10:07 -0500171export { command as command };
pineafan4f164f32022-02-26 22:07:12 +0000172export { callback };