Development (#97)
diff --git a/src/actions/roleMenu.ts b/src/actions/roleMenu.ts
index 8b623a4..5eb1d7e 100644
--- a/src/actions/roleMenu.ts
+++ b/src/actions/roleMenu.ts
@@ -32,7 +32,7 @@
interface ObjectSchema {
name: string;
- description: string | null;
+ description?: string;
min: number;
max: number;
options: {
@@ -46,7 +46,7 @@
placeholder: string,
currentPageData: ObjectSchema,
selectedRoles?: string[],
- disabled?: boolean
+ disabled: boolean = false
): ActionRowBuilder<StringSelectMenuBuilder> => {
return new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
new StringSelectMenuBuilder()
@@ -72,7 +72,7 @@
if (!interaction.member) return;
if (!interaction.guild) return;
const config = await client.database.guilds.read(interaction.guild.id);
- const options = config.roleMenu.options.filter((option) => option.options.length > 0);
+ const options = config.roleMenu.options.filter((option) => option.options.length > 0 && option.enabled);
if (!config.roleMenu.enabled) {
return await interaction.reply({
embeds: [
@@ -195,6 +195,7 @@
while (!(complete && done)) {
const currentPageData = options[page]!;
+ currentPageData.max = currentPageData.max === 0 ? currentPageData.options.length : currentPageData.max;
const embed = new EmojiEmbed()
.setTitle("Roles")
.setDescription(
diff --git a/src/commands/settings/rolemenu.ts b/src/commands/settings/rolemenu.ts
index 47914c6..1ca10a4 100644
--- a/src/commands/settings/rolemenu.ts
+++ b/src/commands/settings/rolemenu.ts
@@ -27,14 +27,17 @@
import ellipsis from "../../utils/ellipsis.js";
import _ from "lodash";
+const cross = getEmojiByName("CONTROL.CROSS");
+const tick = getEmojiByName("CONTROL.TICK");
const isEqual = _.isEqual;
const command = (builder: SlashCommandSubcommandBuilder) =>
builder.setName("rolemenu").setDescription("Allows you to change settings for the servers rolemenu");
interface ObjectSchema {
+ enabled?: boolean;
name: string;
- description: string | null;
+ description?: string;
min: number;
max: number;
options: {
@@ -106,34 +109,60 @@
i: ButtonInteraction,
interaction: StringSelectMenuInteraction | ButtonInteraction,
m: Message,
- data: { name?: string; description?: string | null }
-) => {
- let { name, description } = data;
- const modal = new ModalBuilder()
- .setTitle("Edit Name and Description")
- .setCustomId("editNameDescription")
- .addComponents(
+ data: { name?: string; description?: string; bounds?: { min: number; max: number } },
+ addBounds: boolean = false
+): Promise<[string | undefined, string | undefined, { min: number; max: number } | undefined]> => {
+ let { name, description, bounds } = data;
+ const components = [
+ new ActionRowBuilder<TextInputBuilder>().addComponents(
+ new TextInputBuilder()
+ .setLabel("Name")
+ .setCustomId("name")
+ .setPlaceholder("The name of the role (e.g. Programmer)")
+ .setStyle(TextInputStyle.Short)
+ .setValue(name ?? "")
+ .setRequired(true)
+ .setMaxLength(100)
+ ),
+ new ActionRowBuilder<TextInputBuilder>().addComponents(
+ new TextInputBuilder()
+ .setLabel("Description")
+ .setCustomId("description")
+ .setPlaceholder("A short description of the role (e.g. A role for people who code)")
+ .setStyle(TextInputStyle.Short)
+ .setValue(description ?? "")
+ .setRequired(false)
+ .setMaxLength(100)
+ )
+ ];
+ if (addBounds && bounds) {
+ components.push(
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
- .setLabel("Name")
- .setCustomId("name")
- .setPlaceholder("The name of the role (e.g. Programmer)")
+ .setLabel("Minimum")
+ .setCustomId("min")
+ .setPlaceholder("The minimum number of roles a user can select")
.setStyle(TextInputStyle.Short)
- .setValue(name ?? "")
+ .setValue(bounds.min.toString())
.setRequired(true)
- .setMaxLength(100)
+ .setMaxLength(2)
),
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
- .setLabel("Description")
- .setCustomId("description")
- .setPlaceholder("A short description of the role (e.g. A role for people who code)")
+ .setLabel("Maximum")
+ .setCustomId("max")
+ .setPlaceholder("The maximum number of roles a user can select (0 for no limit)")
.setStyle(TextInputStyle.Short)
- .setValue(description ?? "")
- .setRequired(false)
- .setMaxLength(100)
+ .setValue(bounds.max.toString())
+ .setRequired(true)
+ .setMaxLength(2)
)
);
+ }
+ const modal = new ModalBuilder()
+ .setTitle("Edit Name and Description")
+ .setCustomId("editNameDescription")
+ .addComponents(...components);
const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId("back")
@@ -160,14 +189,20 @@
console.error(e);
out = null;
}
- if (!out) return [name, description];
- if (out.isButton()) return [name, description];
+ if (!out) return [name, description, bounds];
+ if (out.isButton()) return [name, description, bounds];
name = out.fields.fields.find((f) => f.customId === "name")?.value ?? name;
- description = out.fields.fields.find((f) => f.customId === "description")?.value ?? null;
- return [name, description];
+ description = out.fields.fields.find((f) => f.customId === "description")?.value;
+ if (addBounds) {
+ const min = parseInt(out.fields.fields.find((f) => f.customId === "min")?.value!);
+ const max = parseInt(out.fields.fields.find((f) => f.customId === "max")?.value!);
+ bounds = { min, max };
+ }
+ return [name, description, bounds];
};
const defaultRoleMenuData = {
+ enabled: true,
name: "New Page",
description: "",
min: 0,
@@ -204,13 +239,20 @@
const noRoles = data.options.length === 0;
const previewSelect = configToDropdown(
"Edit Roles",
- {
- name: data.name,
- description: data.description ?? null,
- min: 1,
- max: 1,
- options: noRoles ? [{ name: "Role 1", description: null, role: "No role set" }] : data.options
- },
+ data.description
+ ? {
+ name: data.name,
+ description: data.description,
+ min: 1,
+ max: 1,
+ options: noRoles ? [{ name: "Role 1", description: null, role: "No role set" }] : data.options
+ }
+ : {
+ name: data.name,
+ min: 1,
+ max: 1,
+ options: noRoles ? [{ name: "Role 1", description: null, role: "No role set" }] : data.options
+ },
undefined,
noRoles
);
@@ -257,9 +299,9 @@
break;
}
case "edit": {
- const [name, description] = await editNameDescription(i, interaction, m, data);
+ const [name, description, _bounds] = await editNameDescription(i, interaction, m, data);
data.name = name ? name : data.name;
- data.description = description ? description : data.description;
+ description ? (data.description = description) : null;
break;
}
case "addRole": {
@@ -474,15 +516,16 @@
if (page > 0) (actionSelect as StringSelectMenuBuilder).setDisabled(true);
pageSelect.addOptions(new StringSelectMenuOptionBuilder().setLabel("No role menu pages").setValue("none"));
} else if (page === 0) {
- const cross = getEmojiByName("CONTROL.CROSS");
- const tick = getEmojiByName("CONTROL.TICK");
embed.setDescription(
`**Enabled:** ${currentObject.enabled ? `${tick} Yes` : `${cross} No`}\n\n` +
`**Pages:** ${currentObject.options.length}\n` +
(currentObject.options.length > 0
? currentObject.options
.map((key: ObjectSchema) => {
- return `> **${key.name}:** ${key.description ?? "*No description set*"}`;
+ const crossOut = key.enabled ? "" : "~~";
+ return `> ${crossOut}**${key.name}:** ${
+ key.description ?? "*No description set*"
+ }${crossOut}`;
})
.join("\n")
: "")
@@ -502,7 +545,7 @@
50
)
)
- .setValue(index.toString());
+ .setValue((index + 1).toString());
})
);
} else {
@@ -514,10 +557,28 @@
} else {
page = Math.max(Math.min(page, currentObject.options.length), 0);
current = currentObject.options[page - 1]!;
+ (actionSelect as StringSelectMenuBuilder).addOptions(
+ new StringSelectMenuOptionBuilder()
+ .setLabel(current.enabled ? "Disable" : "Enable")
+ .setDescription("Enable or disable this page")
+ .setValue("switch")
+ .setEmoji(
+ getEmojiByName(
+ current.enabled ? "CONTROL.CROSS" : "CONTROL.TICK",
+ "id"
+ ) as APIMessageComponentEmoji
+ )
+ );
embed.setDescription(
`**Currently Editing:** ${current.name}\n\n` +
+ `**Visible:** ${current.enabled ? `${tick} Yes` : `${cross} No`}\n\n` +
`**Description:**\n> ${current.description ?? "*No description set*"}\n` +
- `\n\n${createPageIndicator(Object.keys(config.roleMenu.options).length, page)}`
+ `\n\n${createPageIndicator(
+ Object.keys(currentObject.options).length,
+ page - 1,
+ false,
+ Object.values(currentObject.options).map((o) => !(o.enabled ?? true))
+ )}`
);
pageSelect.addOptions(
@@ -534,7 +595,7 @@
50
)
)
- .setValue(index.toString());
+ .setValue((index + 1).toString());
})
);
}
@@ -595,8 +656,7 @@
}
case "save": {
await client.database.guilds.write(interaction.guild.id, {
- "roleMenu.options": currentObject.options,
- "rolemenu.enabled": currentObject.enabled
+ roleMenu: currentObject
});
modified = false;
await client.memory.forceUpdate(interaction.guild.id);
@@ -615,7 +675,7 @@
case "edit": {
const edited = await editRoleMenuPage(i, m, current!);
if (!edited) break;
- currentObject.options[page] = edited;
+ currentObject.options[page - 1] = edited;
modified = true;
break;
}
@@ -626,6 +686,11 @@
modified = true;
break;
}
+ case "switch": {
+ currentObject.options[page - 1]!.enabled = !currentObject.options[page - 1]!.enabled;
+ modified = true;
+ break;
+ }
}
break;
}
diff --git a/src/config/emojis.ts b/src/config/emojis.ts
index b04c569..8bcab8d 100644
--- a/src/config/emojis.ts
+++ b/src/config/emojis.ts
@@ -344,15 +344,27 @@
HORIZONTAL: {
LEFT: {
ACTIVE: "963121920038035506",
- INACTIVE: "963121944239153242"
+ INACTIVE: "963121944239153242",
+ GRAY: {
+ ACTIVE: "1115723064500572240",
+ INACTIVE: "1115722930970697788"
+ }
},
MIDDLE: {
ACTIVE: "963121925893263420",
- INACTIVE: "963121949796597870"
+ INACTIVE: "963121949796597870",
+ GRAY: {
+ ACTIVE: "1115723063263232112",
+ INACTIVE: "1115722848405827614"
+ }
},
RIGHT: {
ACTIVE: "963121933384302602",
- INACTIVE: "963121956125831168"
+ INACTIVE: "963121956125831168",
+ GRAY: {
+ ACTIVE: "1115722933445349398",
+ INACTIVE: "1115722847051071639"
+ }
}
},
VERTICAL: {
diff --git a/src/utils/createPageIndicator.ts b/src/utils/createPageIndicator.ts
index e16422d..0831c83 100644
--- a/src/utils/createPageIndicator.ts
+++ b/src/utils/createPageIndicator.ts
@@ -1,17 +1,29 @@
import getEmojiByName from "./getEmojiByName.js";
-function pageIndicator(amount: number, selected: number, showDetails?: boolean, disabled?: boolean | string) {
+function pageIndicator(
+ amount: number,
+ selected: number,
+ showDetails?: boolean,
+ disabled?: boolean | string | boolean[]
+) {
let out = "";
- disabled = disabled ? "GRAY." : "";
+ // disabled = disabled ? "GRAY." : "";
+ // If disabled is a string, make a list of booleans the same length as amount.
+ if (!Array.isArray(disabled)) disabled = new Array(amount).fill(disabled);
+ // If the length is wrong, fill extra with false
+ if (disabled.length !== amount) {
+ disabled = disabled.concat(new Array(amount).fill(false));
+ }
+ const grey = disabled.map((x) => (x ? "GRAY." : ""));
if (amount === 1) {
- out += getEmojiByName("TRACKS.SINGLE." + disabled + (selected === 0 ? "ACTIVE" : "INACTIVE"));
+ out += getEmojiByName("TRACKS.SINGLE." + grey[0] + (selected === 0 ? "ACTIVE" : "INACTIVE"));
} else {
for (let i = 0; i < amount; i++) {
out += getEmojiByName(
"TRACKS.HORIZONTAL." +
(i === 0 ? "LEFT" : i === amount - 1 ? "RIGHT" : "MIDDLE") +
"." +
- disabled +
+ grey[i] +
(i === selected ? "ACTIVE" : "INACTIVE")
);
}
diff --git a/src/utils/database.ts b/src/utils/database.ts
index a1d5f49..67049cb 100644
--- a/src/utils/database.ts
+++ b/src/utils/database.ts
@@ -1015,8 +1015,9 @@
enabled: boolean;
allowWebUI: boolean;
options: {
+ enabled?: boolean;
name: string;
- description: string | null;
+ description?: string;
min: number;
max: number;
options: {