blob: 0b418545650fcf7f5bed5f2ba06a66e783dfe586 [file] [log] [blame]
TheCodedProfafca98b2023-01-17 22:25:43 -05001import type Discord from "discord.js";
Skyler Greyda16adf2023-03-05 10:22:12 +00002import {
3 ActionRowBuilder,
4 APIMessageComponentEmoji,
5 ButtonBuilder,
6 ButtonInteraction,
7 ButtonStyle,
8 CommandInteraction,
9 Message,
10 ModalBuilder,
11 RoleSelectMenuBuilder,
12 RoleSelectMenuInteraction,
13 StringSelectMenuBuilder,
14 StringSelectMenuInteraction,
15 StringSelectMenuOptionBuilder,
16 TextInputBuilder,
17 TextInputStyle
18} from "discord.js";
TheCodedProff86ba092023-01-27 17:10:07 -050019import type { SlashCommandSubcommandBuilder } from "discord.js";
TheCodedProf1c3ad3c2023-01-25 17:58:36 -050020import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
21import { LoadingEmbed } from "../../utils/defaults.js";
22import client from "../../utils/client.js";
23import getEmojiByName from "../../utils/getEmojiByName.js";
24import createPageIndicator from "../../utils/createPageIndicator.js";
25import { configToDropdown } from "../../actions/roleMenu.js";
TheCodedProff4facde2023-01-28 13:42:48 -050026import { modalInteractionCollector } from "../../utils/dualCollector.js";
TheCodedProfb5e9d552023-01-29 15:43:26 -050027import ellipsis from "../../utils/ellipsis.js";
TheCodedProfe92b9b52023-03-06 17:07:34 -050028import _ from "lodash";
TheCodedProfa112f612023-01-28 18:06:45 -050029
TheCodedProfe92b9b52023-03-06 17:07:34 -050030const isEqual = _.isEqual;
TheCodedProfa112f612023-01-28 18:06:45 -050031
Skyler Greyda16adf2023-03-05 10:22:12 +000032const command = (builder: SlashCommandSubcommandBuilder) => builder.setName("rolemenu").setDescription("rolemenu");
TheCodedProf1c3ad3c2023-01-25 17:58:36 -050033
34interface ObjectSchema {
35 name: string;
36 description: string;
37 min: number;
38 max: number;
39 options: {
40 name: string;
41 description: string | null;
42 role: string;
43 }[];
44}
45
TheCodedProff4facde2023-01-28 13:42:48 -050046const defaultRolePageConfig = {
47 name: "Role Menu Page",
48 description: "A new role menu page",
49 min: 0,
50 max: 0,
Skyler Greyda16adf2023-03-05 10:22:12 +000051 options: [{ name: "Role 1", description: null, role: "No role set" }]
52};
TheCodedProff4facde2023-01-28 13:42:48 -050053
TheCodedProfa112f612023-01-28 18:06:45 -050054const reorderRoleMenuPages = async (interaction: CommandInteraction, m: Message, currentObj: ObjectSchema[]) => {
Skyler Greyda16adf2023-03-05 10:22:12 +000055 const reorderRow = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
56 new StringSelectMenuBuilder()
57 .setCustomId("reorder")
58 .setPlaceholder("Select all pages in the order you want them to appear.")
59 .setMinValues(currentObj.length)
60 .setMaxValues(currentObj.length)
61 .addOptions(
62 currentObj.map((o, i) => new StringSelectMenuOptionBuilder().setLabel(o.name).setValue(i.toString()))
63 )
64 );
65 const buttonRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
66 new ButtonBuilder()
67 .setCustomId("back")
68 .setLabel("Back")
69 .setStyle(ButtonStyle.Secondary)
70 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
71 );
TheCodedProfa112f612023-01-28 18:06:45 -050072 await interaction.editReply({
73 embeds: [
74 new EmojiEmbed()
75 .setTitle("Role Menu")
76 .setDescription("Select pages in the order you want them to appear.")
77 .setStatus("Success")
78 ],
79 components: [reorderRow, buttonRow]
80 });
81 let out: StringSelectMenuInteraction | ButtonInteraction | null;
82 try {
Skyler Greyda16adf2023-03-05 10:22:12 +000083 out = (await m.awaitMessageComponent({
TheCodedProfa112f612023-01-28 18:06:45 -050084 filter: (i) => i.channel!.id === interaction.channel!.id,
85 time: 300000
Skyler Greyda16adf2023-03-05 10:22:12 +000086 })) as StringSelectMenuInteraction | ButtonInteraction | null;
TheCodedProfa112f612023-01-28 18:06:45 -050087 } catch (e) {
88 console.error(e);
89 out = null;
90 }
Skyler Greyda16adf2023-03-05 10:22:12 +000091 if (!out) return;
Skyler Greyf4f21c42023-03-08 14:36:29 +000092 await out.deferUpdate();
TheCodedProfa112f612023-01-28 18:06:45 -050093 if (out.isButton()) return;
TheCodedProfa112f612023-01-28 18:06:45 -050094 const values = out.values;
95
96 const newOrder: ObjectSchema[] = currentObj.map((_, i) => {
Skyler Greyda16adf2023-03-05 10:22:12 +000097 const index = values.findIndex((v) => v === i.toString());
TheCodedProfa112f612023-01-28 18:06:45 -050098 return currentObj[index];
99 }) as ObjectSchema[];
100
101 return newOrder;
Skyler Greyda16adf2023-03-05 10:22:12 +0000102};
TheCodedProfa112f612023-01-28 18:06:45 -0500103
Skyler Greyda16adf2023-03-05 10:22:12 +0000104const editNameDescription = async (
105 i: ButtonInteraction,
106 interaction: StringSelectMenuInteraction | ButtonInteraction,
107 m: Message,
108 data: { name?: string; description?: string }
109) => {
110 let { name, description } = data;
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500111 const modal = new ModalBuilder()
112 .setTitle("Edit Name and Description")
113 .setCustomId("editNameDescription")
114 .addComponents(
Skyler Greyda16adf2023-03-05 10:22:12 +0000115 new ActionRowBuilder<TextInputBuilder>().addComponents(
116 new TextInputBuilder()
117 .setLabel("Name")
118 .setCustomId("name")
119 .setPlaceholder("The name of the role (e.g. Programmer)")
120 .setStyle(TextInputStyle.Short)
121 .setValue(name ?? "")
122 .setRequired(true)
pineafan72659cc2023-05-28 13:36:44 +0100123 .setMaxLength(100)
Skyler Greyda16adf2023-03-05 10:22:12 +0000124 ),
125 new ActionRowBuilder<TextInputBuilder>().addComponents(
126 new TextInputBuilder()
127 .setLabel("Description")
128 .setCustomId("description")
129 .setPlaceholder("A short description of the role (e.g. A role for people who code)")
130 .setStyle(TextInputStyle.Short)
131 .setValue(description ?? "")
pineafan72659cc2023-05-28 13:36:44 +0100132 .setRequired(false)
133 .setMaxLength(100)
Skyler Greyda16adf2023-03-05 10:22:12 +0000134 )
135 );
136 const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
137 new ButtonBuilder()
138 .setCustomId("back")
139 .setLabel("Back")
140 .setStyle(ButtonStyle.Secondary)
141 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
142 );
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500143
Skyler Greyda16adf2023-03-05 10:22:12 +0000144 await i.showModal(modal);
TheCodedProff4facde2023-01-28 13:42:48 -0500145 await interaction.editReply({
146 embeds: [
147 new EmojiEmbed()
148 .setTitle("Role Menu")
149 .setDescription("Modal opened. If you can't see it, click back and try again.")
150 .setStatus("Success")
151 ],
152 components: [button]
153 });
154
155 let out: Discord.ModalSubmitInteraction | null;
156 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000157 out = (await modalInteractionCollector(m, interaction.user)) as Discord.ModalSubmitInteraction | null;
TheCodedProff4facde2023-01-28 13:42:48 -0500158 } catch (e) {
159 console.error(e);
160 out = null;
161 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000162 if (!out) return [name, description];
TheCodedProff4facde2023-01-28 13:42:48 -0500163 if (out.isButton()) return [name, description];
TheCodedProff4facde2023-01-28 13:42:48 -0500164 name = out.fields.fields.find((f) => f.customId === "name")?.value ?? name;
pineafan72659cc2023-05-28 13:36:44 +0100165 description = out.fields.fields.find((f) => f.customId === "description")?.value ?? "";
Skyler Greyda16adf2023-03-05 10:22:12 +0000166 return [name, description];
167};
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500168
TheCodedProf7a83f762023-03-06 17:17:00 -0500169const defaultRoleMenuData = {
pineafan72659cc2023-05-28 13:36:44 +0100170 name: "New Page",
171 description: "",
TheCodedProf7a83f762023-03-06 17:17:00 -0500172 min: 0,
pineafan72659cc2023-05-28 13:36:44 +0100173 max: 1,
TheCodedProf7a83f762023-03-06 17:17:00 -0500174 options: []
175};
176
Skyler Greyda16adf2023-03-05 10:22:12 +0000177const editRoleMenuPage = async (
178 interaction: StringSelectMenuInteraction | ButtonInteraction,
179 m: Message,
180 data?: ObjectSchema
181): Promise<ObjectSchema | null> => {
pineafan1e462ab2023-03-07 21:34:06 +0000182 if (!data) data = _.cloneDeep(defaultRoleMenuData);
Skyler Greyda16adf2023-03-05 10:22:12 +0000183 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
184 new ButtonBuilder()
185 .setCustomId("back")
186 .setLabel("Back")
187 .setStyle(ButtonStyle.Secondary)
188 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
189 new ButtonBuilder()
190 .setCustomId("edit")
191 .setLabel("Edit")
192 .setStyle(ButtonStyle.Primary)
193 .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
194 new ButtonBuilder()
195 .setCustomId("addRole")
196 .setLabel("Add Role")
197 .setStyle(ButtonStyle.Secondary)
198 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id") as APIMessageComponentEmoji)
199 );
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500200
Skyler Greyda16adf2023-03-05 10:22:12 +0000201 let back = false;
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500202 do {
pineafan72659cc2023-05-28 13:36:44 +0100203 const noRoles = data.options.length === 0;
204 const previewSelect = configToDropdown(
205 "Edit Roles",
206 {
207 name: data.name,
208 description: data.description,
209 min: 1,
210 max: 1,
211 options: noRoles ? [{ name: "Role 1", description: null, role: "No role set" }] : data.options
212 },
213 undefined,
214 noRoles
215 );
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500216 const embed = new EmojiEmbed()
217 .setTitle(`${data.name}`)
218 .setStatus("Success")
219 .setDescription(
220 `**Description:**\n> ${data.description}\n\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000221 `**Min:** ${data.min}` +
222 (data.min === 0 ? " (Members will be given a skip button)" : "") +
223 "\n" +
pineafan72659cc2023-05-28 13:36:44 +0100224 `**Max:** ${data.max}\n` +
225 `\n**Roles:** ${data.options.length === 0 ? "*No roles set*" : data.options.length}`
Skyler Greyda16adf2023-03-05 10:22:12 +0000226 );
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500227
Skyler Greyf4f21c42023-03-08 14:36:29 +0000228 await interaction.editReply({ embeds: [embed], components: [previewSelect, buttons] });
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500229 let i: StringSelectMenuInteraction | ButtonInteraction;
230 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000231 i = (await m.awaitMessageComponent({
232 time: 300000,
233 filter: (i) =>
234 i.user.id === interaction.user.id && i.message.id === m.id && i.channelId === interaction.channelId
235 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500236 } catch (e) {
237 back = true;
238 break;
239 }
240
241 if (i.isStringSelectMenu()) {
Skyler Greyda16adf2023-03-05 10:22:12 +0000242 if (i.customId === "roles") {
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500243 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000244 await createRoleMenuOptionPage(
245 interaction,
246 m,
pineafan72659cc2023-05-28 13:36:44 +0100247 data.options.find((o) => o.role === (i as StringSelectMenuInteraction).values[0]),
248 false
Skyler Greyda16adf2023-03-05 10:22:12 +0000249 );
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500250 }
251 } else if (i.isButton()) {
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500252 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000253 case "back": {
TheCodedProff4facde2023-01-28 13:42:48 -0500254 await i.deferUpdate();
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500255 back = true;
256 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000257 }
258 case "edit": {
259 const [name, description] = await editNameDescription(i, interaction, m, data);
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500260 data.name = name ? name : data.name;
261 data.description = description ? description : data.description;
262 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000263 }
264 case "addRole": {
TheCodedProff4facde2023-01-28 13:42:48 -0500265 await i.deferUpdate();
pineafan72659cc2023-05-28 13:36:44 +0100266 const out = await createRoleMenuOptionPage(interaction, m, undefined, true);
267 if (out) data.options.push(out);
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500268 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000269 }
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500270 }
271 }
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500272 } while (!back);
Skyler Greyda16adf2023-03-05 10:22:12 +0000273 if (isEqual(data, defaultRolePageConfig)) return null;
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500274 return data;
Skyler Greyda16adf2023-03-05 10:22:12 +0000275};
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500276
Skyler Greyda16adf2023-03-05 10:22:12 +0000277const createRoleMenuOptionPage = async (
278 interaction: StringSelectMenuInteraction | ButtonInteraction,
279 m: Message,
pineafan72659cc2023-05-28 13:36:44 +0100280 data?: { name: string; description: string | null; role: string },
281 newRole: boolean = false
Skyler Greyda16adf2023-03-05 10:22:12 +0000282) => {
pineafan72659cc2023-05-28 13:36:44 +0100283 const initialData = _.cloneDeep(data);
Skyler Greyda16adf2023-03-05 10:22:12 +0000284 const { renderRole } = client.logger;
285 if (!data)
286 data = {
287 name: "New role Menu Option",
288 description: null,
289 role: ""
290 };
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500291 let back = false;
Skyler Greyda16adf2023-03-05 10:22:12 +0000292 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
293 new ButtonBuilder()
294 .setCustomId("back")
pineafan72659cc2023-05-28 13:36:44 +0100295 .setLabel(newRole ? "Add" : "Back")
296 .setStyle(newRole ? ButtonStyle.Success : ButtonStyle.Secondary)
297 .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji),
Skyler Greyda16adf2023-03-05 10:22:12 +0000298 new ButtonBuilder()
299 .setCustomId("edit")
300 .setLabel("Edit Details")
301 .setStyle(ButtonStyle.Primary)
pineafan72659cc2023-05-28 13:36:44 +0100302 .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
303 new ButtonBuilder()
304 .setCustomId("delete")
305 .setLabel("Delete")
306 .setStyle(ButtonStyle.Danger)
307 .setEmoji(getEmojiByName("TICKETS.ISSUE", "id") as APIMessageComponentEmoji),
308 new ButtonBuilder()
309 .setCustomId("cancel")
310 .setLabel("Cancel")
311 .setStyle(ButtonStyle.Secondary)
312 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
Skyler Greyda16adf2023-03-05 10:22:12 +0000313 );
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500314 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000315 const roleSelect = new RoleSelectMenuBuilder()
316 .setCustomId("role")
pineafan72659cc2023-05-28 13:36:44 +0100317 .setPlaceholder(data.role ? "Change role to" : "Select a role");
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500318 const embed = new EmojiEmbed()
PineaFanb0d0c242023-02-05 10:59:45 +0000319 .setTitle(`${data.name}`)
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500320 .setStatus("Success")
321 .setDescription(
322 `**Description:**\n> ${data.description ?? "No description set"}\n\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000323 `**Role:** ${
324 data.role ? renderRole((await interaction.guild!.roles.fetch(data.role))!) : "No role set"
325 }\n`
326 );
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500327
Skyler Greyf4f21c42023-03-08 14:36:29 +0000328 await interaction.editReply({
Skyler Greyda16adf2023-03-05 10:22:12 +0000329 embeds: [embed],
330 components: [new ActionRowBuilder<RoleSelectMenuBuilder>().addComponents(roleSelect), buttons]
331 });
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500332
333 let i: RoleSelectMenuInteraction | ButtonInteraction;
334 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000335 i = (await m.awaitMessageComponent({
336 time: 300000,
337 filter: (i) =>
338 i.user.id === interaction.user.id && i.message.id === m.id && i.channelId === interaction.channelId
339 })) as ButtonInteraction | RoleSelectMenuInteraction;
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500340 } catch (e) {
341 back = true;
342 break;
343 }
344
345 if (i.isRoleSelectMenu()) {
Skyler Greyda16adf2023-03-05 10:22:12 +0000346 if (i.customId === "role") {
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500347 await i.deferUpdate();
348 data.role = (i as RoleSelectMenuInteraction).values[0]!;
pineafan72659cc2023-05-28 13:36:44 +0100349 await interaction.editReply({
350 embeds: [
351 new EmojiEmbed().setTitle(`Applying changes`).setStatus("Danger").setEmoji("NUCLEUS.LOADING")
352 ],
353 components: []
354 });
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500355 }
356 } else if (i.isButton()) {
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500357 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000358 case "back": {
TheCodedProff4facde2023-01-28 13:42:48 -0500359 await i.deferUpdate();
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500360 back = true;
361 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000362 }
363 case "edit": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000364 const [name, description] = await editNameDescription(
365 i,
366 interaction,
367 m,
368 data as { name: string; description: string }
369 );
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500370 data.name = name ? name : data.name;
371 data.description = description ? description : data.description;
372 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000373 }
pineafan72659cc2023-05-28 13:36:44 +0100374 case "delete": {
375 await i.deferUpdate();
376 return null;
377 }
378 case "cancel": {
379 await i.deferUpdate();
380 if (newRole) return null;
381 else return initialData;
382 }
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500383 }
384 }
385 } while (!back);
386 return data;
Skyler Greyda16adf2023-03-05 10:22:12 +0000387};
pineafanda6e5342022-07-03 10:03:16 +0100388
pineafan63fc5e22022-08-04 22:04:10 +0100389const callback = async (interaction: CommandInteraction): Promise<void> => {
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500390 if (!interaction.guild) return;
Skyler Greyda16adf2023-03-05 10:22:12 +0000391 const m = await interaction.reply({ embeds: LoadingEmbed, ephemeral: true, fetchReply: true });
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500392
393 let page = 0;
394 let closed = false;
395 const config = await client.database.guilds.read(interaction.guild.id);
TheCodedProfe92b9b52023-03-06 17:07:34 -0500396 let currentObject: ObjectSchema[] = _.cloneDeep(config.roleMenu.options);
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500397 let modified = false;
398 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000399 const embed = new EmojiEmbed().setTitle("Role Menu").setEmoji("GUILD.GREEN").setStatus("Success");
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500400 const noRoleMenus = currentObject.length === 0;
401 let current: ObjectSchema;
402
403 const pageSelect = new StringSelectMenuBuilder()
404 .setCustomId("page")
405 .setPlaceholder("Select a Role Menu page to manage");
406 const actionSelect = new StringSelectMenuBuilder()
407 .setCustomId("action")
408 .setPlaceholder("Perform an action")
409 .addOptions(
410 new StringSelectMenuOptionBuilder()
411 .setLabel("Edit")
412 .setDescription("Edit this page")
413 .setValue("edit")
414 .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
415 new StringSelectMenuOptionBuilder()
416 .setLabel("Delete")
417 .setDescription("Delete this page")
418 .setValue("delete")
419 .setEmoji(getEmojiByName("TICKETS.ISSUE", "id") as APIMessageComponentEmoji)
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500420 );
pineafan72659cc2023-05-28 13:36:44 +0100421 console.log(page);
Skyler Greyda16adf2023-03-05 10:22:12 +0000422 const buttonRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
423 new ButtonBuilder()
424 .setCustomId("back")
425 .setStyle(ButtonStyle.Primary)
426 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
427 .setDisabled(page === 0),
428 new ButtonBuilder()
429 .setCustomId("next")
430 .setEmoji(getEmojiByName("CONTROL.RIGHT", "id") as APIMessageComponentEmoji)
431 .setStyle(ButtonStyle.Primary)
TheCodedProfe92b9b52023-03-06 17:07:34 -0500432 .setDisabled(page === Object.keys(currentObject).length - 1 || noRoleMenus),
Skyler Greyda16adf2023-03-05 10:22:12 +0000433 new ButtonBuilder()
434 .setCustomId("add")
435 .setLabel("New Page")
436 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id") as APIMessageComponentEmoji)
437 .setStyle(ButtonStyle.Secondary)
438 .setDisabled(Object.keys(currentObject).length >= 24),
439 new ButtonBuilder()
440 .setCustomId("reorder")
441 .setLabel("Reorder Pages")
442 .setEmoji(getEmojiByName("ICONS.REORDER", "id") as APIMessageComponentEmoji)
443 .setStyle(ButtonStyle.Secondary)
444 .setDisabled(Object.keys(currentObject).length <= 1),
445 new ButtonBuilder()
446 .setCustomId("save")
447 .setLabel("Save")
448 .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
449 .setStyle(ButtonStyle.Success)
450 .setDisabled(!modified)
451 );
452 if (noRoleMenus) {
453 embed.setDescription(
454 "No role menu pages have been set up yet. Use the button below to add one.\n\n" +
455 createPageIndicator(1, 1, undefined, true)
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500456 );
457 pageSelect.setDisabled(true);
458 actionSelect.setDisabled(true);
Skyler Greyda16adf2023-03-05 10:22:12 +0000459 pageSelect.addOptions(new StringSelectMenuOptionBuilder().setLabel("No role menu pages").setValue("none"));
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500460 } else {
pineafan72659cc2023-05-28 13:36:44 +0100461 page = Math.max(Math.min(page, currentObject.length - 1), 0);
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500462 current = currentObject[page]!;
Skyler Greyda16adf2023-03-05 10:22:12 +0000463 embed.setDescription(
464 `**Currently Editing:** ${current.name}\n\n` +
465 `**Description:**\n> ${current.description}\n` +
466 `\n\n${createPageIndicator(Object.keys(config.roleMenu.options).length, page)}`
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500467 );
468
469 pageSelect.addOptions(
470 currentObject.map((key: ObjectSchema, index) => {
471 return new StringSelectMenuOptionBuilder()
472 .setLabel(ellipsis(key.name, 50))
473 .setDescription(ellipsis(key.description, 50))
474 .setValue(index.toString());
475 })
476 );
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500477 }
478
Skyler Greyda16adf2023-03-05 10:22:12 +0000479 await interaction.editReply({
480 embeds: [embed],
481 components: [
482 new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(actionSelect),
483 new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(pageSelect),
484 buttonRow
485 ]
486 });
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500487 let i: StringSelectMenuInteraction | ButtonInteraction;
488 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000489 i = (await m.awaitMessageComponent({
490 time: 300000,
491 filter: (i) =>
492 i.user.id === interaction.user.id && i.message.id === m.id && i.channelId === interaction.channelId
493 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500494 } catch (e) {
495 closed = true;
PineaFanb0d0c242023-02-05 10:59:45 +0000496 continue;
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500497 }
498
499 await i.deferUpdate();
500 if (i.isButton()) {
501 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000502 case "back": {
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500503 page--;
504 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000505 }
506 case "next": {
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500507 page++;
508 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000509 }
510 case "add": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000511 const newPage = await editRoleMenuPage(i, m);
TheCodedProf7a83f762023-03-06 17:17:00 -0500512 if (_.isEqual(newPage, defaultRoleMenuData)) break;
TheCodedProff4facde2023-01-28 13:42:48 -0500513 currentObject.push();
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500514 page = currentObject.length - 1;
515 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000516 }
517 case "reorder": {
518 const reordered = await reorderRoleMenuPages(interaction, m, currentObject);
Skyler Greyda16adf2023-03-05 10:22:12 +0000519 if (!reordered) break;
TheCodedProfa112f612023-01-28 18:06:45 -0500520 currentObject = reordered;
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500521 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000522 }
523 case "save": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000524 await client.database.guilds.write(interaction.guild.id, { "roleMenu.options": currentObject });
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500525 modified = false;
Skyler Grey16ecb172023-03-05 07:30:32 +0000526 await client.memory.forceUpdate(interaction.guild.id);
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500527 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000528 }
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500529 }
530 } else if (i.isStringSelectMenu()) {
531 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000532 case "action": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000533 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000534 case "edit": {
535 const edited = await editRoleMenuPage(i, m, current!);
Skyler Greyda16adf2023-03-05 10:22:12 +0000536 if (!edited) break;
TheCodedProff4facde2023-01-28 13:42:48 -0500537 currentObject[page] = edited;
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500538 modified = true;
539 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000540 }
541 case "delete": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000542 if (page === 0 && currentObject.keys.length - 1 > 0) page++;
TheCodedProff4facde2023-01-28 13:42:48 -0500543 else page--;
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500544 currentObject.splice(page, 1);
545 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000546 }
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500547 }
548 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000549 }
550 case "page": {
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500551 page = parseInt(i.values[0]!);
552 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000553 }
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500554 }
555 }
TheCodedProf01cba762023-02-18 15:55:05 -0500556 } while (!closed);
Skyler Greyda16adf2023-03-05 10:22:12 +0000557 await interaction.deleteReply();
pineafan63fc5e22022-08-04 22:04:10 +0100558};
pineafanda6e5342022-07-03 10:03:16 +0100559
TheCodedProff86ba092023-01-27 17:10:07 -0500560const check = (interaction: CommandInteraction, _partial: boolean = false) => {
Skyler Grey75ea9172022-08-06 10:22:23 +0100561 const member = interaction.member as Discord.GuildMember;
PineaFan0d06edc2023-01-17 22:10:31 +0000562 if (!member.permissions.has("ManageRoles"))
563 return "You must have the *Manage Roles* permission to use this command";
pineafanda6e5342022-07-03 10:03:16 +0100564 return true;
pineafan63fc5e22022-08-04 22:04:10 +0100565};
pineafanda6e5342022-07-03 10:03:16 +0100566
567export { command };
568export { callback };
Skyler Grey75ea9172022-08-06 10:22:23 +0100569export { check };