blob: 58ab9d42201688c77eda4c7cdc225f2247e12cb9 [file] [log] [blame]
Skyler Grey75ea9172022-08-06 10:22:23 +01001import Discord, {
2 CommandInteraction,
Skyler Grey11236ba2022-08-08 21:13:33 +01003 Interaction,
Skyler Grey75ea9172022-08-06 10:22:23 +01004 Message,
5 MessageActionRow,
6 MessageButton,
Skyler Grey11236ba2022-08-08 21:13:33 +01007 MessageComponentInteraction,
8 ModalSubmitInteraction,
Skyler Grey75ea9172022-08-06 10:22:23 +01009 TextInputComponent
10} from "discord.js";
pineafan73a7c4a2022-07-24 10:38:04 +010011import { modalInteractionCollector } from "./dualCollector.js";
pineafan63fc5e22022-08-04 22:04:10 +010012import EmojiEmbed from "./generateEmojiEmbed.js";
pineafan8b4b17f2022-02-27 20:42:52 +000013import getEmojiByName from "./getEmojiByName.js";
pineafan4f164f32022-02-26 22:07:12 +000014
pineafan02ba0232022-07-24 22:16:15 +010015interface CustomBoolean<T> {
16 title: string;
17 disabled: boolean;
18 value: string | null;
pineafan63fc5e22022-08-04 22:04:10 +010019 emoji: string | undefined;
pineafan02ba0232022-07-24 22:16:15 +010020 active: boolean;
21 onClick: () => Promise<T>;
22 response: T | null;
23}
24
pineafan4f164f32022-02-26 22:07:12 +000025class confirmationMessage {
26 interaction: CommandInteraction;
pineafan63fc5e22022-08-04 22:04:10 +010027 title = "";
28 emoji = "";
29 description = "";
Skyler Grey75ea9172022-08-06 10:22:23 +010030 color: "Danger" | "Warning" | "Success" = "Success";
31 customButtons: Record<string, CustomBoolean<unknown>> = {};
pineafan63fc5e22022-08-04 22:04:10 +010032 inverted = false;
pineafan73a7c4a2022-07-24 10:38:04 +010033 reason: string | null = null;
pineafan4f164f32022-02-26 22:07:12 +000034
35 constructor(interaction: CommandInteraction) {
36 this.interaction = interaction;
pineafan4f164f32022-02-26 22:07:12 +000037 }
38
Skyler Grey75ea9172022-08-06 10:22:23 +010039 setTitle(title: string) {
40 this.title = title;
41 return this;
42 }
43 setEmoji(emoji: string) {
44 this.emoji = emoji;
45 return this;
46 }
47 setDescription(description: string) {
48 this.description = description;
49 return this;
50 }
51 setColor(color: "Danger" | "Warning" | "Success") {
52 this.color = color;
53 return this;
54 }
55 setInverted(inverted: boolean) {
56 this.inverted = inverted;
57 return this;
58 }
59 addCustomBoolean(
60 customId: string,
61 title: string,
62 disabled: boolean,
63 callback: () => Promise<unknown> = async () => null,
64 callbackClicked: string | null,
65 emoji?: string,
66 initial?: boolean
67 ) {
68 this.customButtons[customId] = {
69 title: title,
70 disabled: disabled,
71 value: callbackClicked,
72 emoji: emoji,
73 active: initial ?? false,
74 onClick: callback,
75 response: null
76 };
77 return this;
pineafan6fb3e072022-05-20 19:27:23 +010078 }
pineafan73a7c4a2022-07-24 10:38:04 +010079 addReasonButton(reason: string) {
80 this.reason = reason;
81 return this;
82 }
Skyler Grey11236ba2022-08-08 21:13:33 +010083 async send(editOnly?: boolean): Promise<{
84 success?: boolean;
85 cancelled?: boolean;
86 components?: Record<string, CustomBoolean<unknown>>;
87 newReason?: string;
88 }> {
Skyler Greya402d1c2022-08-13 23:18:16 +010089 let cancelled = false;
90 let success: boolean | undefined = undefined;
91 let returnComponents = false;
92 let newReason = undefined;
93
94 while (!cancelled && success === undefined && !returnComponents && !newReason) {
pineafan63fc5e22022-08-04 22:04:10 +010095 const fullComponents = [
pineafan02ba0232022-07-24 22:16:15 +010096 new Discord.MessageButton()
97 .setCustomId("yes")
98 .setLabel("Confirm")
99 .setStyle(this.inverted ? "SUCCESS" : "DANGER")
100 .setEmoji(getEmojiByName("CONTROL.TICK", "id")),
101 new Discord.MessageButton()
102 .setCustomId("no")
103 .setLabel("Cancel")
104 .setStyle("SECONDARY")
105 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
pineafan63fc5e22022-08-04 22:04:10 +0100106 ];
pineafan02ba0232022-07-24 22:16:15 +0100107 Object.entries(this.customButtons).forEach(([k, v]) => {
Skyler Grey75ea9172022-08-06 10:22:23 +0100108 const button = new Discord.MessageButton()
pineafan02ba0232022-07-24 22:16:15 +0100109 .setCustomId(k)
110 .setLabel(v.title)
111 .setStyle(v.active ? "SUCCESS" : "PRIMARY")
Skyler Grey75ea9172022-08-06 10:22:23 +0100112 .setDisabled(v.disabled);
Skyler Grey11236ba2022-08-08 21:13:33 +0100113 if (v.emoji !== undefined) button.setEmoji(getEmojiByName(v.emoji, "id"));
Skyler Grey75ea9172022-08-06 10:22:23 +0100114 fullComponents.push(button);
pineafan63fc5e22022-08-04 22:04:10 +0100115 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100116 if (this.reason !== null)
117 fullComponents.push(
118 new Discord.MessageButton()
119 .setCustomId("reason")
120 .setLabel("Edit Reason")
121 .setStyle("PRIMARY")
122 .setEmoji(getEmojiByName("ICONS.EDIT", "id"))
123 .setDisabled(false)
124 );
pineafan63fc5e22022-08-04 22:04:10 +0100125 const components = [];
pineafan02ba0232022-07-24 22:16:15 +0100126 for (let i = 0; i < fullComponents.length; i += 5) {
Skyler Grey11236ba2022-08-08 21:13:33 +0100127 components.push(new MessageActionRow().addComponents(fullComponents.slice(i, i + 5)));
pineafan02ba0232022-07-24 22:16:15 +0100128 }
pineafan63fc5e22022-08-04 22:04:10 +0100129 const object = {
pineafan377794f2022-04-18 19:01:01 +0100130 embeds: [
pineafan4edb7762022-06-26 19:21:04 +0100131 new EmojiEmbed()
pineafan377794f2022-04-18 19:01:01 +0100132 .setEmoji(this.emoji)
133 .setTitle(this.title)
Skyler Grey75ea9172022-08-06 10:22:23 +0100134 .setDescription(
135 this.description +
136 "\n\n" +
137 Object.values(this.customButtons)
138 .map((v) => {
139 if (v.value === null) return "";
140 return v.active ? `*${v.value}*\n` : "";
141 })
142 .join("")
143 )
pineafan377794f2022-04-18 19:01:01 +0100144 .setStatus(this.color)
pineafan377794f2022-04-18 19:01:01 +0100145 ],
pineafan02ba0232022-07-24 22:16:15 +0100146 components: components,
pineafan377794f2022-04-18 19:01:01 +0100147 ephemeral: true,
148 fetchReply: true
pineafan63fc5e22022-08-04 22:04:10 +0100149 };
Skyler Grey75ea9172022-08-06 10:22:23 +0100150 let m: Message;
pineafan02ba0232022-07-24 22:16:15 +0100151 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100152 if (editOnly) {
153 m = (await this.interaction.editReply(object)) as Message;
pineafan02ba0232022-07-24 22:16:15 +0100154 } else {
Skyler Grey11236ba2022-08-08 21:13:33 +0100155 m = (await this.interaction.reply(object)) as unknown as Message;
pineafan02ba0232022-07-24 22:16:15 +0100156 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100157 } catch {
Skyler Greya402d1c2022-08-13 23:18:16 +0100158 cancelled = true;
159 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100160 }
pineafan377794f2022-04-18 19:01:01 +0100161 let component;
162 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100163 component = await m.awaitMessageComponent({
164 filter: (m) => m.user.id === this.interaction.user.id,
165 time: 300000
166 });
pineafan377794f2022-04-18 19:01:01 +0100167 } catch (e) {
Skyler Greya402d1c2022-08-13 23:18:16 +0100168 success = false;
169 returnComponents = true;
170 continue;
pineafan377794f2022-04-18 19:01:01 +0100171 }
172 if (component.customId === "yes") {
173 component.deferUpdate();
pineafan63fc5e22022-08-04 22:04:10 +0100174 for (const v of Object.values(this.customButtons)) {
175 if (!v.active) continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100176 try {
177 v.response = await v.onClick();
178 } catch (e) {
179 console.log(e);
180 }
pineafan63fc5e22022-08-04 22:04:10 +0100181 }
Skyler Greya402d1c2022-08-13 23:18:16 +0100182 success = true;
183 returnComponents = true;
184 continue;
pineafan377794f2022-04-18 19:01:01 +0100185 } else if (component.customId === "no") {
186 component.deferUpdate();
Skyler Greya402d1c2022-08-13 23:18:16 +0100187 success = false;
188 returnComponents = true;
189 continue;
pineafan73a7c4a2022-07-24 10:38:04 +0100190 } else if (component.customId === "reason") {
Skyler Grey75ea9172022-08-06 10:22:23 +0100191 await component.showModal(
192 new Discord.Modal()
193 .setCustomId("modal")
194 .setTitle("Editing reason")
195 .addComponents(
196 new MessageActionRow<TextInputComponent>().addComponents(
197 new TextInputComponent()
198 .setCustomId("reason")
199 .setLabel("Reason")
200 .setMaxLength(2000)
201 .setRequired(false)
202 .setStyle("PARAGRAPH")
203 .setPlaceholder("Spammed in #general")
204 .setValue(this.reason ? this.reason : "")
205 )
206 )
207 );
pineafan73a7c4a2022-07-24 10:38:04 +0100208 await this.interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100209 embeds: [
210 new EmojiEmbed()
211 .setTitle(this.title)
Skyler Grey11236ba2022-08-08 21:13:33 +0100212 .setDescription("Modal opened. If you can't see it, click back and try again.")
Skyler Grey75ea9172022-08-06 10:22:23 +0100213 .setStatus(this.color)
214 .setEmoji(this.emoji)
215 ],
216 components: [
217 new MessageActionRow().addComponents([
218 new MessageButton()
219 .setLabel("Back")
220 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
221 .setStyle("PRIMARY")
222 .setCustomId("back")
223 ])
224 ]
pineafan73a7c4a2022-07-24 10:38:04 +0100225 });
226 let out;
227 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100228 out = await modalInteractionCollector(
229 m,
Skyler Grey11236ba2022-08-08 21:13:33 +0100230 (m: Interaction) =>
231 (m as MessageComponentInteraction | ModalSubmitInteraction).channelId ===
232 this.interaction.channelId,
Skyler Grey75ea9172022-08-06 10:22:23 +0100233 (m) => m.customId === "reason"
234 );
235 } catch (e) {
Skyler Greya402d1c2022-08-13 23:18:16 +0100236 cancelled = true;
237 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100238 }
Skyler Grey11236ba2022-08-08 21:13:33 +0100239 if (out === null) {
Skyler Greya402d1c2022-08-13 23:18:16 +0100240 cancelled = true;
241 continue;
Skyler Grey11236ba2022-08-08 21:13:33 +0100242 }
243 if (out instanceof ModalSubmitInteraction) {
Skyler Greya402d1c2022-08-13 23:18:16 +0100244 newReason = out.fields.getTextInputValue("reason");
245 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100246 } else {
Skyler Greya402d1c2022-08-13 23:18:16 +0100247 returnComponents = true;
248 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100249 }
pineafan02ba0232022-07-24 22:16:15 +0100250 } else {
251 component.deferUpdate();
Skyler Grey11236ba2022-08-08 21:13:33 +0100252 this.customButtons[component.customId]!.active = !this.customButtons[component.customId]!.active;
Skyler Greya402d1c2022-08-13 23:18:16 +0100253 returnComponents = true;
254 continue;
pineafan377794f2022-04-18 19:01:01 +0100255 }
pineafan8b4b17f2022-02-27 20:42:52 +0000256 }
Skyler Greya402d1c2022-08-13 23:18:16 +0100257 const returnValue: Awaited<ReturnType<typeof this.send>> = {};
258
259 if (returnComponents) returnValue.components = this.customButtons;
260 if (success !== undefined) returnValue.success = success;
261 if (cancelled) returnValue.cancelled = true;
262 if (newReason) returnValue.newReason = newReason;
263
264 return returnValue;
pineafan4f164f32022-02-26 22:07:12 +0000265 }
266}
267
pineafan73a7c4a2022-07-24 10:38:04 +0100268export default confirmationMessage;