worked on settings/rolemenu and help
diff --git a/src/commands/help.ts b/src/commands/help.ts
index 767ca46..1a0ce16 100644
--- a/src/commands/help.ts
+++ b/src/commands/help.ts
@@ -1,17 +1,89 @@
-import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction } from "discord.js";
+import { ActionRowBuilder, CommandInteraction, StringSelectMenuBuilder, ApplicationCommand, ApplicationCommandOptionType } from "discord.js";
import { SlashCommandBuilder } from "@discordjs/builders";
+import client from "../utils/client.js";
+import EmojiEmbed from "../utils/generateEmojiEmbed.js";
+import { LoadingEmbed } from "../utils/defaults.js";
const command = new SlashCommandBuilder()
.setName("help")
.setDescription("Shows help for commands");
const callback = async (interaction: CommandInteraction): Promise<void> => {
- interaction.reply({components: [new ActionRowBuilder<ButtonBuilder>().addComponents(
- new ButtonBuilder()
- .setLabel("Create ticket")
- .setStyle(ButtonStyle.Primary)
- .setCustomId("createticket")
- )]}); // TODO: FINISH THIS FOR RELEASE
+ const m = await interaction.reply({ embeds: LoadingEmbed, fetchReply: true });
+ const commands = client.fetchedCommands;
+
+ const commandRow = new ActionRowBuilder<StringSelectMenuBuilder>()
+ .addComponents(
+ commands.map((command) => {
+ return new StringSelectMenuBuilder()
+ .setCustomId(command.name)
+ .setPlaceholder("Select a command")
+ .addOptions({
+ label: command.name,
+ value: command.name
+ })
+ })
+ );
+
+ let closed = false;
+ do {
+ let current: ApplicationCommand | undefined;
+ const subcommandGroupRow = new ActionRowBuilder<StringSelectMenuBuilder>()
+ .addComponents(
+ new StringSelectMenuBuilder()
+ .setCustomId("subcommandGroupRow")
+ );
+ const subcommandRow = new ActionRowBuilder<StringSelectMenuBuilder>()
+ .addComponents(
+ new StringSelectMenuBuilder()
+ .setCustomId("subcommandRow")
+ );
+ const embed = new EmojiEmbed()
+ .setTitle("Help")
+ .setStatus("Success")
+ .setEmoji("📖")
+
+ if(!current) {
+ embed.setDescription(
+ `**${"Help Menu Home"}**\n\n` +
+ `${"Select a command to get started"}`
+ )
+ } else {
+ embed.setDescription(
+ `**${current.name}**\n\n` +
+ `${current.description}`
+ )
+ if(current.options.filter((option) => option.type === ApplicationCommandOptionType.SubcommandGroup).length > 0) {
+ subcommandGroupRow.components[0]!
+ .addOptions(
+ current.options.filter((option) => option.type === ApplicationCommandOptionType.SubcommandGroup).map((option) => {
+ return {
+ label: option.name,
+ value: option.name
+ }
+ })
+ )
+ } else {
+ if(current.options.filter((option) => option.type === ApplicationCommandOptionType.Subcommand).length > 0) {
+ subcommandRow.components[0]!
+ .addOptions(
+ current.options.filter((option) => option.type === ApplicationCommandOptionType.Subcommand).map((option) => {
+ return {
+ label: option.name,
+ value: option.name
+ }
+ })
+ )
+ }
+ }
+ }
+ let cmps = [commandRow];
+ if(subcommandGroupRow.components[0]!.options.length > 0) cmps.push(subcommandGroupRow);
+ if(subcommandRow.components[0]!.options.length > 0) cmps.push(subcommandRow);
+
+ await interaction.editReply({ embeds: [embed], components: cmps });
+
+ } while (!closed);
};
const check = () => {
diff --git a/src/commands/nucleus/premium.ts b/src/commands/nucleus/premium.ts
index 8b47ab7..e74e23c 100644
--- a/src/commands/nucleus/premium.ts
+++ b/src/commands/nucleus/premium.ts
@@ -91,7 +91,7 @@
.setDescription(
`You have already activated premium on the maximum amount of servers!` + firstDescription
)
- .setEmoji("NUCLEUS.LOGO")
+ .setEmoji("NUCLEUS.PREMIUMACTIVATE")
.setStatus("Danger")
],
components: []
diff --git a/src/commands/settings/oldStats.ts b/src/commands/settings/oldStats.ts
deleted file mode 100644
index 8f13109..0000000
--- a/src/commands/settings/oldStats.ts
+++ /dev/null
@@ -1,291 +0,0 @@
-import { LoadingEmbed } from "../../utils/defaults.js";
-import Discord, { CommandInteraction, Message, ActionRowBuilder, StringSelectMenuBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuOptionBuilder, APIMessageComponentEmoji, MessageComponentInteraction, TextInputBuilder } from "discord.js";
-import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
-import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
-import client from "../../utils/client.js";
-import convertCurlyBracketString from "../../utils/convertCurlyBracketString.js";
-import singleNotify from "../../utils/singleNotify.js";
-import getEmojiByName from "../../utils/getEmojiByName.js";
-import createPageIndicator from "../../utils/createPageIndicator.js";
-import { modalInteractionCollector } from "../../utils/dualCollector.js";
-import type { GuildConfig } from "../../utils/database.js";
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
- .setName("oldstats")
- .setDescription("Controls channels which update when someone joins or leaves the server")
-
-type ChangesType = Record<string, { name?: string; enabled?: boolean; }>
-
-const applyChanges = (baseObject: GuildConfig['stats'], changes: ChangesType): GuildConfig['stats'] => {
- for (const [id, { name, enabled }] of Object.entries(changes)) {
- if (!baseObject[id]) baseObject[id] = { name: "", enabled: false};
- if (name) baseObject[id]!.name = name;
- if (enabled) baseObject[id]!.enabled = enabled;
- }
- return baseObject;
-}
-
-
-const callback = async (interaction: CommandInteraction) => {
- try{
- if (!interaction.guild) return;
- const { renderChannel } = client.logger;
- let closed = false;
- let page = 0;
- const m: Message = await interaction.reply({ embeds: LoadingEmbed, ephemeral: true, fetchReply: true });
- let changes: ChangesType = {};
- do {
- const config = await client.database.guilds.read(interaction.guild.id);
- const stats = config.stats;
- let currentID = "";
- let current: {
- name: string;
- enabled: boolean;
- } = {
- name: "",
- enabled: false
- };
- let description = "";
- const pageSelect = new StringSelectMenuBuilder()
- .setCustomId("page")
- .setPlaceholder("Select a stats channel to manage")
- .setDisabled(Object.keys(stats).length === 0)
- .setMinValues(1)
- .setMaxValues(1);
- const actionSelect = new StringSelectMenuBuilder()
- .setCustomId("action")
- .setPlaceholder("Perform an action")
- .setMinValues(1)
- .setMaxValues(1)
- .setDisabled(Object.keys(stats).length === 0)
- .addOptions(
- new StringSelectMenuOptionBuilder()
- .setLabel("Edit")
- .setValue("edit")
- .setDescription("Edit the name of this stats channel")
- .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
- new StringSelectMenuOptionBuilder()
- .setLabel("Delete")
- .setValue("delete")
- .setDescription("Delete this stats channel")
- .setEmoji(getEmojiByName("TICKETS.ISSUE", "id") as APIMessageComponentEmoji)
- );
- if (Object.keys(stats).length === 0) {
- description = "You do not have any stats channels set up yet"
- pageSelect.addOptions(new StringSelectMenuOptionBuilder().setLabel("No stats channels").setValue("none"))
- } else {
- currentID = Object.keys(stats)[page]!
- current = stats[currentID]!;
- current = applyChanges({ [currentID]: current }, changes)[currentID]!;
- for (const [id, { name, enabled }] of Object.entries(stats)) {
- pageSelect.addOptions(
- new StringSelectMenuOptionBuilder()
- .setLabel(name)
- .setValue(id)
- .setDescription(`Enabled: ${enabled}`)
- );
- }
- actionSelect.addOptions(new StringSelectMenuOptionBuilder()
- .setLabel(current.enabled ? "Disable" : "Enable")
- .setValue("toggleEnabled")
- .setDescription(`Currently ${current.enabled ? "Enabled" : "Disabled"}, click to ${current.enabled ? "disable" : "enable"} this channel`)
- .setEmoji(getEmojiByName(current.enabled ? "CONTROL.TICK" : "CONTROL.CROSS", "id") as APIMessageComponentEmoji)
- );
- description = `**Currently Editing:** ${renderChannel(currentID)}\n\n` +
- `${getEmojiByName(current.enabled ? "CONTROL.TICK" : "CONTROL.CROSS")} Currently ${current.enabled ? "Enabled" : "Disabled"}\n` +
- `**Name:** \`${current.name}\`\n` +
- `**Preview:** ${await convertCurlyBracketString(current.name, interaction.user.id, interaction.user.username, interaction.guild.name, interaction.guild.members)}`
- }
- const row = new ActionRowBuilder<ButtonBuilder>()
- .addComponents(
- new ButtonBuilder()
- .setCustomId("back")
- .setStyle(ButtonStyle.Primary)
- .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
- .setDisabled(page === 0),
- new ButtonBuilder()
- .setCustomId("next")
- .setEmoji(getEmojiByName("CONTROL.RIGHT", "id") as APIMessageComponentEmoji)
- .setStyle(ButtonStyle.Primary)
- .setDisabled(page === Object.keys(stats).length - 1),
- new ButtonBuilder()
- .setCustomId("add")
- .setLabel("Create new")
- .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id") as APIMessageComponentEmoji)
- .setStyle(ButtonStyle.Secondary)
- .setDisabled(Object.keys(stats).length >= 24),
- new ButtonBuilder()
- .setCustomId("save")
- .setLabel("Save")
- .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
- .setStyle(ButtonStyle.Success)
- .setDisabled(Object.keys(changes).length === 0),
- );
-
- const embed = new EmojiEmbed()
- .setTitle("Stats Channels")
- .setDescription(description + "\n\n" + createPageIndicator(Object.keys(stats).length, page))
- .setEmoji("SETTINGS.STATS.GREEN")
- .setStatus("Success")
-
- interaction.editReply({
- embeds: [embed],
- components: [
- new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(pageSelect),
- new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(actionSelect),
- row
- ]
- });
- let i: MessageComponentInteraction;
- try {
- i = await m.awaitMessageComponent({ filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id, time: 30000 });
- } catch (e) {
- closed = true;
- continue;
- }
- if (i.isStringSelectMenu()) {
- switch(i.customId) {
- case "page":
- page = Object.keys(stats).indexOf(i.values[0]!);
- await i.deferUpdate();
- break;
- case "action":
- if(!changes[currentID]) changes[currentID] = {};
- switch(i.values[0]!) {
- case "edit":
- await i.showModal(
- new Discord.ModalBuilder()
- .setCustomId("modal")
- .setTitle(`Stats channel name`)
- .addComponents(
- new ActionRowBuilder<TextInputBuilder>().addComponents(
- new TextInputBuilder()
- .setCustomId("ex1")
- .setLabel("Server Info (1/3)")
- .setPlaceholder(
- `{serverName} - This server's name\n\n` +
- `These placeholders will be replaced with the server's name, etc..`
- )
- .setMaxLength(1)
- .setRequired(false)
- .setStyle(Discord.TextInputStyle.Paragraph)
- ),
- new ActionRowBuilder<TextInputBuilder>().addComponents(
- new TextInputBuilder()
- .setCustomId("ex2")
- .setLabel("Member Counts (2/3) - {MemberCount:...}")
- .setPlaceholder(
- `{:all} - Total member count\n` +
- `{:humans} - Total non-bot users\n` +
- `{:bots} - Number of bots\n`
- )
- .setMaxLength(1)
- .setRequired(false)
- .setStyle(Discord.TextInputStyle.Paragraph)
- ),
- new ActionRowBuilder<TextInputBuilder>().addComponents(
- new TextInputBuilder()
- .setCustomId("ex3")
- .setLabel("Latest Member (3/3) - {member:...}")
- .setPlaceholder(
- `{:name} - The members name\n`
- )
- .setMaxLength(1)
- .setRequired(false)
- .setStyle(Discord.TextInputStyle.Paragraph)
- ),
- new ActionRowBuilder<TextInputBuilder>().addComponents(
- new TextInputBuilder()
- .setCustomId("text")
- .setLabel("Channel name input")
- .setMaxLength(1000)
- .setRequired(true)
- .setStyle(Discord.TextInputStyle.Short)
- .setValue(current.name)
- )
- )
- );
- await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Stats Channel")
- .setDescription("Modal opened. If you can't see it, click back and try again.")
- .setStatus("Success")
- .setEmoji("SETTINGS.STATS.GREEN")
- ],
- components: [
- new ActionRowBuilder<ButtonBuilder>().addComponents(
- new ButtonBuilder()
- .setLabel("Back")
- .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
- .setStyle(ButtonStyle.Primary)
- .setCustomId("back")
- )
- ]
- });
- let out: Discord.ModalSubmitInteraction | null;
- try {
- out = await modalInteractionCollector(
- m,
- (m) => m.channel!.id === interaction.channel!.id,
- (_) => true
- ) as Discord.ModalSubmitInteraction | null;
- } catch (e) {
- continue;
- }
- if (!out) continue
- if (!out.fields) continue
- if (out.isButton()) continue;
- const newString = out.fields.getTextInputValue("text");
- if (!newString) continue;
- changes[currentID]!.name = newString;
- break;
- case "delete":
- changes[currentID] = {};
- await i.deferUpdate();
- break;
- case "toggleEnabled":
- changes[currentID]!.enabled = !stats[currentID]!.enabled;
- await i.deferUpdate();
- break;
- }
- break;
- }
- } else if (i.isButton()) {
- await i.deferUpdate();
- switch(i.customId) {
- case "back":
- page--;
- break;
- case "next":
- page++;
- break;
- case "add":
- break;
- case "save":
- const changed = applyChanges(config.stats, changes);
- singleNotify("statsChannelDeleted", interaction.guild.id, true)
- config.stats = changed;
- changes = {}
- await client.database.guilds.write(interaction.guildId!, config);
- }
- }
- console.log(changes, config.stats);
- } while (!closed);
- } catch(e) {
- console.log(e)
- }
-};
-
-const check = (interaction: CommandInteraction) => {
- const member = interaction.member as Discord.GuildMember;
- if (!member.permissions.has("ManageChannels"))
- return "You must have the *Manage Channels* permission to use this command";
- return true;
-};
-
-
-export { command };
-export { callback };
-export { check };
\ No newline at end of file
diff --git a/src/commands/settings/rolemenu.ts b/src/commands/settings/rolemenu.ts
index b62d962..f8fb6f4 100644
--- a/src/commands/settings/rolemenu.ts
+++ b/src/commands/settings/rolemenu.ts
@@ -1,16 +1,350 @@
import type Discord from "discord.js";
-import type { CommandInteraction } from "discord.js";
+import { ActionRowBuilder, APIMessageComponentEmoji, ButtonBuilder, ButtonInteraction, ButtonStyle, CommandInteraction, Message, ModalBuilder, RoleSelectMenuBuilder, RoleSelectMenuInteraction, StringSelectMenuBuilder, StringSelectMenuInteraction, StringSelectMenuOptionBuilder, TextInputBuilder, TextInputStyle } from "discord.js";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import { LoadingEmbed } from "../../utils/defaults.js";
+import client from "../../utils/client.js";
+import getEmojiByName from "../../utils/getEmojiByName.js";
+import createPageIndicator from "../../utils/createPageIndicator.js";
+import { configToDropdown } from "../../actions/roleMenu.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
.setName("rolemenu")
- .setDescription("rolemenu") // TODO
- .addRoleOption((option) => option.setName("role").setDescription("The role to give after verifying")); // FIXME FOR FUCK SAKE
+ .setDescription("rolemenu")
+
+interface ObjectSchema {
+ name: string;
+ description: string;
+ min: number;
+ max: number;
+ options: {
+ name: string;
+ description: string | null;
+ role: string;
+ }[];
+}
+
+const editNameDescription = async (interaction: StringSelectMenuInteraction | ButtonInteraction, m: Message, data: {name?: string, description?: string}) => {
+
+ let {name, description} = data;
+ const modal = new ModalBuilder()
+ .setTitle("Edit Name and Description")
+ .setCustomId("editNameDescription")
+ .addComponents(
+ new ActionRowBuilder<TextInputBuilder>()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId("name")
+ .setPlaceholder(name ?? "")
+ .setStyle(TextInputStyle.Short)
+ .setRequired(true),
+ new TextInputBuilder()
+ .setCustomId("description")
+ .setPlaceholder(description ?? "")
+ .setStyle(TextInputStyle.Short)
+ )
+ )
+ const button = new ActionRowBuilder<ButtonBuilder>()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId("back")
+ .setLabel("Back")
+ .setStyle(ButtonStyle.Secondary)
+ .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
+ )
+
+ return [name, description]
+
+}
+
+const ellipsis = (str: string, max: number): string => {
+ if (str.length <= max) return str;
+ return str.slice(0, max - 3) + "...";
+}
+
+const createRoleMenuPage = async (interaction: StringSelectMenuInteraction | ButtonInteraction, m: Message, data?: ObjectSchema) => {
+ if (!data) data = {
+ name: "Role Menu Page",
+ description: "A new role menu page",
+ min: 0,
+ max: 0,
+ options: []
+ };
+ const buttons = new ActionRowBuilder<ButtonBuilder>()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId("back")
+ .setLabel("Back")
+ .setStyle(ButtonStyle.Secondary)
+ .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
+ new ButtonBuilder()
+ .setCustomId("edit")
+ .setLabel("Edit")
+ .setStyle(ButtonStyle.Primary)
+ .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
+ new ButtonBuilder()
+ .setCustomId("addRole")
+ .setLabel("Add Role")
+ .setStyle(ButtonStyle.Secondary)
+ .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id") as APIMessageComponentEmoji)
+ );
+
+ let back = false
+ do {
+ const previewSelect = configToDropdown("Edit Roles", {name: data.name, description: data.description, min: 1, max: 1, options: data.options});
+ const embed = new EmojiEmbed()
+ .setTitle(`${data.name}`)
+ .setStatus("Success")
+ .setDescription(
+ `**Description:**\n> ${data.description}\n\n` +
+ `**Min:** ${data.min}` + (data.min === 0 ? " (Members will be given a skip button)" : "") + "\n" +
+ `**Max:** ${data.max}\n`
+ )
+
+ interaction.editReply({embeds: [embed], components: [previewSelect, buttons]});
+ let i: StringSelectMenuInteraction | ButtonInteraction;
+ try {
+ i = await m.awaitMessageComponent({ time: 300000, filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id && i.channelId === interaction.channelId}) as ButtonInteraction | StringSelectMenuInteraction;
+ } catch (e) {
+ back = true;
+ break;
+ }
+
+ if (i.isStringSelectMenu()) {
+ if(i.customId === "roles") {
+ await i.deferUpdate();
+ await createRoleMenuOptionPage(interaction, m, data.options.find((o) => o.role === (i as StringSelectMenuInteraction).values[0]));
+ }
+ } else if (i.isButton()) {
+ await i.deferUpdate();
+ switch (i.customId) {
+ case "back":
+ back = true;
+ break;
+ case "edit":
+ let [name, description] = await editNameDescription(interaction, m, data);
+ data.name = name ? name : data.name;
+ data.description = description ? description : data.description;
+ break;
+ case "addRole":
+ data.options.push(await createRoleMenuOptionPage(interaction, m));
+ break;
+ }
+ }
+
+ } while (!back);
+ return data;
+}
+
+const createRoleMenuOptionPage = async (interaction: StringSelectMenuInteraction | ButtonInteraction, m: Message, data?: {name: string; description: string | null; role: string}) => {
+ const { renderRole} = client.logger;
+ if (!data) data = {
+ name: "Role Menu Option",
+ description: null,
+ role: "No role set"
+ };
+ let back = false;
+ const buttons = new ActionRowBuilder<ButtonBuilder>()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId("back")
+ .setLabel("Back")
+ .setStyle(ButtonStyle.Secondary)
+ .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
+ new ButtonBuilder()
+ .setCustomId("edit")
+ .setLabel("Edit Details")
+ .setStyle(ButtonStyle.Primary)
+ .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji)
+ );
+ do {
+ const roleSelect = new RoleSelectMenuBuilder().setCustomId("role").setPlaceholder(data.role ? "Set role to" : "Set the role");
+ const embed = new EmojiEmbed()
+ .setTitle(`${data.name ?? "New Role Menu Option"}`)
+ .setStatus("Success")
+ .setDescription(
+ `**Description:**\n> ${data.description ?? "No description set"}\n\n` +
+ `**Role:** ${renderRole((await interaction.guild!.roles.fetch(data.role))!) ?? "No role set"}\n`
+ )
+
+ interaction.editReply({embeds: [embed], components: [new ActionRowBuilder<RoleSelectMenuBuilder>().addComponents(roleSelect), buttons]});
+
+ let i: RoleSelectMenuInteraction | ButtonInteraction;
+ try {
+ i = await m.awaitMessageComponent({ time: 300000, filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id && i.channelId === interaction.channelId}) as ButtonInteraction | RoleSelectMenuInteraction;
+ } catch (e) {
+ back = true;
+ break;
+ }
+
+ if (i.isRoleSelectMenu()) {
+ if(i.customId === "role") {
+ await i.deferUpdate();
+ data.role = (i as RoleSelectMenuInteraction).values[0]!;
+ }
+ } else if (i.isButton()) {
+ await i.deferUpdate();
+ switch (i.customId) {
+ case "back":
+ back = true;
+ break;
+ case "edit":
+ await i.deferUpdate();
+ let [name, description] = await editNameDescription(interaction, m, data as {name: string; description: string});
+ data.name = name ? name : data.name;
+ data.description = description ? description : data.description;
+ break;
+ }
+ }
+ } while (!back);
+ return data;
+}
const callback = async (interaction: CommandInteraction): Promise<void> => {
- console.log("we changed the charger again because fuck you");
- await interaction.reply("You're mum");
+ if (!interaction.guild) return;
+ const m = await interaction.reply({embeds: LoadingEmbed, ephemeral: true, fetchReply: true});
+
+ let page = 0;
+ let closed = false;
+ const config = await client.database.guilds.read(interaction.guild.id);
+ let currentObject: ObjectSchema[] = config.roleMenu.options;
+ let modified = false;
+ do {
+ const embed = new EmojiEmbed()
+ .setTitle("Role Menu Settings")
+ .setEmoji("GUILD.GREEN")
+ .setStatus("Success");
+ const noRoleMenus = currentObject.length === 0;
+ let current: ObjectSchema;
+
+ const pageSelect = new StringSelectMenuBuilder()
+ .setCustomId("page")
+ .setPlaceholder("Select a Role Menu page to manage");
+ const actionSelect = new StringSelectMenuBuilder()
+ .setCustomId("action")
+ .setPlaceholder("Perform an action")
+ .addOptions(
+ new StringSelectMenuOptionBuilder()
+ .setLabel("Edit")
+ .setDescription("Edit this page")
+ .setValue("edit")
+ .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
+ new StringSelectMenuOptionBuilder()
+ .setLabel("Delete")
+ .setDescription("Delete this page")
+ .setValue("delete")
+ .setEmoji(getEmojiByName("TICKETS.ISSUE", "id") as APIMessageComponentEmoji)
+ );
+ const buttonRow = new ActionRowBuilder<ButtonBuilder>()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId("back")
+ .setStyle(ButtonStyle.Primary)
+ .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
+ .setDisabled(page === 0),
+ new ButtonBuilder()
+ .setCustomId("next")
+ .setEmoji(getEmojiByName("CONTROL.RIGHT", "id") as APIMessageComponentEmoji)
+ .setStyle(ButtonStyle.Primary)
+ .setDisabled(page === Object.keys(currentObject).length - 1),
+ new ButtonBuilder()
+ .setCustomId("add")
+ .setLabel("New Page")
+ .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id") as APIMessageComponentEmoji)
+ .setStyle(ButtonStyle.Secondary)
+ .setDisabled(Object.keys(currentObject).length >= 24),
+ new ButtonBuilder()
+ .setCustomId("reorder")
+ .setLabel("Reorder Pages")
+ .setEmoji(getEmojiByName("ICONS.SHUFFLE", "id") as APIMessageComponentEmoji)
+ .setStyle(ButtonStyle.Secondary)
+ .setDisabled(Object.keys(currentObject).length <= 1),
+ new ButtonBuilder()
+ .setCustomId("save")
+ .setLabel("Save")
+ .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
+ .setStyle(ButtonStyle.Success)
+ .setDisabled(!modified),
+ );
+ if(noRoleMenus) {
+ embed.setDescription("No role menu page have been set up yet. Use the button below to add one.\n\n" +
+ createPageIndicator(1, 1, undefined, true)
+ );
+ pageSelect.setDisabled(true);
+ actionSelect.setDisabled(true);
+ pageSelect.addOptions(new StringSelectMenuOptionBuilder()
+ .setLabel("No role menu pages")
+ .setValue("none")
+ );
+ } else {
+ page = Math.min(page, Object.keys(currentObject).length - 1);
+ current = currentObject[page]!;
+ embed.setDescription(`**Currently Editing:** ${current.name}\n\n` +
+ `**Description:** \`${current.description}\`\n` +
+ `\n\n${createPageIndicator(Object.keys(config.roleMenu.options).length, page)}`
+ );
+
+ pageSelect.addOptions(
+ currentObject.map((key: ObjectSchema, index) => {
+ return new StringSelectMenuOptionBuilder()
+ .setLabel(ellipsis(key.name, 50))
+ .setDescription(ellipsis(key.description, 50))
+ .setValue(index.toString());
+ })
+ );
+
+ }
+
+ await interaction.editReply({embeds: [embed], components: [new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(actionSelect), new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(pageSelect), buttonRow]});
+ let i: StringSelectMenuInteraction | ButtonInteraction;
+ try {
+ i = await m.awaitMessageComponent({ time: 300000, filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id && i.channelId === interaction.channelId}) as ButtonInteraction | StringSelectMenuInteraction;
+ } catch (e) {
+ closed = true;
+ break;
+ }
+
+ await i.deferUpdate();
+ if (i.isButton()) {
+ switch (i.customId) {
+ case "back":
+ page--;
+ break;
+ case "next":
+ page++;
+ break;
+ case "add":
+ currentObject.push(await createRoleMenuPage(i, m));
+ page = currentObject.length - 1;
+ break;
+ case "reorder":
+ break;
+ case "save":
+ client.database.guilds.write(interaction.guild.id, {"roleMenu.options": currentObject});
+ modified = false;
+ break;
+ }
+ } else if (i.isStringSelectMenu()) {
+ switch (i.customId) {
+ case "action":
+ switch(i.values[0]) {
+ case "edit":
+ currentObject[page] = await createRoleMenuPage(i, m, current!);
+ modified = true;
+ break;
+ case "delete":
+ currentObject.splice(page, 1);
+ break;
+ }
+ break;
+ case "page":
+ page = parseInt(i.values[0]!);
+ break;
+ }
+ }
+
+ } while (!closed)
};
const check = (interaction: CommandInteraction) => {
diff --git a/src/commands/settings/stats.ts b/src/commands/settings/stats.ts
index f191a34..91da382 100644
--- a/src/commands/settings/stats.ts
+++ b/src/commands/settings/stats.ts
@@ -232,29 +232,29 @@
.setEmoji(getEmojiByName("TICKETS.ISSUE", "id") as APIMessageComponentEmoji)
);
const buttonRow = new ActionRowBuilder<ButtonBuilder>()
- .addComponents(
- new ButtonBuilder()
- .setCustomId("back")
- .setStyle(ButtonStyle.Primary)
- .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
- .setDisabled(page === 0),
- new ButtonBuilder()
- .setCustomId("next")
- .setEmoji(getEmojiByName("CONTROL.RIGHT", "id") as APIMessageComponentEmoji)
- .setStyle(ButtonStyle.Primary)
- .setDisabled(page === Object.keys(currentObject).length - 1),
- new ButtonBuilder()
- .setCustomId("add")
- .setLabel("Create new")
- .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id") as APIMessageComponentEmoji)
- .setStyle(ButtonStyle.Secondary)
- .setDisabled(Object.keys(currentObject).length >= 24),
- new ButtonBuilder()
- .setCustomId("save")
- .setLabel("Save")
- .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
- .setStyle(ButtonStyle.Success)
- .setDisabled(modified),
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId("back")
+ .setStyle(ButtonStyle.Primary)
+ .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
+ .setDisabled(page === 0),
+ new ButtonBuilder()
+ .setCustomId("next")
+ .setEmoji(getEmojiByName("CONTROL.RIGHT", "id") as APIMessageComponentEmoji)
+ .setStyle(ButtonStyle.Primary)
+ .setDisabled(page === Object.keys(currentObject).length - 1),
+ new ButtonBuilder()
+ .setCustomId("add")
+ .setLabel("Create new")
+ .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id") as APIMessageComponentEmoji)
+ .setStyle(ButtonStyle.Secondary)
+ .setDisabled(Object.keys(currentObject).length >= 24),
+ new ButtonBuilder()
+ .setCustomId("save")
+ .setLabel("Save")
+ .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
+ .setStyle(ButtonStyle.Success)
+ .setDisabled(modified),
);
if (noStatsChannels) {
embed.setDescription("No stats channels have been set up yet. Use the button below to add one.\n\n" +
@@ -275,7 +275,6 @@
.setDescription(`Currently ${current.enabled ? "Enabled" : "Disabled"}, click to ${current.enabled ? "disable" : "enable"} this channel`)
.setEmoji(getEmojiByName(current.enabled ? "CONTROL.TICK" : "CONTROL.CROSS", "id") as APIMessageComponentEmoji)
);
-
embed.setDescription(`**Currently Editing:** ${renderChannel(Object.keys(currentObject)[page]!)}\n\n` +
`${getEmojiByName(current.enabled ? "CONTROL.TICK" : "CONTROL.CROSS")} Currently ${current.enabled ? "Enabled" : "Disabled"}\n` +
`**Name:** \`${current.name}\`\n` +