diff --git a/src/commands/general/help.ts b/src/commands/general/help.ts
index a58e171..73ccb69 100644
--- a/src/commands/general/help.ts
+++ b/src/commands/general/help.ts
@@ -15,9 +15,10 @@
* along with ArgonBot. If not, see .
*/
import Command from '@structures/command';
+import config from 'config';
+import { MessageButton } from 'discord.js';
import { Client, Message, MessageEmbed } from 'discord.js';
import i18next from 'i18next';
-import path from 'path';
export default class extends Command {
public constructor(client: Client, file: string) {
@@ -36,7 +37,7 @@ export default class extends Command {
public async run(message: Message, command: string): Promise {
if(!command) {
- const commandGroups: { name: string; embeds: MessageEmbed, commands: Command[] }[] = [];
+ const commandGroups: { name: string; embed: MessageEmbed, commands: Command[] }[] = [];
this.client.commands.forEach((command) => {
const findCommand = commandGroups.find((val) => val.name === command.options.group);
@@ -46,13 +47,113 @@ export default class extends Command {
} else {
commandGroups.push({
name: command.options.group!,
- embeds: new MessageEmbed(),
+ embed: new MessageEmbed(),
commands: [command],
});
}
});
- console.log(path.basename(this.file));
+ commandGroups.forEach((val, index) => {
+ val.embed = new MessageEmbed();
+ val.embed.setAuthor(i18next.t('commands:help.embedName'));
+ val.embed.setTitle(val.name.toUpperCase());
+ val.embed.setColor(message.member?.roles.highest.color ?? 0xFFFFFF);
+ val.embed.setFooter(`Page ${index+1}/${commandGroups.length}`);
+ val.embed.setTimestamp();
+
+ val.commands.forEach((command) => {
+ val.embed.addField(`${config.get('prefix')}${command.options.name}`, command.options.shortDescription ?? i18next.t('commands:generic.noShortDescription').toUpperCase(), false);
+ });
+ });
+
+ let currentPage = 0;
+
+ const nextCategoryBtn = new MessageButton();
+ nextCategoryBtn.setCustomID('nextCategoryBtn');
+ nextCategoryBtn.setLabel(i18next.t('commands:help.nextCategoryBtn'));
+ nextCategoryBtn.setStyle('PRIMARY');
+
+ const previousCategoryBtn = new MessageButton();
+ previousCategoryBtn.setCustomID('previousCategoryBtn');
+ previousCategoryBtn.setLabel(i18next.t('commands:help.previousCategoryBtn'));
+ previousCategoryBtn.setStyle('SECONDARY');
+ previousCategoryBtn.setDisabled(true);
+
+ const helpMsg = await message.channel.send({
+ content: i18next.t('commands:help.helpScreenBtnHelp'),
+ embeds: [commandGroups[0]!.embed],
+ components: [[previousCategoryBtn, nextCategoryBtn]],
+ });
+
+ const buttonCollector = helpMsg.channel.createMessageComponentInteractionCollector({ time: 60000 });
+
+ buttonCollector.on('collect', async (interaction) => {
+ if(interaction.customID === 'nextCategoryBtn') {
+ currentPage++;
+
+ if(currentPage+1 === commandGroups.length) {
+ nextCategoryBtn.setDisabled(true);
+ }
+
+ if(currentPage !== 0) {
+ previousCategoryBtn.setDisabled(false);
+ }
+
+ await interaction.update({
+ content: i18next.t('commands:help.helpScreenBtnHelp'),
+ embeds: [commandGroups[currentPage]!.embed],
+ components: [[previousCategoryBtn, nextCategoryBtn]],
+ });
+ } else {
+ currentPage--;
+
+ if(currentPage === 0) {
+ previousCategoryBtn.setDisabled(true);
+ nextCategoryBtn.setDisabled(false);
+ }
+
+ if(currentPage !== 0) {
+ nextCategoryBtn.setDisabled(false);
+ }
+
+ await interaction.update({
+ content: i18next.t('commands:help.helpScreenBtnHelp'),
+ embeds: [commandGroups[currentPage]!.embed],
+ components: [[previousCategoryBtn, nextCategoryBtn]],
+ });
+ }
+ });
+
+ buttonCollector.on('end', async () => {
+ nextCategoryBtn.setDisabled(true);
+ previousCategoryBtn.setDisabled(true);
+
+ await helpMsg.edit({
+ content: i18next.t('commands:help.helpTimedOut'),
+ embeds: [commandGroups[currentPage]!.embed],
+ components: [[previousCategoryBtn, nextCategoryBtn]],
+ });
+ });
+ } else {
+ const findCommand = this.client.commands.find((cmd) => cmd.options.name === command);
+
+ if(findCommand) {
+ const commandEmbed = new MessageEmbed();
+ commandEmbed.setAuthor(i18next.t('commands:help.embedName'));
+ commandEmbed.setTitle(findCommand.options.name!.toUpperCase());
+ commandEmbed.setColor(message.member?.roles.highest.color ?? 0xFFFFFF);
+ commandEmbed.setTimestamp();
+
+ commandEmbed.setDescription(i18next.t('commands:help.commandDescription', {
+ name: findCommand.options.name,
+ description: findCommand.options.extendedDescription ?? i18next.t('commands:generic.noExtendedDescription'),
+ usage: findCommand.options.usage ? `!${findCommand.options.name} ${findCommand.options.usage}` : i18next.t('commands:generic.noUsage'),
+ }));
+
+ await message.channel.send({ embeds: [commandEmbed] });
+ } else {
+ await message.reply(i18next.t('commands:help.unknownCommand'));
+ }
}
}
}
diff --git a/src/index.ts b/src/index.ts
index 908e5c6..bf6d0ae 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -15,6 +15,7 @@
* along with ArgonBot. If not, see .
*/
import 'module-alias/register';
+import '@utils/augments';
import ArgonClient from '@lib/ArgonClient';
import { Defaults } from '@utils/defaults';
@@ -33,7 +34,6 @@ import Fluent from 'i18next-fluent';
import FSBackend from 'i18next-fs-backend';
import { Validator } from 'jsonschema';
import { DateTime } from 'luxon';
-import path from 'path';
import process from 'process';
let isBotReady = false;
@@ -146,7 +146,7 @@ client.on('ready', async () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fileCommand = require(file);
- const command = new fileCommand['default'](client, path.basename(file, path.extname(file)));
+ const command = new fileCommand['default'](client, file);
client.commands.set(command.options.name, command);
@@ -156,6 +156,7 @@ client.on('ready', async () => {
info(`Finished loading commands! Found ${client.commands.size} commands.`, ELoggingScope.Startup);
} catch(err) {
+ console.log(err);
fatal(`An error has occurred while attempting to load command files! Please see error below\n${err.message}`, ELoggingScope.Startup);
}
diff --git a/src/lib/ArgonClient.ts b/src/lib/ArgonClient.ts
index 16a43d0..e461e24 100644
--- a/src/lib/ArgonClient.ts
+++ b/src/lib/ArgonClient.ts
@@ -18,7 +18,7 @@ import type Command from '@structures/command';
import { Client, ClientOptions, Collection } from 'discord.js';
export default class extends Client {
- public readonly commands: Collection = new Collection();
+ public override readonly commands: Collection = new Collection();
public constructor(options: ClientOptions) {
super(options);
diff --git a/src/lib/structures/command.ts b/src/lib/structures/command.ts
index e8bedd5..6d67c5d 100644
--- a/src/lib/structures/command.ts
+++ b/src/lib/structures/command.ts
@@ -15,7 +15,6 @@
* along with ArgonBot. If not, see .
*/
import type { ICommandOptions } from '@utils/types';
-import { ECommandRunIn } from '@utils/types';
import config from 'config';
import type { Client, Message } from 'discord.js';
import path from 'path';
@@ -31,11 +30,7 @@ export default abstract class Command {
const defaultOptions: ICommandOptions = {
name: path.basename(this.file, path.extname(this.file)),
- group: path.dirname(this.file) === 'commands' ? '' : path.dirname(this.file),
- ownerOnly: false,
- runIn: ECommandRunIn.Both,
- shortDescription: '',
- extendedDescription: '',
+ group: path.basename(path.dirname(this.file)) === 'commands' ? '' : path.basename(path.dirname(this.file)),
};
this.options = config.util.extendDeep(defaultOptions, options);
diff --git a/src/lib/utils/augments.ts b/src/lib/utils/augments.ts
index 2686a0b..c7b1075 100644
--- a/src/lib/utils/augments.ts
+++ b/src/lib/utils/augments.ts
@@ -14,3 +14,13 @@
* You should have received a copy of the GNU General Public License
* along with ArgonBot. If not, see .
*/
+
+import type ArgonClient from '@lib/ArgonClient';
+import type Command from '@structures/command';
+
+declare module 'discord.js' {
+ export interface Client {
+ constructor: typeof ArgonClient;
+ readonly commands: Collection;
+ }
+}
diff --git a/src/lib/utils/types.ts b/src/lib/utils/types.ts
index 948b1c1..36cd516 100644
--- a/src/lib/utils/types.ts
+++ b/src/lib/utils/types.ts
@@ -32,9 +32,10 @@ export enum ECommandRunIn {
// Interfaces
export interface ICommandOptions {
name?: string;
+ group?: string;
shortDescription?: string;
extendedDescription?: string;
- group?: string;
+ usage?: string;
ownerOnly?: boolean;
runIn?: ECommandRunIn;
args?: {
diff --git a/translations/en-US/commands.json b/translations/en-US/commands.json
index 6e009f9..d1140d0 100644
--- a/translations/en-US/commands.json
+++ b/translations/en-US/commands.json
@@ -12,7 +12,13 @@
"shortDescription": "Shows help menu",
"extendedDescription": "Shows an advanced help menu for commands to show usage",
"commandArg": "The command to see",
- "unknownCommand": "Unknown command given!"
+ "unknownCommand": "Unknown command given!",
+ "embedName": "Help Menu!",
+ "helpScreenBtnHelp": "Press the \"Forward\" or \"Back\" Button to move categories!",
+ "nextCategoryBtn": "Next Category",
+ "previousCategoryBtn": "Previous Category",
+ "helpTimedOut": "Timed Out",
+ "commandDescription": "Name: { $name }\nCategory: { $category }\nDescription: { $description }\nUsage: { $usage }"
},
"errors": {
"ownerOnly": "Only the bot owner can run this command!",
@@ -23,6 +29,7 @@
"generic": {
"noShortDescription": "No short description given!",
"noExtendedDescription": "No extended description given!",
- "noArgsDescription": "No description for { $arg } has been given!"
+ "noArgsDescription": "No description for { $arg } has been given!",
+ "noUsage": "No usage given!"
}
}