diff --git a/src/commands/roles.ts b/src/commands/roles.ts index 414652b..9ea1a33 100644 --- a/src/commands/roles.ts +++ b/src/commands/roles.ts @@ -1,21 +1,37 @@ import { ModalActionRowComponentBuilder, ModalBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; import { Command } from '@sapphire/framework'; -import { ActionRowBuilder, TextInputBuilder, TextInputStyle } from 'discord.js'; +import { ActionRowBuilder, ButtonStyle, ComponentType, TextInputBuilder, TextInputStyle } from 'discord.js'; +import { RolesMessage } from '../lib/types'; @ApplyOptions({ description: 'Lets you configure a role message' }) export class UserCommand extends Command { public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => - builder // - .setName(this.name) - .setDescription(this.description) - .addSubcommand(builder => builder.setName('new').setDescription('Creates a new role message')) - .addSubcommand(builder => builder.setName('edit').setDescription('Edit an existing role message')) - .addSubcommand(builder => builder.setName('show').setDescription('Re-send an existing role message')) - , + registry.registerChatInputCommand( + (builder) => + builder // + .setName(this.name) + .setDescription(this.description) + .addSubcommand((builder) => builder.setName('new').setDescription('Creates a new role message')) + .addSubcommand((builder) => + builder + .setName('edit') + .setDescription('Edit an existing role message') + .addStringOption((b) => + b.setName('id').setDescription('The ID of the menu to edit. See all with /roles list').setRequired(true) + ) + ) + .addSubcommand((builder) => + builder + .setName('show') + .setDescription('Re-send an existing role message') + .addStringOption((b) => + b.setName('id').setDescription('The ID of the menu to edit. See all with /roles list').setRequired(true) + ) + ) + .addSubcommand((builder) => builder.setName('list').setDescription('Lists all available role menus.')), { guildIds: ['1030563119132594187'], idHints: ['1074474624672350279'] @@ -27,45 +43,90 @@ export class UserCommand extends Command { let subcommand = interaction.options.getSubcommand(true); switch (subcommand) { - case 'new': await this.new(interaction); break; - case 'edit': await this.edit(interaction); break; - case 'show': await this.show(interaction); break; + case 'new': + await this.new(interaction); + break; + case 'edit': + await this.edit(interaction); + break; + case 'show': + await this.show(interaction); + break; + case 'list': + await this.list(interaction); + break; } } private async new(interaction: Command.ChatInputCommandInteraction) { - const modal = new ModalBuilder() - .setCustomId('newEmbedEditorModal') - .setTitle('Embed Editor') + const modal = new ModalBuilder().setCustomId('newEmbedEditorModal').setTitle('Embed Editor'); - const embedTitle = new TextInputBuilder() - .setCustomId('embedTitle') - .setLabel('Title') - .setStyle(TextInputStyle.Short); - const embedDescription = new TextInputBuilder() - .setCustomId('embedDescription') - .setLabel('Description') - .setStyle(TextInputStyle.Paragraph) + const embedTitle = new TextInputBuilder().setCustomId('embedTitle').setLabel('Title').setStyle(TextInputStyle.Short); + const embedDescription = new TextInputBuilder().setCustomId('embedDescription').setLabel('Description').setStyle(TextInputStyle.Paragraph); const embedColor = new TextInputBuilder() .setCustomId('embedColor') .setLabel('Color') .setPlaceholder('RGB color for the embed (e.g #FF0000)') + .setStyle(TextInputStyle.Short); + + const buttonLabel = new TextInputBuilder() + .setCustomId('buttonLabel') + .setLabel('Button Label') + .setPlaceholder('The text to display on the "show roles" button') .setStyle(TextInputStyle.Short) + .setMaxLength(80); - let firstRow = new ActionRowBuilder().addComponents(embedTitle) - let secondRow = new ActionRowBuilder().addComponents(embedDescription) - let thirdRow = new ActionRowBuilder().addComponents(embedColor) + let firstRow = new ActionRowBuilder().addComponents(embedTitle); + let secondRow = new ActionRowBuilder().addComponents(embedDescription); + let thirdRow = new ActionRowBuilder().addComponents(embedColor); + let fourthRow = new ActionRowBuilder().addComponents(buttonLabel); - modal.addComponents(firstRow, secondRow, thirdRow) + modal.addComponents(firstRow, secondRow, thirdRow, fourthRow); - await interaction.showModal(modal) - } - - private async edit(interaction: Command.ChatInputCommandInteraction) { - await interaction.reply({content: 'edit', ephemeral: true}) + await interaction.showModal(modal); } private async show(interaction: Command.ChatInputCommandInteraction) { - await interaction.reply({content: 'show', ephemeral: true}) + let menuData = await RolesMessage.findByPk(Number(interaction.options.getString('id'))); + if (!menuData) { + return await interaction.reply({ content: 'No role menu exists with that ID.', ephemeral: true }); + } + if (menuData.dataValues.guildId != interaction.guild?.id) { + return await interaction.reply({ content: 'No role menu exists with that ID.', ephemeral: true }); + } + + let color = menuData.dataValues.embedColor ?? '0x36393E'; + let regex = /[0-9A-F]{6}/gi; + let matches = color.match(regex); + if (matches == null) color = '0x36393E'; + else color = `0x${matches[0]}`; + + await interaction.reply({ content: 'Ok.', ephemeral: true }); + await interaction.channel?.send({ + embeds: [{ title: menuData.dataValues.embedTitle ?? 'Generic Title', description: menuData.dataValues.embedDescription ?? 'Generic Description', color: Number(color) }], + components: [ + { + type: ComponentType.ActionRow, + components: [ + { + type: ComponentType.Button, + label: menuData.dataValues.buttonLabel ?? 'Select Roles', + customId: `showRoleSelector-${interaction.options.getString('id')}`, + style: ButtonStyle.Primary + } + ] + } + ] + }); + + return; } -} \ No newline at end of file + + private async edit(interaction: Command.ChatInputCommandInteraction) { + await interaction.reply({ content: 'edit', ephemeral: true }); + } + + private async list(interaction: Command.ChatInputCommandInteraction) { + await interaction.reply({ content: 'list', ephemeral: true }); + } +} diff --git a/src/lib/types.ts b/src/lib/types.ts index 7d40159..ec7a76a 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,5 +1,5 @@ import { container, LogLevel, SapphireClient } from '@sapphire/framework'; -import { GatewayIntentBits, Partials } from 'discord.js'; +import { GatewayIntentBits, Partials, Role } from 'discord.js'; import { Model, Sequelize } from 'sequelize'; export class SaplingClient extends SapphireClient { @@ -61,3 +61,8 @@ declare module '@sapphire/pieces' { } export class RolesMessage extends Model {} + +export type RolesChecker = { + role: Role, + has: boolean +} \ No newline at end of file diff --git a/src/listeners/buttons.ts b/src/listeners/buttons.ts index b17ae78..ec79270 100644 --- a/src/listeners/buttons.ts +++ b/src/listeners/buttons.ts @@ -1,6 +1,7 @@ import { ApplyOptions } from '@sapphire/decorators'; import { Listener, ListenerOptions } from '@sapphire/framework'; -import { ButtonStyle, ComponentType, Interaction, InteractionType, MessageComponentInteraction } from 'discord.js'; +import { ComponentType, GuildMember, Interaction, InteractionType } from 'discord.js'; +import { RolesChecker, RolesMessage } from '../lib/types'; @ApplyOptions({ event: 'interactionCreate' @@ -11,47 +12,50 @@ export class UserEvent extends Listener { switch (interaction.componentType) { case ComponentType.Button: { - if (interaction.customId == 'showRolesButton') await this.showRolesButton(interaction); + if (interaction.customId.startsWith('showRoleSelector-')) { + let id = interaction.customId.split('-')[1]; + let data = await RolesMessage.findByPk(id); + if (!data) { + return await interaction.reply({ content: 'Someone messed up big time.', ephemeral: true }); + } + let roleIds = data.dataValues.roles; + let roles = []; + for (const id of roleIds) { + let r = await interaction.guild?.roles.fetch(id); + if (r) { + roles.push(r); + } + } + + let userRoles = (interaction.member as GuildMember).roles.cache; + + let newRoles: RolesChecker[] = []; + for (const role of roles) { + if (userRoles.has(role.id)) { + newRoles.push({ role, has: true }); + } else { + newRoles.push({ role, has: false }); + } + } + + console.log(roles); + console.log(userRoles); + console.log(newRoles); + + if (data.dataValues.style == 'buttons') { + let size = 5; + let arrayOfArrays = []; + for (let i = 0; i < newRoles.length; i += size) { + arrayOfArrays.push(newRoles.slice(i, i + size)); + } + + // arrays with all the buttons and if the user has them are now in arrayOfArrays, figure out how to get that in a message later:tm: + } + + return; + } } } - } - - private async showRolesButton(interaction: MessageComponentInteraction) { - interaction.reply({ - content: 'This button lets you select pronoun roles. You can select multiple.', - allowedMentions: { parse: [] }, - ephemeral: true, - components: [ - { - type: ComponentType.ActionRow, - components: [ - { - type: ComponentType.Button, - style: ButtonStyle.Danger, - label: 'she/her', - customId: 'giveRole.' - }, - { - type: ComponentType.Button, - style: ButtonStyle.Success, - label: 'he/him', - customId: 'giveRole.1' - }, - { - type: ComponentType.Button, - style: ButtonStyle.Success, - label: 'they/them', - customId: 'giveRole.2' - }, - { - type: ComponentType.Button, - style: ButtonStyle.Success, - label: 'ask', - customId: 'giveRole.3' - }, - ] - } - ] - }); + return; } } diff --git a/src/listeners/rolesNew.ts b/src/listeners/rolesNew.ts index 8c23241..0786991 100644 --- a/src/listeners/rolesNew.ts +++ b/src/listeners/rolesNew.ts @@ -10,12 +10,12 @@ export class UserEvent extends Listener { if (interaction.customId != 'newEmbedEditorModal') return; await interaction.reply({ content: 'modal recieved', ephemeral: true }); - let regex = /[0-9A-F]{6}/gi; let title = interaction.fields.fields.get('embedTitle')?.value; let description = interaction.fields.fields.get('embedDescription')?.value; let color: string = interaction.fields.fields.get('embedColor')?.value as string; + let regex = /[0-9A-F]{6}/gi; let matches = color.match(regex); if (matches == null) color = '0x36393E'; else color = `0x${matches[0]}`;