blob: 20972f461f5fb9a9d1b38077ec825189e3830166 [file] [log] [blame]
Skyler Greyda16adf2023-03-05 10:22:12 +00001import {
2 ActionRowBuilder,
3 APIMessageComponentEmoji,
4 ButtonBuilder,
5 ButtonInteraction,
6 ButtonStyle,
7 Collection,
8 CommandInteraction,
9 GuildMember,
10 Message,
11 ModalBuilder,
12 ModalSubmitInteraction,
13 PermissionsBitField,
14 Role,
15 RoleSelectMenuBuilder,
16 RoleSelectMenuInteraction,
17 SlashCommandSubcommandBuilder,
18 StringSelectMenuBuilder,
19 StringSelectMenuInteraction,
20 StringSelectMenuOptionBuilder,
21 TextInputBuilder,
22 TextInputStyle
23} from "discord.js";
TheCodedProfa112f612023-01-28 18:06:45 -050024import client from "../../utils/client.js";
TheCodedProfb5e9d552023-01-29 15:43:26 -050025import createPageIndicator, { createVerticalTrack } from "../../utils/createPageIndicator.js";
26import { LoadingEmbed } from "../../utils/defaults.js";
27import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
28import getEmojiByName from "../../utils/getEmojiByName.js";
29import ellipsis from "../../utils/ellipsis.js";
30import { modalInteractionCollector } from "../../utils/dualCollector.js";
TheCodedProfa112f612023-01-28 18:06:45 -050031
Skyler Greyda16adf2023-03-05 10:22:12 +000032const { renderRole } = client.logger;
TheCodedProf4f79da12023-01-31 16:50:37 -050033
TheCodedProfa112f612023-01-28 18:06:45 -050034const command = (builder: SlashCommandSubcommandBuilder) =>
Skyler Greyda16adf2023-03-05 10:22:12 +000035 builder.setName("tracks").setDescription("Manage the tracks for the server");
TheCodedProfa112f612023-01-28 18:06:45 -050036
TheCodedProfb5e9d552023-01-29 15:43:26 -050037interface ObjectSchema {
38 name: string;
39 retainPrevious: boolean;
40 nullable: boolean;
41 track: string[];
42 manageableBy: string[];
43}
44
Skyler Greyda16adf2023-03-05 10:22:12 +000045const editName = async (
46 i: ButtonInteraction,
47 interaction: StringSelectMenuInteraction | ButtonInteraction,
48 m: Message,
49 current?: string
50) => {
TheCodedProfb5e9d552023-01-29 15:43:26 -050051 let name = current ?? "";
52 const modal = new ModalBuilder()
53 .setTitle("Edit Name and Description")
54 .setCustomId("editNameDescription")
55 .addComponents(
Skyler Greyda16adf2023-03-05 10:22:12 +000056 new ActionRowBuilder<TextInputBuilder>().addComponents(
57 new TextInputBuilder()
58 .setLabel("Name")
59 .setCustomId("name")
60 .setPlaceholder("The name of the track (e.g. Moderators)")
61 .setStyle(TextInputStyle.Short)
62 .setValue(name)
63 .setRequired(true)
64 )
65 );
66 const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
67 new ButtonBuilder()
68 .setCustomId("back")
69 .setLabel("Back")
70 .setStyle(ButtonStyle.Secondary)
71 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
72 );
TheCodedProfb5e9d552023-01-29 15:43:26 -050073
Skyler Greyda16adf2023-03-05 10:22:12 +000074 await i.showModal(modal);
TheCodedProfb5e9d552023-01-29 15:43:26 -050075 await interaction.editReply({
76 embeds: [
77 new EmojiEmbed()
78 .setTitle("Tracks")
79 .setDescription("Modal opened. If you can't see it, click back and try again.")
80 .setStatus("Success")
81 ],
82 components: [button]
83 });
84
85 let out: ModalSubmitInteraction | null;
86 try {
Skyler Greyda16adf2023-03-05 10:22:12 +000087 out = (await modalInteractionCollector(m, interaction.user)) as ModalSubmitInteraction | null;
TheCodedProfb5e9d552023-01-29 15:43:26 -050088 } catch (e) {
89 console.error(e);
90 out = null;
91 }
Skyler Greyda16adf2023-03-05 10:22:12 +000092 if (!out) return name;
TheCodedProfb5e9d552023-01-29 15:43:26 -050093 if (out.isButton()) return name;
TheCodedProfb5e9d552023-01-29 15:43:26 -050094 name = out.fields.fields.find((f) => f.customId === "name")?.value ?? name;
Skyler Greyda16adf2023-03-05 10:22:12 +000095 return name;
96};
TheCodedProfb5e9d552023-01-29 15:43:26 -050097
Skyler Greyda16adf2023-03-05 10:22:12 +000098const reorderTracks = async (
99 interaction: ButtonInteraction,
100 m: Message,
101 roles: Collection<string, Role>,
102 currentObj: string[]
103) => {
104 const reorderRow = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
105 new StringSelectMenuBuilder()
106 .setCustomId("reorder")
107 .setPlaceholder("Select all roles in the order you want users to gain them (Lowest to highest rank).")
108 .setMinValues(currentObj.length)
109 .setMaxValues(currentObj.length)
110 .addOptions(
111 currentObj.map((o, i) =>
112 new StringSelectMenuOptionBuilder().setLabel(roles.get(o)!.name).setValue(i.toString())
TheCodedProfb5e9d552023-01-29 15:43:26 -0500113 )
Skyler Greyda16adf2023-03-05 10:22:12 +0000114 )
115 );
116 const buttonRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
117 new ButtonBuilder()
118 .setCustomId("back")
119 .setLabel("Back")
120 .setStyle(ButtonStyle.Secondary)
121 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
122 );
TheCodedProfb5e9d552023-01-29 15:43:26 -0500123 await interaction.editReply({
124 embeds: [
125 new EmojiEmbed()
126 .setTitle("Tracks")
127 .setDescription("Select all roles in the order you want users to gain them (Lowest to highest rank).")
128 .setStatus("Success")
129 ],
130 components: [reorderRow, buttonRow]
131 });
132 let out: StringSelectMenuInteraction | ButtonInteraction | null;
133 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000134 out = (await m.awaitMessageComponent({
TheCodedProfb5e9d552023-01-29 15:43:26 -0500135 filter: (i) => i.channel!.id === interaction.channel!.id,
136 time: 300000
Skyler Greyda16adf2023-03-05 10:22:12 +0000137 })) as StringSelectMenuInteraction | ButtonInteraction | null;
TheCodedProfb5e9d552023-01-29 15:43:26 -0500138 } catch (e) {
139 console.error(e);
140 out = null;
141 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000142 if (!out) return;
TheCodedProfb5e9d552023-01-29 15:43:26 -0500143 out.deferUpdate();
144 if (out.isButton()) return;
TheCodedProfb5e9d552023-01-29 15:43:26 -0500145 const values = out.values;
146
147 const newOrder: string[] = currentObj.map((_, i) => {
Skyler Greyda16adf2023-03-05 10:22:12 +0000148 const index = values.findIndex((v) => v === i.toString());
TheCodedProfb5e9d552023-01-29 15:43:26 -0500149 return currentObj[index];
150 }) as string[];
151
152 return newOrder;
Skyler Greyda16adf2023-03-05 10:22:12 +0000153};
TheCodedProfb5e9d552023-01-29 15:43:26 -0500154
Skyler Greyda16adf2023-03-05 10:22:12 +0000155const editTrack = async (
156 interaction: ButtonInteraction | StringSelectMenuInteraction,
157 message: Message,
158 roles: Collection<string, Role>,
159 current?: ObjectSchema
160) => {
TheCodedProf4f79da12023-01-31 16:50:37 -0500161 const isAdmin = (interaction.member!.permissions as PermissionsBitField).has("Administrator");
Skyler Greyda16adf2023-03-05 10:22:12 +0000162 if (!current) {
TheCodedProfb5e9d552023-01-29 15:43:26 -0500163 current = {
164 name: "",
165 retainPrevious: false,
166 nullable: false,
167 track: [],
168 manageableBy: []
Skyler Greyda16adf2023-03-05 10:22:12 +0000169 };
TheCodedProfb5e9d552023-01-29 15:43:26 -0500170 }
TheCodedProf4f79da12023-01-31 16:50:37 -0500171
Skyler Greyda16adf2023-03-05 10:22:12 +0000172 const roleSelect = new ActionRowBuilder<RoleSelectMenuBuilder>().addComponents(
173 new RoleSelectMenuBuilder().setCustomId("addRole").setPlaceholder("Select a role to add").setDisabled(!isAdmin)
174 );
TheCodedProfb5e9d552023-01-29 15:43:26 -0500175 let closed = false;
176 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000177 const editableRoles: string[] = current.track
178 .map((r) => {
179 if (
180 !(roles.get(r)!.position >= (interaction.member as GuildMember).roles.highest.position) ||
181 interaction.user.id === interaction.guild?.ownerId
182 )
183 return roles.get(r)!.name;
184 })
185 .filter((v) => v !== undefined) as string[];
186 const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
187 new StringSelectMenuBuilder()
188 .setCustomId("removeRole")
189 .setPlaceholder("Select a role to remove")
190 .setDisabled(!isAdmin)
191 .addOptions(
192 editableRoles.map((r, i) => {
193 return new StringSelectMenuOptionBuilder().setLabel(r).setValue(i.toString());
194 })
195 )
196 );
197 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
198 new ButtonBuilder()
199 .setCustomId("back")
200 .setLabel("Back")
201 .setStyle(ButtonStyle.Secondary)
202 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
203 new ButtonBuilder()
204 .setCustomId("edit")
205 .setLabel("Edit Name")
206 .setStyle(ButtonStyle.Primary)
207 .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
208 new ButtonBuilder()
209 .setCustomId("reorder")
210 .setLabel("Reorder")
211 .setDisabled(!isAdmin)
212 .setStyle(ButtonStyle.Primary)
213 .setEmoji(getEmojiByName("ICONS.REORDER", "id") as APIMessageComponentEmoji),
214 new ButtonBuilder()
215 .setCustomId("retainPrevious")
216 .setLabel("Retain Previous")
217 .setStyle(current.retainPrevious ? ButtonStyle.Success : ButtonStyle.Danger)
218 .setEmoji(
219 getEmojiByName(
220 "CONTROL." + (current.retainPrevious ? "TICK" : "CROSS"),
221 "id"
222 ) as APIMessageComponentEmoji
223 ),
224 new ButtonBuilder()
225 .setCustomId("nullable")
226 .setLabel(`Role ${current.nullable ? "Not " : ""}Required`)
227 .setStyle(current.nullable ? ButtonStyle.Success : ButtonStyle.Danger)
228 .setEmoji(
229 getEmojiByName("CONTROL." + (current.nullable ? "TICK" : "CROSS"), "id") as APIMessageComponentEmoji
230 )
TheCodedProf4f79da12023-01-31 16:50:37 -0500231 );
232
PineaFanb0d0c242023-02-05 10:59:45 +0000233 const allowed: boolean[] = [];
TheCodedProfb5e9d552023-01-29 15:43:26 -0500234 for (const role of current.track) {
235 const disabled: boolean =
236 roles.get(role)!.position >= (interaction.member as GuildMember).roles.highest.position;
Skyler Greyda16adf2023-03-05 10:22:12 +0000237 allowed.push(disabled);
TheCodedProfb5e9d552023-01-29 15:43:26 -0500238 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000239 const mapped = current.track.map((role) => roles.find((aRole) => aRole.id === role)!);
TheCodedProfb5e9d552023-01-29 15:43:26 -0500240
241 const embed = new EmojiEmbed()
242 .setTitle("Tracks")
243 .setDescription(
244 `**Currently Editing:** ${current.name}\n\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000245 `${getEmojiByName("CONTROL." + (current.nullable ? "CROSS" : "TICK"))} Members ${
246 current.nullable ? "don't " : ""
247 }need a role in this track\n` +
248 `${getEmojiByName("CONTROL." + (current.retainPrevious ? "TICK" : "CROSS"))} Members ${
249 current.retainPrevious ? "" : "don't "
250 }keep all roles below their current highest\n\n` +
251 createVerticalTrack(
252 mapped.map((role) => renderRole(role)),
253 new Array(current.track.length).fill(false),
254 allowed
255 )
TheCodedProfb5e9d552023-01-29 15:43:26 -0500256 )
Skyler Greyda16adf2023-03-05 10:22:12 +0000257 .setStatus("Success");
TheCodedProfb5e9d552023-01-29 15:43:26 -0500258
Skyler Greyda16adf2023-03-05 10:22:12 +0000259 const comps: ActionRowBuilder<RoleSelectMenuBuilder | ButtonBuilder | StringSelectMenuBuilder>[] = [
260 roleSelect,
261 buttons
262 ];
263 if (current.track.length >= 1) comps.splice(1, 0, selectMenu);
TheCodedProfd0a166d2023-02-19 00:04:53 -0500264
Skyler Greyda16adf2023-03-05 10:22:12 +0000265 interaction.editReply({ embeds: [embed], components: comps });
TheCodedProfb5e9d552023-01-29 15:43:26 -0500266
267 let out: ButtonInteraction | RoleSelectMenuInteraction | StringSelectMenuInteraction | null;
268
269 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000270 out = (await message.awaitMessageComponent({
TheCodedProfb5e9d552023-01-29 15:43:26 -0500271 filter: (i) => i.channel!.id === interaction.channel!.id,
272 time: 300000
Skyler Greyda16adf2023-03-05 10:22:12 +0000273 })) as ButtonInteraction | RoleSelectMenuInteraction | StringSelectMenuInteraction | null;
TheCodedProfb5e9d552023-01-29 15:43:26 -0500274 } catch (e) {
275 console.error(e);
276 out = null;
277 }
278
Skyler Greyda16adf2023-03-05 10:22:12 +0000279 if (!out) return;
TheCodedProfb5e9d552023-01-29 15:43:26 -0500280 if (out.isButton()) {
Skyler Greyda16adf2023-03-05 10:22:12 +0000281 switch (out.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000282 case "back": {
TheCodedProfd0a166d2023-02-19 00:04:53 -0500283 out.deferUpdate();
TheCodedProfb5e9d552023-01-29 15:43:26 -0500284 closed = true;
285 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000286 }
287 case "edit": {
TheCodedProfb5e9d552023-01-29 15:43:26 -0500288 current.name = (await editName(out, interaction, message, current.name))!;
289 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000290 }
291 case "reorder": {
TheCodedProfd0a166d2023-02-19 00:04:53 -0500292 out.deferUpdate();
TheCodedProfb5e9d552023-01-29 15:43:26 -0500293 current.track = (await reorderTracks(out, message, roles, current.track))!;
TheCodedProf4f79da12023-01-31 16:50:37 -0500294 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000295 }
296 case "retainPrevious": {
TheCodedProfd0a166d2023-02-19 00:04:53 -0500297 out.deferUpdate();
TheCodedProf4f79da12023-01-31 16:50:37 -0500298 current.retainPrevious = !current.retainPrevious;
299 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000300 }
301 case "nullable": {
TheCodedProfd0a166d2023-02-19 00:04:53 -0500302 out.deferUpdate();
TheCodedProf4f79da12023-01-31 16:50:37 -0500303 current.nullable = !current.nullable;
304 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000305 }
TheCodedProfb5e9d552023-01-29 15:43:26 -0500306 }
307 } else if (out.isStringSelectMenu()) {
308 out.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000309 switch (out.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000310 case "removeRole": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000311 const index = current.track.findIndex(
312 (v) => v === editableRoles[parseInt((out! as StringSelectMenuInteraction).values![0]!)]
313 );
TheCodedProfb5e9d552023-01-29 15:43:26 -0500314 current.track.splice(index, 1);
315 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000316 }
TheCodedProfb5e9d552023-01-29 15:43:26 -0500317 }
318 } else {
Skyler Greyda16adf2023-03-05 10:22:12 +0000319 switch (out.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000320 case "addRole": {
TheCodedProfb5e9d552023-01-29 15:43:26 -0500321 const role = out.values![0]!;
Skyler Greyda16adf2023-03-05 10:22:12 +0000322 if (!current.track.includes(role)) {
TheCodedProfb5e9d552023-01-29 15:43:26 -0500323 current.track.push(role);
TheCodedProfd0a166d2023-02-19 00:04:53 -0500324 } else {
Skyler Greyda16adf2023-03-05 10:22:12 +0000325 out.reply({ content: "That role is already on this track", ephemeral: true });
TheCodedProfb5e9d552023-01-29 15:43:26 -0500326 }
TheCodedProfb5e9d552023-01-29 15:43:26 -0500327 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000328 }
TheCodedProfb5e9d552023-01-29 15:43:26 -0500329 }
330 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000331 } while (!closed);
TheCodedProfb5e9d552023-01-29 15:43:26 -0500332 return current;
Skyler Greyda16adf2023-03-05 10:22:12 +0000333};
TheCodedProfa112f612023-01-28 18:06:45 -0500334
335const callback = async (interaction: CommandInteraction) => {
Skyler Greyda16adf2023-03-05 10:22:12 +0000336 const m = await interaction.reply({ embeds: LoadingEmbed, fetchReply: true, ephemeral: true });
TheCodedProfb5e9d552023-01-29 15:43:26 -0500337 const config = await client.database.guilds.read(interaction.guild!.id);
338 const tracks: ObjectSchema[] = config.tracks;
339 const roles = await interaction.guild!.roles.fetch();
TheCodedProfb5e9d552023-01-29 15:43:26 -0500340
341 let page = 0;
342 let closed = false;
343 let modified = false;
344
345 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000346 const embed = new EmojiEmbed().setTitle("Track Settings").setEmoji("TRACKS.ICON").setStatus("Success");
TheCodedProfb5e9d552023-01-29 15:43:26 -0500347 const noTracks = config.tracks.length === 0;
348 let current: ObjectSchema;
349
Skyler Greyda16adf2023-03-05 10:22:12 +0000350 const pageSelect = new StringSelectMenuBuilder().setCustomId("page").setPlaceholder("Select a track to manage");
TheCodedProfb5e9d552023-01-29 15:43:26 -0500351 const actionSelect = new StringSelectMenuBuilder()
352 .setCustomId("action")
353 .setPlaceholder("Perform an action")
354 .addOptions(
355 new StringSelectMenuOptionBuilder()
356 .setLabel("Edit")
357 .setDescription("Edit this track")
358 .setValue("edit")
359 .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
360 new StringSelectMenuOptionBuilder()
361 .setLabel("Delete")
362 .setDescription("Delete this track")
363 .setValue("delete")
364 .setEmoji(getEmojiByName("TICKETS.ISSUE", "id") as APIMessageComponentEmoji)
TheCodedProfb5e9d552023-01-29 15:43:26 -0500365 );
Skyler Greyda16adf2023-03-05 10:22:12 +0000366 const buttonRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
367 new ButtonBuilder()
368 .setCustomId("back")
369 .setStyle(ButtonStyle.Primary)
370 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
371 .setDisabled(page === 0),
372 new ButtonBuilder()
373 .setCustomId("next")
374 .setEmoji(getEmojiByName("CONTROL.RIGHT", "id") as APIMessageComponentEmoji)
375 .setStyle(ButtonStyle.Primary)
376 .setDisabled(page === tracks.length - 1),
377 new ButtonBuilder()
378 .setCustomId("add")
379 .setLabel("New Track")
380 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id") as APIMessageComponentEmoji)
381 .setStyle(ButtonStyle.Secondary)
382 .setDisabled(Object.keys(tracks).length >= 24),
383 new ButtonBuilder()
384 .setCustomId("save")
385 .setLabel("Save")
386 .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
387 .setStyle(ButtonStyle.Success)
388 .setDisabled(!modified)
389 );
390 if (noTracks) {
391 embed.setDescription(
392 "No tracks have been set up yet. Use the button below to add one.\n\n" +
393 createPageIndicator(1, 1, undefined, true)
TheCodedProfb5e9d552023-01-29 15:43:26 -0500394 );
395 pageSelect.setDisabled(true);
396 actionSelect.setDisabled(true);
Skyler Greyda16adf2023-03-05 10:22:12 +0000397 pageSelect.addOptions(new StringSelectMenuOptionBuilder().setLabel("No tracks").setValue("none"));
TheCodedProfb5e9d552023-01-29 15:43:26 -0500398 } else {
399 page = Math.min(page, Object.keys(tracks).length - 1);
400 current = tracks[page]!;
Skyler Greyda16adf2023-03-05 10:22:12 +0000401 const mapped = current.track.map((role) => roles.find((aRole) => aRole.id === role)!);
402 embed.setDescription(
403 `**Currently Editing:** ${current.name}\n\n` +
404 `${getEmojiByName("CONTROL." + (current.nullable ? "CROSS" : "TICK"))} Members ${
405 current.nullable ? "don't " : ""
406 }need a role in this track\n` +
407 `${getEmojiByName("CONTROL." + (current.retainPrevious ? "TICK" : "CROSS"))} Members ${
408 current.retainPrevious ? "" : "don't "
409 }keep all roles below their current highest\n\n` +
410 createVerticalTrack(
411 mapped.map((role) => renderRole(role)),
412 new Array(current.track.length).fill(false)
413 ) +
414 `\n${createPageIndicator(config.tracks.length, page)}`
TheCodedProfb5e9d552023-01-29 15:43:26 -0500415 );
416
417 pageSelect.addOptions(
418 tracks.map((key: ObjectSchema, index) => {
419 return new StringSelectMenuOptionBuilder()
420 .setLabel(ellipsis(key.name, 50))
421 .setDescription(ellipsis(roles.get(key.track[0]!)?.name!, 50))
422 .setValue(index.toString());
423 })
424 );
TheCodedProfb5e9d552023-01-29 15:43:26 -0500425 }
426
Skyler Greyda16adf2023-03-05 10:22:12 +0000427 await interaction.editReply({
428 embeds: [embed],
429 components: [
430 new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(actionSelect),
431 new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(pageSelect),
432 buttonRow
433 ]
434 });
TheCodedProfb5e9d552023-01-29 15:43:26 -0500435 let i: StringSelectMenuInteraction | ButtonInteraction;
436 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000437 i = (await m.awaitMessageComponent({
438 time: 300000,
439 filter: (i) =>
440 i.user.id === interaction.user.id && i.message.id === m.id && i.channelId === interaction.channelId
441 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProfb5e9d552023-01-29 15:43:26 -0500442 } catch (e) {
443 closed = true;
PineaFanb0d0c242023-02-05 10:59:45 +0000444 continue;
TheCodedProfb5e9d552023-01-29 15:43:26 -0500445 }
446
447 await i.deferUpdate();
448 if (i.isButton()) {
449 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000450 case "back": {
TheCodedProfb5e9d552023-01-29 15:43:26 -0500451 page--;
452 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000453 }
454 case "next": {
TheCodedProfb5e9d552023-01-29 15:43:26 -0500455 page++;
456 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000457 }
458 case "add": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000459 const newPage = await editTrack(i, m, roles);
460 if (!newPage) break;
TheCodedProfb5e9d552023-01-29 15:43:26 -0500461 tracks.push();
462 page = tracks.length - 1;
463 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000464 }
465 case "save": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000466 client.database.guilds.write(interaction.guild!.id, { tracks: tracks });
TheCodedProfb5e9d552023-01-29 15:43:26 -0500467 modified = false;
Skyler Grey16ecb172023-03-05 07:30:32 +0000468 await client.memory.forceUpdate(interaction.guild!.id);
TheCodedProfb5e9d552023-01-29 15:43:26 -0500469 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000470 }
TheCodedProfb5e9d552023-01-29 15:43:26 -0500471 }
472 } else if (i.isStringSelectMenu()) {
473 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000474 case "action": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000475 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000476 case "edit": {
477 const edited = await editTrack(i, m, roles, current!);
Skyler Greyda16adf2023-03-05 10:22:12 +0000478 if (!edited) break;
TheCodedProfb5e9d552023-01-29 15:43:26 -0500479 tracks[page] = edited;
480 modified = true;
481 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000482 }
483 case "delete": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000484 if (page === 0 && tracks.keys.length - 1 > 0) page++;
TheCodedProfb5e9d552023-01-29 15:43:26 -0500485 else page--;
486 tracks.splice(page, 1);
487 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000488 }
TheCodedProfb5e9d552023-01-29 15:43:26 -0500489 }
490 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000491 }
492 case "page": {
TheCodedProfb5e9d552023-01-29 15:43:26 -0500493 page = parseInt(i.values[0]!);
494 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000495 }
TheCodedProfb5e9d552023-01-29 15:43:26 -0500496 }
497 }
TheCodedProf01cba762023-02-18 15:55:05 -0500498 } while (!closed);
Skyler Greyda16adf2023-03-05 10:22:12 +0000499 await interaction.deleteReply();
500};
TheCodedProfa112f612023-01-28 18:06:45 -0500501
502const check = (interaction: CommandInteraction, _partial: boolean = false) => {
503 const member = interaction.member as GuildMember;
504 if (!member.permissions.has("ManageRoles"))
505 return "You must have the *Manage Server* permission to use this command";
506 return true;
507};
508
509export { command };
510export { callback };
511export { check };