blob: dfdc3fb01127e8d542a6578c268473237e359b69 [file] [log] [blame]
pineafan73a7c4a2022-07-24 10:38:04 +01001import Discord, { CommandInteraction, MessageActionRow, Message, MessageButton, TextInputComponent } from "discord.js";
2import { modalInteractionCollector } from "./dualCollector.js";
pineafan4edb7762022-06-26 19:21:04 +01003import EmojiEmbed from "./generateEmojiEmbed.js"
pineafan8b4b17f2022-02-27 20:42:52 +00004import getEmojiByName from "./getEmojiByName.js";
pineafan4f164f32022-02-26 22:07:12 +00005
pineafan02ba0232022-07-24 22:16:15 +01006
7interface CustomBoolean<T> {
8 title: string;
9 disabled: boolean;
10 value: string | null;
11 emoji: string | null;
12 active: boolean;
13 onClick: () => Promise<T>;
14 response: T | null;
15}
16
pineafan4f164f32022-02-26 22:07:12 +000017class confirmationMessage {
18 interaction: CommandInteraction;
pineafan73a7c4a2022-07-24 10:38:04 +010019 title: string = "";
20 emoji: string = "";
21 description: string = "";
22 color: string = "";
pineafan02ba0232022-07-24 22:16:15 +010023 customButtons: {[index:string]: CustomBoolean<unknown>} = {};
pineafan73a7c4a2022-07-24 10:38:04 +010024 inverted: boolean = false;
25 reason: string | null = null;
pineafan4f164f32022-02-26 22:07:12 +000026
27 constructor(interaction: CommandInteraction) {
28 this.interaction = interaction;
pineafan4f164f32022-02-26 22:07:12 +000029 }
30
31 setTitle(title: string) { this.title = title; return this }
32 setEmoji(emoji: string) { this.emoji = emoji; return this }
33 setDescription(description: string) { this.description = description; return this }
34 setColor(color: string) { this.color = color; return this }
pineafan167bde32022-05-19 19:33:46 +010035 setInverted(inverted: boolean) { this.inverted = inverted; return this }
pineafan02ba0232022-07-24 22:16:15 +010036 addCustomBoolean(customId: string, title: string, disabled: boolean, callback: () => Promise<unknown> | null, callbackClicked: string | null, emoji?: string, initial?: boolean) { this.customButtons[customId] = {
37 title: title,
38 disabled: disabled,
39 value: callbackClicked,
40 emoji: emoji,
41 active: initial ?? false,
42 onClick: callback ?? (() => null),
43 response: null,
44 }
pineafan6fb3e072022-05-20 19:27:23 +010045 return this;
46 }
pineafan73a7c4a2022-07-24 10:38:04 +010047 addReasonButton(reason: string) {
48 this.reason = reason;
49 return this;
50 }
pineafan8b4b17f2022-02-27 20:42:52 +000051 async send(editOnly?: boolean) {
pineafan377794f2022-04-18 19:01:01 +010052 while (true) {
pineafan02ba0232022-07-24 22:16:15 +010053 let fullComponents = [
54 new Discord.MessageButton()
55 .setCustomId("yes")
56 .setLabel("Confirm")
57 .setStyle(this.inverted ? "SUCCESS" : "DANGER")
58 .setEmoji(getEmojiByName("CONTROL.TICK", "id")),
59 new Discord.MessageButton()
60 .setCustomId("no")
61 .setLabel("Cancel")
62 .setStyle("SECONDARY")
63 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
64 ]
65 Object.entries(this.customButtons).forEach(([k, v]) => {
66 fullComponents.push(new Discord.MessageButton()
67 .setCustomId(k)
68 .setLabel(v.title)
69 .setStyle(v.active ? "SUCCESS" : "PRIMARY")
70 .setEmoji(getEmojiByName(v.emoji, "id"))
71 .setDisabled(v.disabled))
72 })
73 if (this.reason !== null) fullComponents.push(new Discord.MessageButton()
74 .setCustomId("reason")
75 .setLabel(`Edit Reason`)
76 .setStyle("PRIMARY")
77 .setEmoji(getEmojiByName("ICONS.EDIT", "id"))
78 .setDisabled(false)
79 )
80 let components = []
81 for (let i = 0; i < fullComponents.length; i += 5) {
82 components.push(new MessageActionRow().addComponents(fullComponents.slice(i, i + 5)));
83 }
pineafan377794f2022-04-18 19:01:01 +010084 let object = {
85 embeds: [
pineafan4edb7762022-06-26 19:21:04 +010086 new EmojiEmbed()
pineafan377794f2022-04-18 19:01:01 +010087 .setEmoji(this.emoji)
88 .setTitle(this.title)
pineafan02ba0232022-07-24 22:16:15 +010089 .setDescription(this.description + "\n\n" + Object.values(this.customButtons).map(v => {
90 if (v.value === null) return "";
91 return v.active ? `*${v.value}*\n` : "";
92 }).join(""))
pineafan377794f2022-04-18 19:01:01 +010093 .setStatus(this.color)
pineafan377794f2022-04-18 19:01:01 +010094 ],
pineafan02ba0232022-07-24 22:16:15 +010095 components: components,
pineafan377794f2022-04-18 19:01:01 +010096 ephemeral: true,
97 fetchReply: true
98 }
99 let m;
pineafan02ba0232022-07-24 22:16:15 +0100100 try {
101 if ( editOnly ) {
102 m = await this.interaction.editReply(object);
103 } else {
104 m = await this.interaction.reply(object)
105 }
106 } catch { return { cancelled: true } }
pineafan377794f2022-04-18 19:01:01 +0100107 let component;
108 try {
pineafanc6158ab2022-06-17 16:34:07 +0100109 component = await (m as Message).awaitMessageComponent({filter: (m) => m.user.id === this.interaction.user.id, time: 300000});
pineafan377794f2022-04-18 19:01:01 +0100110 } catch (e) {
pineafan02ba0232022-07-24 22:16:15 +0100111 return { success: false, components: this.customButtons };
pineafan377794f2022-04-18 19:01:01 +0100112 }
113 if (component.customId === "yes") {
114 component.deferUpdate();
pineafan02ba0232022-07-24 22:16:15 +0100115 for (let [k, v] of Object.entries(this.customButtons)) {
116 if (!v.active) continue
117 try { v.response = await v.onClick(); }
118 catch (e) { console.log(e) }
pineafan6fb3e072022-05-20 19:27:23 +0100119 };
pineafan02ba0232022-07-24 22:16:15 +0100120 return { success: true, components: this.customButtons };
pineafan377794f2022-04-18 19:01:01 +0100121 } else if (component.customId === "no") {
122 component.deferUpdate();
pineafan02ba0232022-07-24 22:16:15 +0100123 return { success: false, components: this.customButtons };
pineafan73a7c4a2022-07-24 10:38:04 +0100124 } else if (component.customId === "reason") {
125 await component.showModal(new Discord.Modal().setCustomId("modal").setTitle(`Editing reason`).addComponents(
pineafan02ba0232022-07-24 22:16:15 +0100126 new MessageActionRow<TextInputComponent>().addComponents(new TextInputComponent()
pineafan73a7c4a2022-07-24 10:38:04 +0100127 .setCustomId("reason")
128 .setLabel("Reason")
129 .setMaxLength(2000)
130 .setRequired(false)
131 .setStyle("PARAGRAPH")
132 .setPlaceholder("Spammed in #general")
133 .setValue(this.reason ? this.reason : "")
134 )
135 ))
136 await this.interaction.editReply({
137 embeds: [new EmojiEmbed()
138 .setTitle(this.title)
139 .setDescription("Modal opened. If you can't see it, click back and try again.")
140 .setStatus(this.color)
141 .setEmoji(this.emoji)
142 ], components: [new MessageActionRow().addComponents([new MessageButton()
143 .setLabel("Back")
144 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
145 .setStyle("PRIMARY")
146 .setCustomId("back")
147 ])]
148 });
149 let out;
150 try {
pineafane23c4ec2022-07-27 21:56:27 +0100151 out = await modalInteractionCollector(m, (m) => m.channel.id === this.interaction.channel.id, (m) => m.customId === "reason")
pineafan02ba0232022-07-24 22:16:15 +0100152 } catch (e) { return {} }
153 if (out.fields) { return { newReason: out.fields.getTextInputValue("reason") ?? "" }; }
154 else { return { newReason: this.reason } }
155 } else {
156 component.deferUpdate();
157 this.customButtons[component.customId].active = !this.customButtons[component.customId].active;
158 return { components: this.customButtons };
pineafan377794f2022-04-18 19:01:01 +0100159 }
pineafan8b4b17f2022-02-27 20:42:52 +0000160 }
pineafan4f164f32022-02-26 22:07:12 +0000161 }
162}
163
pineafan73a7c4a2022-07-24 10:38:04 +0100164export default confirmationMessage;