diff --git a/src/actions/roleMenu.ts b/src/actions/roleMenu.ts index 6997393..9c9430d 100644 --- a/src/actions/roleMenu.ts +++ b/src/actions/roleMenu.ts @@ -45,7 +45,8 @@ interface ObjectSchema { export const configToDropdown = ( placeholder: string, currentPageData: ObjectSchema, - selectedRoles?: string[] + selectedRoles?: string[], + disabled?: boolean ): ActionRowBuilder => { return new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() @@ -53,6 +54,7 @@ export const configToDropdown = ( .setPlaceholder(placeholder) .setMinValues(currentPageData.min) .setMaxValues(currentPageData.max) + .setDisabled(disabled) .addOptions( currentPageData.options.map((option: { name: string; description: string | null; role: string }) => { const builder = new StringSelectMenuOptionBuilder() diff --git a/src/commands/nucleus/suggest.ts b/src/commands/nucleus/suggest.ts index f6755e2..1110b9a 100644 --- a/src/commands/nucleus/suggest.ts +++ b/src/commands/nucleus/suggest.ts @@ -119,9 +119,21 @@ const callback = async (interaction: CommandInteraction): Promise => { ], components: [ new Discord.ActionRowBuilder().addComponents( - new ButtonBuilder().setCustomId("accept:Suggestion").setLabel("Accept").setStyle(ButtonStyle.Success).setDisabled(disabled), - new ButtonBuilder().setCustomId("deny:Suggestion").setLabel("Deny").setStyle(ButtonStyle.Danger).setDisabled(disabled), - new ButtonBuilder().setCustomId("close:Suggestion").setLabel("Close").setStyle(ButtonStyle.Secondary).setDisabled(disabled), + new ButtonBuilder() + .setCustomId("accept:Suggestion") + .setLabel("Accept") + .setStyle(ButtonStyle.Success) + .setDisabled(disabled), + new ButtonBuilder() + .setCustomId("deny:Suggestion") + .setLabel("Deny") + .setStyle(ButtonStyle.Danger) + .setDisabled(disabled), + new ButtonBuilder() + .setCustomId("close:Suggestion") + .setLabel("Close") + .setStyle(ButtonStyle.Secondary) + .setDisabled(disabled), new ButtonBuilder() .setCustomId("implemented:Suggestion") .setLabel("Implemented") @@ -134,8 +146,16 @@ const callback = async (interaction: CommandInteraction): Promise => { .setDisabled(disabled) ), new Discord.ActionRowBuilder().addComponents( - new ButtonBuilder().setCustomId("lock:Comment").setLabel("Lock").setStyle(ButtonStyle.Danger).setDisabled(disabled), - new ButtonBuilder().setCustomId("spam:Suggestion").setLabel("Mark as Spam").setStyle(ButtonStyle.Danger).setDisabled(disabled) + new ButtonBuilder() + .setCustomId("lock:Comment") + .setLabel("Lock") + .setStyle(ButtonStyle.Danger) + .setDisabled(disabled), + new ButtonBuilder() + .setCustomId("spam:Suggestion") + .setLabel("Mark as Spam") + .setStyle(ButtonStyle.Danger) + .setDisabled(disabled) ) ] }); diff --git a/src/commands/settings/rolemenu.ts b/src/commands/settings/rolemenu.ts index 7da9dfe..0b41854 100644 --- a/src/commands/settings/rolemenu.ts +++ b/src/commands/settings/rolemenu.ts @@ -120,6 +120,7 @@ const editNameDescription = async ( .setStyle(TextInputStyle.Short) .setValue(name ?? "") .setRequired(true) + .setMaxLength(100) ), new ActionRowBuilder().addComponents( new TextInputBuilder() @@ -128,6 +129,8 @@ const editNameDescription = async ( .setPlaceholder("A short description of the role (e.g. A role for people who code)") .setStyle(TextInputStyle.Short) .setValue(description ?? "") + .setRequired(false) + .setMaxLength(100) ) ); const button = new ActionRowBuilder().addComponents( @@ -159,15 +162,15 @@ const editNameDescription = async ( if (!out) return [name, description]; if (out.isButton()) return [name, description]; name = out.fields.fields.find((f) => f.customId === "name")?.value ?? name; - description = out.fields.fields.find((f) => f.customId === "description")?.value ?? description; + description = out.fields.fields.find((f) => f.customId === "description")?.value ?? ""; return [name, description]; }; const defaultRoleMenuData = { - name: "Role Menu Page", - description: "A new role menu page", + name: "New Page", + description: "", min: 0, - max: 0, + max: 1, options: [] }; @@ -196,17 +199,20 @@ const editRoleMenuPage = async ( ); let back = false; - if (data.options.length === 0) { - data.options = [{ name: "Role 1", description: null, role: "No role set" }]; - } do { - const previewSelect = configToDropdown("Edit Roles", { - name: data.name, - description: data.description, - min: 1, - max: 1, - options: data.options - }); + const noRoles = data.options.length === 0; + const previewSelect = configToDropdown( + "Edit Roles", + { + name: data.name, + description: data.description, + min: 1, + max: 1, + options: noRoles ? [{ name: "Role 1", description: null, role: "No role set" }] : data.options + }, + undefined, + noRoles + ); const embed = new EmojiEmbed() .setTitle(`${data.name}`) .setStatus("Success") @@ -215,7 +221,8 @@ const editRoleMenuPage = async ( `**Min:** ${data.min}` + (data.min === 0 ? " (Members will be given a skip button)" : "") + "\n" + - `**Max:** ${data.max}\n` + `**Max:** ${data.max}\n` + + `\n**Roles:** ${data.options.length === 0 ? "*No roles set*" : data.options.length}` ); await interaction.editReply({ embeds: [embed], components: [previewSelect, buttons] }); @@ -237,7 +244,8 @@ const editRoleMenuPage = async ( await createRoleMenuOptionPage( interaction, m, - data.options.find((o) => o.role === (i as StringSelectMenuInteraction).values[0]) + data.options.find((o) => o.role === (i as StringSelectMenuInteraction).values[0]), + false ); } } else if (i.isButton()) { @@ -255,7 +263,8 @@ const editRoleMenuPage = async ( } case "addRole": { await i.deferUpdate(); - data.options.push(await createRoleMenuOptionPage(interaction, m)); + const out = await createRoleMenuOptionPage(interaction, m, undefined, true); + if (out) data.options.push(out); break; } } @@ -268,8 +277,10 @@ const editRoleMenuPage = async ( const createRoleMenuOptionPage = async ( interaction: StringSelectMenuInteraction | ButtonInteraction, m: Message, - data?: { name: string; description: string | null; role: string } + data?: { name: string; description: string | null; role: string }, + newRole: boolean = false ) => { + const initialData = _.cloneDeep(data); const { renderRole } = client.logger; if (!data) data = { @@ -281,19 +292,29 @@ const createRoleMenuOptionPage = async ( const buttons = new ActionRowBuilder().addComponents( new ButtonBuilder() .setCustomId("back") - .setLabel("Back") - .setStyle(ButtonStyle.Secondary) - .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji), + .setLabel(newRole ? "Add" : "Back") + .setStyle(newRole ? ButtonStyle.Success : ButtonStyle.Secondary) + .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji), new ButtonBuilder() .setCustomId("edit") .setLabel("Edit Details") .setStyle(ButtonStyle.Primary) - .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji) + .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji), + new ButtonBuilder() + .setCustomId("delete") + .setLabel("Delete") + .setStyle(ButtonStyle.Danger) + .setEmoji(getEmojiByName("TICKETS.ISSUE", "id") as APIMessageComponentEmoji), + new ButtonBuilder() + .setCustomId("cancel") + .setLabel("Cancel") + .setStyle(ButtonStyle.Secondary) + .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji) ); do { const roleSelect = new RoleSelectMenuBuilder() .setCustomId("role") - .setPlaceholder(data.role ? "Set role to" : "Set the role"); + .setPlaceholder(data.role ? "Change role to" : "Select a role"); const embed = new EmojiEmbed() .setTitle(`${data.name}`) .setStatus("Success") @@ -325,6 +346,12 @@ const createRoleMenuOptionPage = async ( if (i.customId === "role") { await i.deferUpdate(); data.role = (i as RoleSelectMenuInteraction).values[0]!; + await interaction.editReply({ + embeds: [ + new EmojiEmbed().setTitle(`Applying changes`).setStatus("Danger").setEmoji("NUCLEUS.LOADING") + ], + components: [] + }); } } else if (i.isButton()) { switch (i.customId) { @@ -334,7 +361,6 @@ const createRoleMenuOptionPage = async ( break; } case "edit": { - await i.deferUpdate(); const [name, description] = await editNameDescription( i, interaction, @@ -345,6 +371,15 @@ const createRoleMenuOptionPage = async ( data.description = description ? description : data.description; break; } + case "delete": { + await i.deferUpdate(); + return null; + } + case "cancel": { + await i.deferUpdate(); + if (newRole) return null; + else return initialData; + } } } } while (!back); @@ -383,6 +418,7 @@ const callback = async (interaction: CommandInteraction): Promise => { .setValue("delete") .setEmoji(getEmojiByName("TICKETS.ISSUE", "id") as APIMessageComponentEmoji) ); + console.log(page); const buttonRow = new ActionRowBuilder().addComponents( new ButtonBuilder() .setCustomId("back") @@ -422,7 +458,7 @@ const callback = async (interaction: CommandInteraction): Promise => { actionSelect.setDisabled(true); pageSelect.addOptions(new StringSelectMenuOptionBuilder().setLabel("No role menu pages").setValue("none")); } else { - page = Math.min(page, Object.keys(currentObject).length - 1); + page = Math.max(Math.min(page, currentObject.length - 1), 0); current = currentObject[page]!; embed.setDescription( `**Currently Editing:** ${current.name}\n\n` + diff --git a/src/reflex/guide.ts b/src/reflex/guide.ts index 1b463cf..93978e6 100644 --- a/src/reflex/guide.ts +++ b/src/reflex/guide.ts @@ -19,21 +19,23 @@ import { Embed } from "../utils/defaults.js"; export default async (guild: Guild | null, interaction?: CommandInteraction) => { let m: Message; if (guild) { - let c: GuildTextBasedChannel | null = guild.publicUpdatesChannel ? guild.publicUpdatesChannel : guild.systemChannel; + let c: GuildTextBasedChannel | null = guild.publicUpdatesChannel + ? guild.publicUpdatesChannel + : guild.systemChannel; c = c ? c : (guild.channels.cache.find( - (ch) => - [ - ChannelType.GuildText, - ChannelType.GuildAnnouncement, - ChannelType.PublicThread, - ChannelType.PrivateThread, - ChannelType.AnnouncementThread - ].includes(ch.type) && - ch.permissionsFor(guild.roles.everyone).has("SendMessages") && - ch.permissionsFor(guild.members.me!).has("EmbedLinks") - ) as GuildTextBasedChannel | undefined) ?? null; + (ch) => + [ + ChannelType.GuildText, + ChannelType.GuildAnnouncement, + ChannelType.PublicThread, + ChannelType.PrivateThread, + ChannelType.AnnouncementThread + ].includes(ch.type) && + ch.permissionsFor(guild.roles.everyone).has("SendMessages") && + ch.permissionsFor(guild.members.me!).has("EmbedLinks") + ) as GuildTextBasedChannel | undefined) ?? null; if (interaction) c = interaction.channel as GuildTextBasedChannel; if (!c) { return; diff --git a/src/utils/confirmationMessage.ts b/src/utils/confirmationMessage.ts index f5aaa6b..fc29b56 100644 --- a/src/utils/confirmationMessage.ts +++ b/src/utils/confirmationMessage.ts @@ -226,7 +226,8 @@ class confirmationMessage { try { component = await m.awaitMessageComponent({ filter: (i) => - i.user.id === this.interaction.user.id && (i.channel ? (i.channel!.id === this.interaction.channel!.id) : true), + i.user.id === this.interaction.user.id && + (i.channel ? i.channel!.id === this.interaction.channel!.id : true), time: 300000 }); } catch (e) { diff --git a/src/utils/dualCollector.ts b/src/utils/dualCollector.ts index 28fa2bc..b9f2c23 100644 --- a/src/utils/dualCollector.ts +++ b/src/utils/dualCollector.ts @@ -54,7 +54,7 @@ function defaultInteractionFilter(i: MessageComponentInteraction, user: User, m: return i.channel!.id === m.channel!.id && i.user.id === user.id; } function defaultModalFilter(i: ModalSubmitInteraction, user: User, m: Message) { - return (i.channel ? (i.channel!.id === m.channel!.id) : true) && i.user.id === user.id; + return (i.channel ? i.channel!.id === m.channel!.id : true) && i.user.id === user.id; } export async function modalInteractionCollector(