blob: 3c6515d4c9c0806e5a77de35e81a4a61351f0dbb [file] [log] [blame]
pineafan63fc5e22022-08-04 22:04:10 +01001import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
pineafan6702cef2022-06-13 17:52:37 +01002import getEmojiByName from "../../utils/getEmojiByName.js";
pineafan4edb7762022-06-26 19:21:04 +01003import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
pineafan6702cef2022-06-13 17:52:37 +01004import confirmationMessage from "../../utils/confirmationMessage.js";
Skyler Grey75ea9172022-08-06 10:22:23 +01005import Discord, {
6 CommandInteraction,
7 GuildChannel,
8 Message,
9 MessageActionRow,
10 MessageActionRowComponent,
11 MessageButton,
12 MessageComponentInteraction,
13 MessageSelectMenu,
14 Role,
15 SelectMenuInteraction,
16 TextInputComponent
17} from "discord.js";
Skyler Grey11236ba2022-08-08 21:13:33 +010018import { SelectMenuOption, SlashCommandSubcommandBuilder } from "@discordjs/builders";
Skyler Greyc634e2b2022-08-06 17:50:48 +010019import { ChannelType } from "discord-api-types/v9";
pineafan6702cef2022-06-13 17:52:37 +010020import client from "../../utils/client.js";
Skyler Grey11236ba2022-08-08 21:13:33 +010021import { toHexInteger, toHexArray, tickets as ticketTypes } from "../../utils/calculate.js";
pineafan63fc5e22022-08-04 22:04:10 +010022import { capitalize } from "../../utils/generateKeyValueList.js";
pineafan6702cef2022-06-13 17:52:37 +010023import { modalInteractionCollector } from "../../utils/dualCollector.js";
Skyler Grey75ea9172022-08-06 10:22:23 +010024import { GuildConfig } from "../../utils/database.js";
pineafan4f164f32022-02-26 22:07:12 +000025
Skyler Grey75ea9172022-08-06 10:22:23 +010026const command = (builder: SlashCommandSubcommandBuilder) =>
27 builder
28 .setName("tickets")
Skyler Grey11236ba2022-08-08 21:13:33 +010029 .setDescription("Shows settings for tickets | Use no arguments to manage custom types")
Skyler Grey75ea9172022-08-06 10:22:23 +010030 .addStringOption((option) =>
31 option
32 .setName("enabled")
33 .setDescription("If users should be able to create tickets")
34 .setRequired(false)
35 .addChoices([
36 ["Yes", "yes"],
37 ["No", "no"]
38 ])
39 )
40 .addChannelOption((option) =>
41 option
42 .setName("category")
43 .setDescription("The category where tickets are created")
44 .addChannelType(ChannelType.GuildCategory)
45 .setRequired(false)
46 )
47 .addNumberOption((option) =>
48 option
49 .setName("maxticketsperuser")
Skyler Grey11236ba2022-08-08 21:13:33 +010050 .setDescription("The maximum amount of tickets a user can create | Default: 5")
Skyler Grey75ea9172022-08-06 10:22:23 +010051 .setRequired(false)
52 .setMinValue(1)
53 )
54 .addRoleOption((option) =>
55 option
56 .setName("supportrole")
57 .setDescription(
58 "This role will have view access to all tickets and will be pinged when a ticket is created"
59 )
60 .setRequired(false)
61 );
pineafan4f164f32022-02-26 22:07:12 +000062
Skyler Grey11236ba2022-08-08 21:13:33 +010063const callback = async (interaction: CommandInteraction): Promise<void | unknown> => {
Skyler Grey75ea9172022-08-06 10:22:23 +010064 let m = (await interaction.reply({
65 embeds: LoadingEmbed,
66 ephemeral: true,
67 fetchReply: true
68 })) as Message;
pineafan63fc5e22022-08-04 22:04:10 +010069 const options = {
pineafan6702cef2022-06-13 17:52:37 +010070 enabled: interaction.options.getString("enabled") as string | boolean,
71 category: interaction.options.getChannel("category"),
72 maxtickets: interaction.options.getNumber("maxticketsperuser"),
73 supportping: interaction.options.getRole("supportrole")
pineafan63fc5e22022-08-04 22:04:10 +010074 };
Skyler Grey11236ba2022-08-08 21:13:33 +010075 if (options.enabled !== null || options.category || options.maxtickets || options.supportping) {
pineafan6702cef2022-06-13 17:52:37 +010076 options.enabled = options.enabled === "yes" ? true : false;
77 if (options.category) {
Skyler Grey1a67e182022-08-04 23:05:44 +010078 let channel: GuildChannel;
pineafan6702cef2022-06-13 17:52:37 +010079 try {
Skyler Grey11236ba2022-08-08 21:13:33 +010080 channel = await interaction.guild.channels.fetch(options.category.id);
pineafan6702cef2022-06-13 17:52:37 +010081 } catch {
82 return await interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +010083 embeds: [
84 new EmojiEmbed()
85 .setEmoji("CHANNEL.TEXT.DELETE")
86 .setTitle("Tickets > Category")
Skyler Grey11236ba2022-08-08 21:13:33 +010087 .setDescription("The channel you provided is not a valid category")
Skyler Grey75ea9172022-08-06 10:22:23 +010088 .setStatus("Danger")
pineafan6702cef2022-06-13 17:52:37 +010089 ]
pineafan63fc5e22022-08-04 22:04:10 +010090 });
pineafan6702cef2022-06-13 17:52:37 +010091 }
pineafan63fc5e22022-08-04 22:04:10 +010092 channel = channel as Discord.CategoryChannel;
Skyler Grey75ea9172022-08-06 10:22:23 +010093 if (channel.guild.id !== interaction.guild.id)
94 return interaction.editReply({
95 embeds: [
96 new EmojiEmbed()
97 .setTitle("Tickets > Category")
Skyler Grey11236ba2022-08-08 21:13:33 +010098 .setDescription("You must choose a category in this server")
Skyler Grey75ea9172022-08-06 10:22:23 +010099 .setStatus("Danger")
100 .setEmoji("CHANNEL.TEXT.DELETE")
101 ]
102 });
pineafan6702cef2022-06-13 17:52:37 +0100103 }
104 if (options.maxtickets) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100105 if (options.maxtickets < 1)
106 return interaction.editReply({
107 embeds: [
108 new EmojiEmbed()
109 .setTitle("Tickets > Max Tickets")
Skyler Grey11236ba2022-08-08 21:13:33 +0100110 .setDescription("You must choose a number greater than 0")
Skyler Grey75ea9172022-08-06 10:22:23 +0100111 .setStatus("Danger")
112 .setEmoji("CHANNEL.TEXT.DELETE")
113 ]
114 });
pineafan6702cef2022-06-13 17:52:37 +0100115 }
Skyler Grey1a67e182022-08-04 23:05:44 +0100116 let role: Role;
pineafan6702cef2022-06-13 17:52:37 +0100117 if (options.supportping) {
118 try {
Skyler Grey11236ba2022-08-08 21:13:33 +0100119 role = await interaction.guild.roles.fetch(options.supportping.id);
pineafan6702cef2022-06-13 17:52:37 +0100120 } catch {
121 return await interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100122 embeds: [
123 new EmojiEmbed()
124 .setEmoji("GUILD.ROLE.DELETE")
125 .setTitle("Tickets > Support Ping")
Skyler Grey11236ba2022-08-08 21:13:33 +0100126 .setDescription("The role you provided is not a valid role")
Skyler Grey75ea9172022-08-06 10:22:23 +0100127 .setStatus("Danger")
pineafan6702cef2022-06-13 17:52:37 +0100128 ]
pineafan63fc5e22022-08-04 22:04:10 +0100129 });
pineafan6702cef2022-06-13 17:52:37 +0100130 }
pineafan63fc5e22022-08-04 22:04:10 +0100131 role = role as Discord.Role;
Skyler Grey75ea9172022-08-06 10:22:23 +0100132 if (role.guild.id !== interaction.guild.id)
133 return interaction.editReply({
134 embeds: [
135 new EmojiEmbed()
136 .setTitle("Tickets > Support Ping")
Skyler Grey11236ba2022-08-08 21:13:33 +0100137 .setDescription("You must choose a role in this server")
Skyler Grey75ea9172022-08-06 10:22:23 +0100138 .setStatus("Danger")
139 .setEmoji("GUILD.ROLE.DELETE")
140 ]
141 });
pineafan6702cef2022-06-13 17:52:37 +0100142 }
143
pineafan63fc5e22022-08-04 22:04:10 +0100144 const confirmation = await new confirmationMessage(interaction)
pineafan6702cef2022-06-13 17:52:37 +0100145 .setEmoji("GUILD.TICKET.ARCHIVED")
146 .setTitle("Tickets")
147 .setDescription(
Skyler Grey11236ba2022-08-08 21:13:33 +0100148 (options.category ? `**Category:** ${options.category.name}\n` : "") +
149 (options.maxtickets ? `**Max Tickets:** ${options.maxtickets}\n` : "") +
150 (options.supportping ? `**Support Ping:** ${options.supportping.name}\n` : "") +
Skyler Grey75ea9172022-08-06 10:22:23 +0100151 (options.enabled !== null
152 ? `**Enabled:** ${
153 options.enabled
154 ? `${getEmojiByName("CONTROL.TICK")} Yes`
155 : `${getEmojiByName("CONTROL.CROSS")} No`
156 }\n`
157 : "") +
158 "\nAre you sure you want to apply these settings?"
pineafan6702cef2022-06-13 17:52:37 +0100159 )
160 .setColor("Warning")
161 .setInverted(true)
pineafan63fc5e22022-08-04 22:04:10 +0100162 .send(true);
163 if (confirmation.cancelled) return;
pineafan6702cef2022-06-13 17:52:37 +0100164 if (confirmation.success) {
pineafan63fc5e22022-08-04 22:04:10 +0100165 const toUpdate = {};
Skyler Grey11236ba2022-08-08 21:13:33 +0100166 if (options.enabled !== null) toUpdate["tickets.enabled"] = options.enabled;
167 if (options.category) toUpdate["tickets.category"] = options.category.id;
168 if (options.maxtickets) toUpdate["tickets.maxTickets"] = options.maxtickets;
169 if (options.supportping) toUpdate["tickets.supportRole"] = options.supportping.id;
pineafan6702cef2022-06-13 17:52:37 +0100170 try {
Skyler Grey11236ba2022-08-08 21:13:33 +0100171 await client.database.guilds.write(interaction.guild.id, toUpdate);
pineafan6702cef2022-06-13 17:52:37 +0100172 } catch (e) {
173 return interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100174 embeds: [
175 new EmojiEmbed()
176 .setTitle("Tickets")
Skyler Grey11236ba2022-08-08 21:13:33 +0100177 .setDescription("Something went wrong and the staff notifications channel could not be set")
Skyler Grey75ea9172022-08-06 10:22:23 +0100178 .setStatus("Danger")
179 .setEmoji("GUILD.TICKET.DELETE")
180 ],
181 components: []
pineafan6702cef2022-06-13 17:52:37 +0100182 });
183 }
184 } else {
185 return interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100186 embeds: [
187 new EmojiEmbed()
188 .setTitle("Tickets")
189 .setDescription("No changes were made")
190 .setStatus("Success")
191 .setEmoji("GUILD.TICKET.OPEN")
192 ],
193 components: []
pineafan6702cef2022-06-13 17:52:37 +0100194 });
195 }
196 }
pineafan4edb7762022-06-26 19:21:04 +0100197 let data = await client.database.guilds.read(interaction.guild.id);
Skyler Grey75ea9172022-08-06 10:22:23 +0100198 data.tickets.customTypes = (data.tickets.customTypes || []).filter(
Skyler Grey11236ba2022-08-08 21:13:33 +0100199 (value: string, index: number, array: string[]) => array.indexOf(value) === index
Skyler Grey75ea9172022-08-06 10:22:23 +0100200 );
pineafan6702cef2022-06-13 17:52:37 +0100201 let lastClicked = "";
Skyler Grey1a67e182022-08-04 23:05:44 +0100202 let embed: EmojiEmbed;
pineafan6702cef2022-06-13 17:52:37 +0100203 data = {
204 enabled: data.tickets.enabled,
205 category: data.tickets.category,
206 maxTickets: data.tickets.maxTickets,
207 supportRole: data.tickets.supportRole,
208 useCustom: data.tickets.useCustom,
209 types: data.tickets.types,
210 customTypes: data.tickets.customTypes
pineafan63fc5e22022-08-04 22:04:10 +0100211 };
pineafan6702cef2022-06-13 17:52:37 +0100212 while (true) {
pineafan4edb7762022-06-26 19:21:04 +0100213 embed = new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100214 .setTitle("Tickets")
215 .setDescription(
Skyler Grey11236ba2022-08-08 21:13:33 +0100216 `${data.enabled ? "" : getEmojiByName("TICKETS.REPORT")} **Enabled:** ${
217 data.enabled ? `${getEmojiByName("CONTROL.TICK")} Yes` : `${getEmojiByName("CONTROL.CROSS")} No`
Skyler Grey75ea9172022-08-06 10:22:23 +0100218 }\n` +
Skyler Grey11236ba2022-08-08 21:13:33 +0100219 `${data.category ? "" : getEmojiByName("TICKETS.REPORT")} **Category:** ${
Skyler Grey75ea9172022-08-06 10:22:23 +0100220 data.category ? `<#${data.category}>` : "*None set*"
221 }\n` +
Skyler Grey11236ba2022-08-08 21:13:33 +0100222 `**Max Tickets:** ${data.maxTickets ? data.maxTickets : "*No limit*"}\n` +
223 `**Support Ping:** ${data.supportRole ? `<@&${data.supportRole}>` : "*None set*"}\n\n` +
224 (data.useCustom && data.customTypes === null ? `${getEmojiByName("TICKETS.REPORT")} ` : "") +
Skyler Grey75ea9172022-08-06 10:22:23 +0100225 `${data.useCustom ? "Custom" : "Default"} types in use` +
226 "\n\n" +
Skyler Grey11236ba2022-08-08 21:13:33 +0100227 `${getEmojiByName("TICKETS.REPORT")} *Indicates a setting stopping tickets from being used*`
pineafan6702cef2022-06-13 17:52:37 +0100228 )
229 .setStatus("Success")
pineafan63fc5e22022-08-04 22:04:10 +0100230 .setEmoji("GUILD.TICKET.OPEN");
Skyler Grey75ea9172022-08-06 10:22:23 +0100231 m = (await interaction.editReply({
232 embeds: [embed],
233 components: [
234 new MessageActionRow().addComponents([
235 new MessageButton()
Skyler Grey11236ba2022-08-08 21:13:33 +0100236 .setLabel("Tickets " + (data.enabled ? "enabled" : "disabled"))
237 .setEmoji(getEmojiByName("CONTROL." + (data.enabled ? "TICK" : "CROSS"), "id"))
Skyler Grey75ea9172022-08-06 10:22:23 +0100238 .setStyle(data.enabled ? "SUCCESS" : "DANGER")
239 .setCustomId("enabled"),
240 new MessageButton()
Skyler Grey11236ba2022-08-08 21:13:33 +0100241 .setLabel(lastClicked === "cat" ? "Click again to confirm" : "Clear category")
Skyler Grey75ea9172022-08-06 10:22:23 +0100242 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
243 .setStyle("DANGER")
244 .setCustomId("clearCategory")
245 .setDisabled(data.category === null),
246 new MessageButton()
Skyler Grey11236ba2022-08-08 21:13:33 +0100247 .setLabel(lastClicked === "max" ? "Click again to confirm" : "Reset max tickets")
Skyler Grey75ea9172022-08-06 10:22:23 +0100248 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
249 .setStyle("DANGER")
250 .setCustomId("clearMaxTickets")
251 .setDisabled(data.maxTickets === 5),
252 new MessageButton()
Skyler Grey11236ba2022-08-08 21:13:33 +0100253 .setLabel(lastClicked === "sup" ? "Click again to confirm" : "Clear support ping")
Skyler Grey75ea9172022-08-06 10:22:23 +0100254 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
255 .setStyle("DANGER")
256 .setCustomId("clearSupportPing")
257 .setDisabled(data.supportRole === null)
258 ]),
259 new MessageActionRow().addComponents([
260 new MessageButton()
261 .setLabel("Manage types")
262 .setEmoji(getEmojiByName("TICKETS.OTHER", "id"))
263 .setStyle("SECONDARY")
264 .setCustomId("manageTypes"),
265 new MessageButton()
266 .setLabel("Add create ticket button")
267 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
268 .setStyle("PRIMARY")
269 .setCustomId("send")
270 ])
271 ]
272 })) as Message;
Skyler Grey1a67e182022-08-04 23:05:44 +0100273 let i: MessageComponentInteraction;
pineafan6702cef2022-06-13 17:52:37 +0100274 try {
pineafanbd02b4a2022-08-05 22:01:38 +0100275 i = await m.awaitMessageComponent({ time: 300000 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100276 } catch (e) {
277 break;
278 }
pineafan63fc5e22022-08-04 22:04:10 +0100279 i.deferUpdate();
Skyler Grey11236ba2022-08-08 21:13:33 +0100280 if ((i.component as MessageActionRowComponent).customId === "clearCategory") {
pineafane23c4ec2022-07-27 21:56:27 +0100281 if (lastClicked === "cat") {
pineafan6702cef2022-06-13 17:52:37 +0100282 lastClicked = "";
Skyler Grey11236ba2022-08-08 21:13:33 +0100283 await client.database.guilds.write(interaction.guild.id, null, ["tickets.category"]);
pineafan6702cef2022-06-13 17:52:37 +0100284 data.category = undefined;
285 } else lastClicked = "cat";
Skyler Grey11236ba2022-08-08 21:13:33 +0100286 } else if ((i.component as MessageActionRowComponent).customId === "clearMaxTickets") {
pineafane23c4ec2022-07-27 21:56:27 +0100287 if (lastClicked === "max") {
pineafan6702cef2022-06-13 17:52:37 +0100288 lastClicked = "";
Skyler Grey11236ba2022-08-08 21:13:33 +0100289 await client.database.guilds.write(interaction.guild.id, null, ["tickets.maxTickets"]);
pineafan6702cef2022-06-13 17:52:37 +0100290 data.maxTickets = 5;
291 } else lastClicked = "max";
Skyler Grey11236ba2022-08-08 21:13:33 +0100292 } else if ((i.component as MessageActionRowComponent).customId === "clearSupportPing") {
pineafane23c4ec2022-07-27 21:56:27 +0100293 if (lastClicked === "sup") {
pineafan6702cef2022-06-13 17:52:37 +0100294 lastClicked = "";
Skyler Grey11236ba2022-08-08 21:13:33 +0100295 await client.database.guilds.write(interaction.guild.id, null, ["tickets.supportRole"]);
pineafan6702cef2022-06-13 17:52:37 +0100296 data.supportRole = undefined;
297 } else lastClicked = "sup";
Skyler Grey11236ba2022-08-08 21:13:33 +0100298 } else if ((i.component as MessageActionRowComponent).customId === "send") {
pineafan41d93562022-07-30 22:10:15 +0100299 const ticketMessages = [
Skyler Grey75ea9172022-08-06 10:22:23 +0100300 {
301 label: "Create ticket",
302 description: "Click the button below to create a ticket"
303 },
304 {
305 label: "Issues, questions or feedback?",
Skyler Grey11236ba2022-08-08 21:13:33 +0100306 description: "Click below to open a ticket and get help from our staff team"
Skyler Grey75ea9172022-08-06 10:22:23 +0100307 },
308 {
309 label: "Contact Us",
Skyler Grey11236ba2022-08-08 21:13:33 +0100310 description: "Click the button below to speak to us privately"
Skyler Grey75ea9172022-08-06 10:22:23 +0100311 }
pineafan63fc5e22022-08-04 22:04:10 +0100312 ];
pineafan41d93562022-07-30 22:10:15 +0100313 while (true) {
pineafan63fc5e22022-08-04 22:04:10 +0100314 const enabled = data.enabled && data.category !== null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100315 await interaction.editReply({
316 embeds: [
317 new EmojiEmbed()
318 .setTitle("Ticket Button")
Skyler Grey11236ba2022-08-08 21:13:33 +0100319 .setDescription("Select a message template to send in this channel")
Skyler Grey75ea9172022-08-06 10:22:23 +0100320 .setFooter({
321 text: enabled
322 ? ""
323 : "Tickets are not set up correctly so the button may not work for users. Check the main menu to find which options must be set."
324 })
325 .setStatus(enabled ? "Success" : "Warning")
326 .setEmoji("GUILD.ROLES.CREATE")
327 ],
328 components: [
329 new MessageActionRow().addComponents([
330 new MessageSelectMenu()
331 .setOptions(
332 ticketMessages.map(
333 (
334 t: {
335 label: string;
336 description: string;
337 value?: string;
338 },
339 index
340 ) => {
341 t.value = index.toString();
342 return t as {
343 value: string;
344 label: string;
345 description: string;
346 };
347 }
348 )
349 )
350 .setCustomId("template")
351 .setMaxValues(1)
352 .setMinValues(1)
353 .setPlaceholder("Select a message template")
354 ]),
355 new MessageActionRow().addComponents([
356 new MessageButton()
357 .setCustomId("back")
358 .setLabel("Back")
359 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
360 .setStyle("DANGER"),
Skyler Grey11236ba2022-08-08 21:13:33 +0100361 new MessageButton().setCustomId("blank").setLabel("Empty").setStyle("SECONDARY"),
Skyler Grey75ea9172022-08-06 10:22:23 +0100362 new MessageButton()
363 .setCustomId("custom")
364 .setLabel("Custom")
365 .setEmoji(getEmojiByName("TICKETS.OTHER", "id"))
366 .setStyle("PRIMARY")
367 ])
368 ]
369 });
Skyler Grey1a67e182022-08-04 23:05:44 +0100370 let i: MessageComponentInteraction;
pineafan41d93562022-07-30 22:10:15 +0100371 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100372 i = await m.awaitMessageComponent({ time: 300000 });
373 } catch (e) {
pineafan63fc5e22022-08-04 22:04:10 +0100374 break;
Skyler Grey75ea9172022-08-06 10:22:23 +0100375 }
Skyler Grey11236ba2022-08-08 21:13:33 +0100376 if ((i.component as MessageActionRowComponent).customId === "template") {
pineafan63fc5e22022-08-04 22:04:10 +0100377 i.deferUpdate();
Skyler Grey75ea9172022-08-06 10:22:23 +0100378 await interaction.channel.send({
379 embeds: [
380 new EmojiEmbed()
Skyler Grey11236ba2022-08-08 21:13:33 +0100381 .setTitle(ticketMessages[parseInt((i as SelectMenuInteraction).values[0])].label)
Skyler Grey75ea9172022-08-06 10:22:23 +0100382 .setDescription(
Skyler Grey11236ba2022-08-08 21:13:33 +0100383 ticketMessages[parseInt((i as SelectMenuInteraction).values[0])].description
Skyler Grey75ea9172022-08-06 10:22:23 +0100384 )
385 .setStatus("Success")
386 .setEmoji("GUILD.TICKET.OPEN")
387 ],
388 components: [
389 new MessageActionRow().addComponents([
390 new MessageButton()
391 .setLabel("Create Ticket")
Skyler Grey11236ba2022-08-08 21:13:33 +0100392 .setEmoji(getEmojiByName("CONTROL.TICK", "id"))
Skyler Grey75ea9172022-08-06 10:22:23 +0100393 .setStyle("SUCCESS")
394 .setCustomId("createticket")
395 ])
396 ]
397 });
pineafan63fc5e22022-08-04 22:04:10 +0100398 break;
Skyler Grey11236ba2022-08-08 21:13:33 +0100399 } else if ((i.component as MessageActionRowComponent).customId === "blank") {
Skyler Grey75ea9172022-08-06 10:22:23 +0100400 i.deferUpdate();
401 await interaction.channel.send({
402 components: [
403 new MessageActionRow().addComponents([
404 new MessageButton()
405 .setLabel("Create Ticket")
Skyler Grey11236ba2022-08-08 21:13:33 +0100406 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
Skyler Grey75ea9172022-08-06 10:22:23 +0100407 .setStyle("SUCCESS")
408 .setCustomId("createticket")
409 ])
410 ]
411 });
412 break;
Skyler Grey11236ba2022-08-08 21:13:33 +0100413 } else if ((i.component as MessageActionRowComponent).customId === "custom") {
Skyler Grey75ea9172022-08-06 10:22:23 +0100414 await i.showModal(
415 new Discord.Modal()
416 .setCustomId("modal")
417 .setTitle("Enter embed details")
418 .addComponents(
419 new MessageActionRow<TextInputComponent>().addComponents(
420 new TextInputComponent()
421 .setCustomId("title")
422 .setLabel("Title")
423 .setMaxLength(256)
424 .setRequired(true)
425 .setStyle("SHORT")
426 ),
427 new MessageActionRow<TextInputComponent>().addComponents(
428 new TextInputComponent()
429 .setCustomId("description")
430 .setLabel("Description")
431 .setMaxLength(4000)
432 .setRequired(true)
433 .setStyle("PARAGRAPH")
434 )
435 )
436 );
pineafan41d93562022-07-30 22:10:15 +0100437 await interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100438 embeds: [
439 new EmojiEmbed()
440 .setTitle("Ticket Button")
Skyler Grey11236ba2022-08-08 21:13:33 +0100441 .setDescription("Modal opened. If you can't see it, click back and try again.")
Skyler Grey75ea9172022-08-06 10:22:23 +0100442 .setStatus("Success")
443 .setEmoji("GUILD.TICKET.OPEN")
444 ],
445 components: [
446 new MessageActionRow().addComponents([
447 new MessageButton()
448 .setLabel("Back")
Skyler Grey11236ba2022-08-08 21:13:33 +0100449 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
Skyler Grey75ea9172022-08-06 10:22:23 +0100450 .setStyle("PRIMARY")
451 .setCustomId("back")
452 ])
453 ]
pineafan41d93562022-07-30 22:10:15 +0100454 });
455 let out;
456 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100457 out = await modalInteractionCollector(
458 m,
459 (m) => m.channel.id === interaction.channel.id,
460 (m) => m.customId === "modify"
461 );
462 } catch (e) {
463 break;
464 }
pineafan41d93562022-07-30 22:10:15 +0100465 if (out.fields) {
pineafan63fc5e22022-08-04 22:04:10 +0100466 const title = out.fields.getTextInputValue("title");
Skyler Grey11236ba2022-08-08 21:13:33 +0100467 const description = out.fields.getTextInputValue("description");
Skyler Grey75ea9172022-08-06 10:22:23 +0100468 await interaction.channel.send({
469 embeds: [
470 new EmojiEmbed()
471 .setTitle(title)
472 .setDescription(description)
473 .setStatus("Success")
474 .setEmoji("GUILD.TICKET.OPEN")
475 ],
476 components: [
477 new MessageActionRow().addComponents([
478 new MessageButton()
479 .setLabel("Create Ticket")
Skyler Grey11236ba2022-08-08 21:13:33 +0100480 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
Skyler Grey75ea9172022-08-06 10:22:23 +0100481 .setStyle("SUCCESS")
482 .setCustomId("createticket")
483 ])
484 ]
485 });
pineafan63fc5e22022-08-04 22:04:10 +0100486 break;
Skyler Grey75ea9172022-08-06 10:22:23 +0100487 } else {
488 continue;
489 }
pineafan41d93562022-07-30 22:10:15 +0100490 }
491 }
Skyler Grey11236ba2022-08-08 21:13:33 +0100492 } else if ((i.component as MessageActionRowComponent).customId === "enabled") {
Skyler Grey75ea9172022-08-06 10:22:23 +0100493 await client.database.guilds.write(interaction.guild.id, {
494 "tickets.enabled": !data.enabled
495 });
pineafan6702cef2022-06-13 17:52:37 +0100496 data.enabled = !data.enabled;
Skyler Grey11236ba2022-08-08 21:13:33 +0100497 } else if ((i.component as MessageActionRowComponent).customId === "manageTypes") {
Skyler Grey1a67e182022-08-04 23:05:44 +0100498 data = await manageTypes(interaction, data, m as Message);
pineafan6702cef2022-06-13 17:52:37 +0100499 } else {
pineafan63fc5e22022-08-04 22:04:10 +0100500 break;
pineafan6702cef2022-06-13 17:52:37 +0100501 }
502 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100503 await interaction.editReply({
504 embeds: [embed.setFooter({ text: "Message closed" })],
505 components: []
506 });
pineafan63fc5e22022-08-04 22:04:10 +0100507};
pineafan4f164f32022-02-26 22:07:12 +0000508
Skyler Grey11236ba2022-08-08 21:13:33 +0100509async function manageTypes(interaction: CommandInteraction, data: GuildConfig["tickets"], m: Message) {
pineafan6702cef2022-06-13 17:52:37 +0100510 while (true) {
511 if (data.useCustom) {
pineafan63fc5e22022-08-04 22:04:10 +0100512 const customTypes = data.customTypes;
pineafanc6158ab2022-06-17 16:34:07 +0100513 await interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100514 embeds: [
515 new EmojiEmbed()
516 .setTitle("Tickets > Types")
517 .setDescription(
518 "**Custom types enabled**\n\n" +
519 "**Types in use:**\n" +
Skyler Grey11236ba2022-08-08 21:13:33 +0100520 (customTypes !== null ? customTypes.map((t) => `> ${t}`).join("\n") : "*None set*") +
Skyler Grey75ea9172022-08-06 10:22:23 +0100521 "\n\n" +
522 (customTypes === null
523 ? `${getEmojiByName(
524 "TICKETS.REPORT"
525 )} Having no types will disable tickets. Please add at least 1 type or use default types`
526 : "")
pineafan6702cef2022-06-13 17:52:37 +0100527 )
Skyler Grey75ea9172022-08-06 10:22:23 +0100528 .setStatus("Success")
529 .setEmoji("GUILD.TICKET.OPEN")
530 ],
531 components: (customTypes
532 ? [
533 new MessageActionRow().addComponents([
534 new Discord.MessageSelectMenu()
535 .setCustomId("removeTypes")
536 .setPlaceholder("Select types to remove")
537 .setMaxValues(customTypes.length)
538 .setMinValues(1)
539 .addOptions(
540 customTypes.map((t) => ({
541 label: t,
542 value: t
543 }))
544 )
545 ])
546 ]
547 : []
548 ).concat([
pineafan6702cef2022-06-13 17:52:37 +0100549 new MessageActionRow().addComponents([
550 new MessageButton()
551 .setLabel("Back")
552 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
553 .setStyle("PRIMARY")
554 .setCustomId("back"),
555 new MessageButton()
556 .setLabel("Add new type")
Skyler Grey11236ba2022-08-08 21:13:33 +0100557 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
pineafan6702cef2022-06-13 17:52:37 +0100558 .setStyle("PRIMARY")
559 .setCustomId("addType")
Skyler Grey11236ba2022-08-08 21:13:33 +0100560 .setDisabled(customTypes !== null && customTypes.length >= 25),
pineafan6702cef2022-06-13 17:52:37 +0100561 new MessageButton()
562 .setLabel("Switch to default types")
563 .setStyle("SECONDARY")
pineafan63fc5e22022-08-04 22:04:10 +0100564 .setCustomId("switchToDefault")
pineafan6702cef2022-06-13 17:52:37 +0100565 ])
566 ])
567 });
568 } else {
pineafan63fc5e22022-08-04 22:04:10 +0100569 const inUse = toHexArray(data.types, ticketTypes);
570 const options = [];
Skyler Grey75ea9172022-08-06 10:22:23 +0100571 ticketTypes.forEach((type) => {
572 options.push(
573 new SelectMenuOption({
574 label: capitalize(type),
575 value: type,
Skyler Grey11236ba2022-08-08 21:13:33 +0100576 emoji: client.emojis.cache.get(getEmojiByName(`TICKETS.${type.toUpperCase()}`, "id")),
Skyler Grey75ea9172022-08-06 10:22:23 +0100577 default: inUse.includes(type)
578 })
579 );
pineafan63fc5e22022-08-04 22:04:10 +0100580 });
581 const selectPane = new MessageActionRow().addComponents([
pineafan6702cef2022-06-13 17:52:37 +0100582 new Discord.MessageSelectMenu()
583 .addOptions(options)
584 .setCustomId("types")
585 .setMaxValues(ticketTypes.length)
586 .setMinValues(1)
587 .setPlaceholder("Select types to use")
pineafan63fc5e22022-08-04 22:04:10 +0100588 ]);
pineafanc6158ab2022-06-17 16:34:07 +0100589 await interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100590 embeds: [
591 new EmojiEmbed()
592 .setTitle("Tickets > Types")
593 .setDescription(
594 "**Default types enabled**\n\n" +
595 "**Types in use:**\n" +
596 inUse
Skyler Grey11236ba2022-08-08 21:13:33 +0100597 .map((t) => `> ${getEmojiByName("TICKETS." + t.toUpperCase())} ${capitalize(t)}`)
Skyler Grey75ea9172022-08-06 10:22:23 +0100598 .join("\n")
599 )
600 .setStatus("Success")
601 .setEmoji("GUILD.TICKET.OPEN")
602 ],
603 components: [
pineafan6702cef2022-06-13 17:52:37 +0100604 selectPane,
605 new MessageActionRow().addComponents([
606 new MessageButton()
607 .setLabel("Back")
608 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
609 .setStyle("PRIMARY")
610 .setCustomId("back"),
611 new MessageButton()
612 .setLabel("Switch to custom types")
613 .setStyle("SECONDARY")
pineafan63fc5e22022-08-04 22:04:10 +0100614 .setCustomId("switchToCustom")
pineafan6702cef2022-06-13 17:52:37 +0100615 ])
616 ]
617 });
618 }
619 let i;
620 try {
pineafanc6158ab2022-06-17 16:34:07 +0100621 i = await m.awaitMessageComponent({ time: 300000 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100622 } catch (e) {
623 break;
624 }
pineafane23c4ec2022-07-27 21:56:27 +0100625 if (i.component.customId === "types") {
pineafan63fc5e22022-08-04 22:04:10 +0100626 i.deferUpdate();
627 const types = toHexInteger(i.values, ticketTypes);
Skyler Grey75ea9172022-08-06 10:22:23 +0100628 await client.database.guilds.write(interaction.guild.id, {
629 "tickets.types": types
630 });
pineafan6702cef2022-06-13 17:52:37 +0100631 data.types = types;
pineafane23c4ec2022-07-27 21:56:27 +0100632 } else if (i.component.customId === "removeTypes") {
pineafan63fc5e22022-08-04 22:04:10 +0100633 i.deferUpdate();
634 const types = i.values;
pineafan6702cef2022-06-13 17:52:37 +0100635 let customTypes = data.customTypes;
636 if (customTypes) {
637 customTypes = customTypes.filter((t) => !types.includes(t));
638 customTypes = customTypes.length > 0 ? customTypes : null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100639 await client.database.guilds.write(interaction.guild.id, {
640 "tickets.customTypes": customTypes
641 });
pineafan6702cef2022-06-13 17:52:37 +0100642 data.customTypes = customTypes;
643 }
pineafane23c4ec2022-07-27 21:56:27 +0100644 } else if (i.component.customId === "addType") {
Skyler Grey75ea9172022-08-06 10:22:23 +0100645 await i.showModal(
646 new Discord.Modal()
647 .setCustomId("modal")
648 .setTitle("Enter a name for the new type")
649 .addComponents(
650 new MessageActionRow<TextInputComponent>().addComponents(
651 new TextInputComponent()
652 .setCustomId("type")
653 .setLabel("Name")
654 .setMaxLength(100)
655 .setMinLength(1)
656 .setPlaceholder('E.g. "Server Idea"')
657 .setRequired(true)
658 .setStyle("SHORT")
659 )
660 )
661 );
pineafan6702cef2022-06-13 17:52:37 +0100662 await interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100663 embeds: [
664 new EmojiEmbed()
665 .setTitle("Tickets > Types")
Skyler Grey11236ba2022-08-08 21:13:33 +0100666 .setDescription("Modal opened. If you can't see it, click back and try again.")
Skyler Grey75ea9172022-08-06 10:22:23 +0100667 .setStatus("Success")
668 .setEmoji("GUILD.TICKET.OPEN")
669 ],
670 components: [
671 new MessageActionRow().addComponents([
672 new MessageButton()
673 .setLabel("Back")
674 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
675 .setStyle("PRIMARY")
676 .setCustomId("back")
677 ])
678 ]
pineafan6702cef2022-06-13 17:52:37 +0100679 });
pineafan4edb7762022-06-26 19:21:04 +0100680 let out;
pineafan6702cef2022-06-13 17:52:37 +0100681 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100682 out = await modalInteractionCollector(
683 m,
684 (m) => m.channel.id === interaction.channel.id,
685 (m) => m.customId === "addType"
686 );
687 } catch (e) {
688 continue;
689 }
pineafan6702cef2022-06-13 17:52:37 +0100690 if (out.fields) {
691 let toAdd = out.fields.getTextInputValue("type");
Skyler Grey75ea9172022-08-06 10:22:23 +0100692 if (!toAdd) {
693 continue;
694 }
pineafan63fc5e22022-08-04 22:04:10 +0100695 toAdd = toAdd.substring(0, 80);
pineafan6702cef2022-06-13 17:52:37 +0100696 try {
Skyler Grey11236ba2022-08-08 21:13:33 +0100697 await client.database.guilds.append(interaction.guild.id, "tickets.customTypes", toAdd);
Skyler Grey75ea9172022-08-06 10:22:23 +0100698 } catch {
699 continue;
700 }
pineafan6702cef2022-06-13 17:52:37 +0100701 data.customTypes = data.customTypes || [];
702 if (!data.customTypes.includes(toAdd)) {
703 data.customTypes.push(toAdd);
704 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100705 } else {
706 continue;
707 }
pineafane23c4ec2022-07-27 21:56:27 +0100708 } else if (i.component.customId === "switchToDefault") {
pineafan63fc5e22022-08-04 22:04:10 +0100709 i.deferUpdate();
Skyler Grey11236ba2022-08-08 21:13:33 +0100710 await client.database.guilds.write(interaction.guild.id, { "tickets.useCustom": false }, []);
pineafan6702cef2022-06-13 17:52:37 +0100711 data.useCustom = false;
pineafane23c4ec2022-07-27 21:56:27 +0100712 } else if (i.component.customId === "switchToCustom") {
pineafan63fc5e22022-08-04 22:04:10 +0100713 i.deferUpdate();
Skyler Grey11236ba2022-08-08 21:13:33 +0100714 await client.database.guilds.write(interaction.guild.id, { "tickets.useCustom": true }, []);
pineafan6702cef2022-06-13 17:52:37 +0100715 data.useCustom = true;
716 } else {
pineafan63fc5e22022-08-04 22:04:10 +0100717 i.deferUpdate();
718 break;
pineafan6702cef2022-06-13 17:52:37 +0100719 }
720 }
pineafan63fc5e22022-08-04 22:04:10 +0100721 return data;
pineafan6702cef2022-06-13 17:52:37 +0100722}
723
Skyler Grey1a67e182022-08-04 23:05:44 +0100724const check = (interaction: CommandInteraction) => {
Skyler Grey75ea9172022-08-06 10:22:23 +0100725 const member = interaction.member as Discord.GuildMember;
726 if (!member.permissions.has("MANAGE_GUILD"))
727 throw "You must have the *Manage Server* permission to use this command";
pineafan6702cef2022-06-13 17:52:37 +0100728 return true;
pineafan63fc5e22022-08-04 22:04:10 +0100729};
pineafan4f164f32022-02-26 22:07:12 +0000730
731export { command };
732export { callback };
Skyler Grey1a67e182022-08-04 23:05:44 +0100733export { check };