blob: 44f974ebe5fbc87e13abf07b3068decba2205472 [file] [log] [blame]
pineafane23c4ec2022-07-27 21:56:27 +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";
5import Discord, { CommandInteraction, MessageActionRow, MessageButton, MessageSelectMenu, TextInputComponent } from "discord.js";
6import { SelectMenuOption, SlashCommandSubcommandBuilder } from "@discordjs/builders";
pineafan4f164f32022-02-26 22:07:12 +00007import { WrappedCheck } from "jshaiku";
pineafan1dc15722022-03-14 21:27:34 +00008import { ChannelType } from 'discord-api-types';
pineafan6702cef2022-06-13 17:52:37 +01009import client from "../../utils/client.js";
10import { toHexInteger, toHexArray, tickets as ticketTypes } from "../../utils/calculate.js";
11import { capitalize } from '../../utils/generateKeyValueList.js';
12import { modalInteractionCollector } from "../../utils/dualCollector.js";
pineafan4f164f32022-02-26 22:07:12 +000013
pineafan6702cef2022-06-13 17:52:37 +010014const command = (builder: SlashCommandSubcommandBuilder) => builder
pineafan4f164f32022-02-26 22:07:12 +000015 .setName("tickets")
pineafan6702cef2022-06-13 17:52:37 +010016 .setDescription("Shows settings for tickets | Use no arguments to manage custom types")
17 .addStringOption(option => option.setName("enabled").setDescription("If users should be able to create tickets").setRequired(false)
pineafan1dc15722022-03-14 21:27:34 +000018 .addChoices([["Yes", "yes"], ["No", "no"]]))
19 .addChannelOption(option => option.setName("category").setDescription("The category where tickets are created").addChannelType(ChannelType.GuildCategory).setRequired(false))
pineafan73a7c4a2022-07-24 10:38:04 +010020 .addNumberOption(option => option.setName("maxticketsperuser").setDescription("The maximum amount of tickets a user can create | Default: 5").setRequired(false).setMinValue(1))
pineafan6702cef2022-06-13 17:52:37 +010021 .addRoleOption(option => option.setName("supportrole").setDescription("This role will have view access to all tickets and will be pinged when a ticket is created").setRequired(false))
pineafan4f164f32022-02-26 22:07:12 +000022
pineafan6702cef2022-06-13 17:52:37 +010023const callback = async (interaction: CommandInteraction): Promise<any> => {
24 let m;
pineafane23c4ec2022-07-27 21:56:27 +010025 m = await interaction.reply({embeds: LoadingEmbed, ephemeral: true, fetchReply: true});
pineafan6702cef2022-06-13 17:52:37 +010026 let options = {
27 enabled: interaction.options.getString("enabled") as string | boolean,
28 category: interaction.options.getChannel("category"),
29 maxtickets: interaction.options.getNumber("maxticketsperuser"),
30 supportping: interaction.options.getRole("supportrole")
31 }
32 if (options.enabled !== null || options.category || options.maxtickets || options.supportping) {
33 options.enabled = options.enabled === "yes" ? true : false;
34 if (options.category) {
35 let channel
36 try {
37 channel = interaction.guild.channels.cache.get(options.category.id)
38 } catch {
39 return await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010040 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +010041 .setEmoji("CHANNEL.TEXT.DELETE")
42 .setTitle("Tickets > Category")
43 .setDescription("The channel you provided is not a valid category")
44 .setStatus("Danger")
45 ]
46 })
47 }
48 channel = channel as Discord.CategoryChannel
pineafane23c4ec2022-07-27 21:56:27 +010049 if (channel.guild.id !== interaction.guild.id) return interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010050 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +010051 .setTitle("Tickets > Category")
52 .setDescription(`You must choose a category in this server`)
53 .setStatus("Danger")
54 .setEmoji("CHANNEL.TEXT.DELETE")
55 ]
56 });
57 }
58 if (options.maxtickets) {
59 if (options.maxtickets < 1) return interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010060 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +010061 .setTitle("Tickets > Max Tickets")
62 .setDescription(`You must choose a number greater than 0`)
63 .setStatus("Danger")
64 .setEmoji("CHANNEL.TEXT.DELETE")
65 ]
66 });
67 }
68 let role
69 if (options.supportping) {
70 try {
71 role = interaction.guild.roles.cache.get(options.supportping.id)
72 } catch {
73 return await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010074 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +010075 .setEmoji("GUILD.ROLE.DELETE")
76 .setTitle("Tickets > Support Ping")
77 .setDescription("The role you provided is not a valid role")
78 .setStatus("Danger")
79 ]
80 })
81 }
82 role = role as Discord.Role
pineafane23c4ec2022-07-27 21:56:27 +010083 if (role.guild.id !== interaction.guild.id) return interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010084 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +010085 .setTitle("Tickets > Support Ping")
86 .setDescription(`You must choose a role in this server`)
87 .setStatus("Danger")
88 .setEmoji("GUILD.ROLE.DELETE")
89 ]
90 });
91 }
92
93 let confirmation = await new confirmationMessage(interaction)
94 .setEmoji("GUILD.TICKET.ARCHIVED")
95 .setTitle("Tickets")
96 .setDescription(
97 (options.category ? `**Category:** ${options.category.name}\n` : "") +
98 (options.maxtickets ? `**Max Tickets:** ${options.maxtickets}\n` : "") +
99 (options.supportping ? `**Support Ping:** ${options.supportping.name}\n` : "") +
100 (options.enabled !== null ? `**Enabled:** ${options.enabled ? `${getEmojiByName("CONTROL.TICK")} Yes` : `${getEmojiByName("CONTROL.CROSS")} No`
101 }\n` : "") +
102 `\nAre you sure you want to apply these settings?`
103 )
104 .setColor("Warning")
105 .setInverted(true)
106 .send(true)
pineafan02ba0232022-07-24 22:16:15 +0100107 if (confirmation.cancelled) return
pineafan6702cef2022-06-13 17:52:37 +0100108 if (confirmation.success) {
109 let toUpdate = {}
110 if (options.enabled !== null) toUpdate["tickets.enabled"] = options.enabled
111 if (options.category) toUpdate["tickets.category"] = options.category.id
112 if (options.maxtickets) toUpdate["tickets.maxTickets"] = options.maxtickets
113 if (options.supportping) toUpdate["tickets.supportRole"] = options.supportping.id
114 try {
pineafan4edb7762022-06-26 19:21:04 +0100115 await client.database.guilds.write(interaction.guild.id, toUpdate)
pineafan6702cef2022-06-13 17:52:37 +0100116 } catch (e) {
117 return interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100118 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100119 .setTitle("Tickets")
120 .setDescription(`Something went wrong and the staff notifications channel could not be set`)
121 .setStatus("Danger")
122 .setEmoji("GUILD.TICKET.DELETE")
123 ], components: []
124 });
125 }
126 } else {
127 return interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100128 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100129 .setTitle("Tickets")
130 .setDescription(`No changes were made`)
131 .setStatus("Success")
132 .setEmoji("GUILD.TICKET.OPEN")
133 ], components: []
134 });
135 }
136 }
pineafan4edb7762022-06-26 19:21:04 +0100137 let data = await client.database.guilds.read(interaction.guild.id);
pineafan73a7c4a2022-07-24 10:38:04 +0100138 data.tickets.customTypes = (data.tickets.customTypes || []).filter((v, i, a) => a.indexOf(v) === i)
pineafan6702cef2022-06-13 17:52:37 +0100139 let lastClicked = "";
140 let embed;
141 data = {
142 enabled: data.tickets.enabled,
143 category: data.tickets.category,
144 maxTickets: data.tickets.maxTickets,
145 supportRole: data.tickets.supportRole,
146 useCustom: data.tickets.useCustom,
147 types: data.tickets.types,
148 customTypes: data.tickets.customTypes
149 }
150 while (true) {
pineafan4edb7762022-06-26 19:21:04 +0100151 embed = new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100152 .setTitle("Tickets")
153 .setDescription(
154 `${data.enabled ? "" : getEmojiByName("TICKETS.REPORT")} **Enabled:** ${data.enabled ? `${getEmojiByName("CONTROL.TICK")} Yes` : `${getEmojiByName("CONTROL.CROSS")} No`}\n` +
155 `${data.category ? "" : getEmojiByName("TICKETS.REPORT")} **Category:** ${data.category ? `<#${data.category}>` : "*None set*"}\n` +
156 `**Max Tickets:** ${data.maxTickets ? data.maxTickets : "*No limit*"}\n` +
157 `**Support Ping:** ${data.supportRole ? `<@&${data.supportRole}>` : "*None set*"}\n\n` +
158 ((data.useCustom && data.customTypes === null) ? `${getEmojiByName("TICKETS.REPORT")} ` : "") +
159 `${data.useCustom ? "Custom" : "Default"} types in use` + "\n\n" +
160 `${getEmojiByName("TICKETS.REPORT")} *Indicates a setting stopping tickets from being used*`
161 )
162 .setStatus("Success")
163 .setEmoji("GUILD.TICKET.OPEN")
164 m = await interaction.editReply({
165 embeds: [embed], components: [new MessageActionRow().addComponents([
166 new MessageButton()
167 .setLabel("Tickets " + (data.enabled ? "enabled" : "disabled"))
168 .setEmoji(getEmojiByName("CONTROL." + (data.enabled ? "TICK" : "CROSS"), "id"))
169 .setStyle(data.enabled ? "SUCCESS" : "DANGER")
170 .setCustomId("enabled"),
171 new MessageButton()
pineafane23c4ec2022-07-27 21:56:27 +0100172 .setLabel(lastClicked === "cat" ? "Click again to confirm" : "Clear category")
pineafan6702cef2022-06-13 17:52:37 +0100173 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
174 .setStyle("DANGER")
175 .setCustomId("clearCategory")
pineafane23c4ec2022-07-27 21:56:27 +0100176 .setDisabled(data.category === null),
pineafan6702cef2022-06-13 17:52:37 +0100177 new MessageButton()
pineafane23c4ec2022-07-27 21:56:27 +0100178 .setLabel(lastClicked === "max" ? "Click again to confirm" : "Reset max tickets")
pineafan6702cef2022-06-13 17:52:37 +0100179 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
180 .setStyle("DANGER")
181 .setCustomId("clearMaxTickets")
pineafane23c4ec2022-07-27 21:56:27 +0100182 .setDisabled(data.maxTickets === 5),
pineafan6702cef2022-06-13 17:52:37 +0100183 new MessageButton()
pineafane23c4ec2022-07-27 21:56:27 +0100184 .setLabel(lastClicked === "sup" ? "Click again to confirm" : "Clear support ping")
pineafan6702cef2022-06-13 17:52:37 +0100185 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
186 .setStyle("DANGER")
187 .setCustomId("clearSupportPing")
pineafane23c4ec2022-07-27 21:56:27 +0100188 .setDisabled(data.supportRole === null),
pineafan6702cef2022-06-13 17:52:37 +0100189 ]), new MessageActionRow().addComponents([
190 new MessageButton()
191 .setLabel("Manage types")
192 .setEmoji(getEmojiByName("TICKETS.OTHER", "id"))
193 .setStyle("SECONDARY")
194 .setCustomId("manageTypes"),
pineafan41d93562022-07-30 22:10:15 +0100195 new MessageButton()
196 .setLabel("Add create ticket button")
197 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
198 .setStyle("PRIMARY")
199 .setCustomId("send"),
pineafan6702cef2022-06-13 17:52:37 +0100200 ])]
201 });
202 let i;
203 try {
pineafanc6158ab2022-06-17 16:34:07 +0100204 i = await m.awaitMessageComponent({ time: 300000 });
pineafan6702cef2022-06-13 17:52:37 +0100205 } catch (e) { break }
206 i.deferUpdate()
pineafane23c4ec2022-07-27 21:56:27 +0100207 if (i.component.customId === "clearCategory") {
208 if (lastClicked === "cat") {
pineafan6702cef2022-06-13 17:52:37 +0100209 lastClicked = "";
pineafane23c4ec2022-07-27 21:56:27 +0100210 await client.database.guilds.write(interaction.guild.id, null, ["tickets.category"])
pineafan6702cef2022-06-13 17:52:37 +0100211 data.category = undefined;
212 } else lastClicked = "cat";
pineafane23c4ec2022-07-27 21:56:27 +0100213 } else if (i.component.customId === "clearMaxTickets") {
214 if (lastClicked === "max") {
pineafan6702cef2022-06-13 17:52:37 +0100215 lastClicked = "";
pineafane23c4ec2022-07-27 21:56:27 +0100216 await client.database.guilds.write(interaction.guild.id, null, ["tickets.maxTickets"])
pineafan6702cef2022-06-13 17:52:37 +0100217 data.maxTickets = 5;
218 } else lastClicked = "max";
pineafane23c4ec2022-07-27 21:56:27 +0100219 } else if (i.component.customId === "clearSupportPing") {
220 if (lastClicked === "sup") {
pineafan6702cef2022-06-13 17:52:37 +0100221 lastClicked = "";
pineafane23c4ec2022-07-27 21:56:27 +0100222 await client.database.guilds.write(interaction.guild.id, null, ["tickets.supportRole"])
pineafan6702cef2022-06-13 17:52:37 +0100223 data.supportRole = undefined;
224 } else lastClicked = "sup";
pineafan41d93562022-07-30 22:10:15 +0100225 } else if (i.component.customId === "send") {
226 const ticketMessages = [
227 {label: "Create ticket", description: "Click the button below to create a ticket"},
228 {label: "Issues, questions or feedback?", description: "Click below to open a ticket and get help from our staff team"},
229 {label: "Contact Us", description: "Click the button below to speak to us privately"},
230 ]
231 while (true) {
232 let enabled = data.enabled && data.category !== null;
233 await interaction.editReply({embeds: [new EmojiEmbed()
234 .setTitle("Ticket Button")
235 .setDescription("Select a message template to send in this channel")
236 .setFooter({text: enabled ? "" : "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."})
237 .setStatus(enabled ? "Success" : "Warning")
238 .setEmoji("GUILD.ROLES.CREATE")
239 ], components: [
240 new MessageActionRow().addComponents([
241 new MessageSelectMenu().setOptions(ticketMessages.map((t: {label: string, description: string, value?: string}, index) => {
242 t.value = index.toString(); return t as {value: string, label: string, description: string}
243 })).setCustomId("template").setMaxValues(1).setMinValues(1).setPlaceholder("Select a message template"),
244 ]),
245 new MessageActionRow().addComponents([
246 new MessageButton()
247 .setCustomId("back")
248 .setLabel("Back")
249 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
250 .setStyle("DANGER"),
251 new MessageButton()
252 .setCustomId("blank")
253 .setLabel("Empty")
254 .setStyle("SECONDARY"),
255 new MessageButton()
256 .setCustomId("custom")
257 .setLabel("Custom")
258 .setEmoji(getEmojiByName("TICKETS.OTHER", "id"))
259 .setStyle("PRIMARY")
260 ])
261 ]});
262 let i;
263 try {
264 i = await m.awaitMessageComponent({time: 300000});
265 } catch(e) { break }
266 if (i.component.customId === "template") {
267 i.deferUpdate()
268 await interaction.channel.send({embeds: [new EmojiEmbed()
269 .setTitle(ticketMessages[parseInt(i.values[0])].label)
270 .setDescription(ticketMessages[parseInt(i.values[0])].description)
271 .setStatus("Success")
272 .setEmoji("GUILD.TICKET.OPEN")
273 ], components: [new MessageActionRow().addComponents([new MessageButton()
274 .setLabel("Create Ticket")
275 .setEmoji(getEmojiByName("CONTROL.TICK", "id"))
276 .setStyle("SUCCESS")
277 .setCustomId("createticket")
278 ])]});
279 break
280 } else if (i.component.customId === "blank") {
281 i.deferUpdate()
282 await interaction.channel.send({components: [new MessageActionRow().addComponents([new MessageButton()
283 .setLabel("Create Ticket")
284 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
285 .setStyle("SUCCESS")
286 .setCustomId("createticket")
287 ])]});
288 break
289 } else if (i.component.customId === "custom") {
290 await i.showModal(new Discord.Modal().setCustomId("modal").setTitle(`Enter embed details`).addComponents(
291 new MessageActionRow<TextInputComponent>().addComponents(new TextInputComponent()
292 .setCustomId("title")
293 .setLabel("Title")
294 .setMaxLength(256)
295 .setRequired(true)
296 .setStyle("SHORT")
297 ),
298 new MessageActionRow<TextInputComponent>().addComponents(new TextInputComponent()
299 .setCustomId("description")
300 .setLabel("Description")
301 .setMaxLength(4000)
302 .setRequired(true)
303 .setStyle("PARAGRAPH")
304 )
305 ))
306 await interaction.editReply({
307 embeds: [new EmojiEmbed()
308 .setTitle("Ticket Button")
309 .setDescription("Modal opened. If you can't see it, click back and try again.")
310 .setStatus("Success")
311 .setEmoji("GUILD.TICKET.OPEN")
312 ], components: [new MessageActionRow().addComponents([new MessageButton()
313 .setLabel("Back")
314 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
315 .setStyle("PRIMARY")
316 .setCustomId("back")
317 ])]
318 });
319 let out;
320 try {
321 out = await modalInteractionCollector(m, (m) => m.channel.id === interaction.channel.id, (m) => m.customId === "modify")
322 } catch (e) { break }
323 if (out.fields) {
324 let title = out.fields.getTextInputValue("title");
325 let description = out.fields.getTextInputValue("description");
326 await interaction.channel.send({embeds: [new EmojiEmbed()
327 .setTitle(title)
328 .setDescription(description)
329 .setStatus("Success")
330 .setEmoji("GUILD.TICKET.OPEN")
331 ], components: [new MessageActionRow().addComponents([new MessageButton()
332 .setLabel("Create Ticket")
333 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
334 .setStyle("SUCCESS")
335 .setCustomId("createticket")
336 ])]});
337 break
338 } else { continue }
339 }
340 }
pineafane23c4ec2022-07-27 21:56:27 +0100341 } else if (i.component.customId === "enabled") {
pineafan4edb7762022-06-26 19:21:04 +0100342 await client.database.guilds.write(interaction.guild.id, { "tickets.enabled": !data.enabled })
pineafan6702cef2022-06-13 17:52:37 +0100343 data.enabled = !data.enabled;
pineafane23c4ec2022-07-27 21:56:27 +0100344 } else if (i.component.customId === "manageTypes") {
pineafan6702cef2022-06-13 17:52:37 +0100345 data = await manageTypes(interaction, data, m);
346 } else {
347 break
348 }
349 }
350 await interaction.editReply({ embeds: [embed.setFooter({ text: "Message closed" })], components: [] });
pineafan4f164f32022-02-26 22:07:12 +0000351}
352
pineafan6702cef2022-06-13 17:52:37 +0100353async function manageTypes(interaction, data, m) {
354 while (true) {
355 if (data.useCustom) {
356 let customTypes = data.customTypes;
pineafanc6158ab2022-06-17 16:34:07 +0100357 await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100358 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100359 .setTitle("Tickets > Types")
360 .setDescription(
361 "**Custom types enabled**\n\n" +
362 "**Types in use:**\n" + ((customTypes !== null) ?
363 (customTypes.map((t) => `> ${t}`).join("\n")) :
364 "*None set*"
365 ) + "\n\n" + (customTypes === null ?
366 `${getEmojiByName("TICKETS.REPORT")} Having no types will disable tickets. Please add at least 1 type or use default types` : ""
367 )
368 )
369 .setStatus("Success")
370 .setEmoji("GUILD.TICKET.OPEN")
371 ], components: (customTypes ? [
372 new MessageActionRow().addComponents([new Discord.MessageSelectMenu()
373 .setCustomId("removeTypes")
374 .setPlaceholder("Select types to remove")
375 .setMaxValues(customTypes.length)
376 .setMinValues(1)
377 .addOptions(customTypes.map((t) => new SelectMenuOption().setLabel(t).setValue(t)))
378 ])
379 ] : []).concat([
380 new MessageActionRow().addComponents([
381 new MessageButton()
382 .setLabel("Back")
383 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
384 .setStyle("PRIMARY")
385 .setCustomId("back"),
386 new MessageButton()
387 .setLabel("Add new type")
388 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
389 .setStyle("PRIMARY")
390 .setCustomId("addType")
391 .setDisabled(customTypes !== null && customTypes.length >= 25),
392 new MessageButton()
393 .setLabel("Switch to default types")
394 .setStyle("SECONDARY")
395 .setCustomId("switchToDefault"),
396 ])
397 ])
398 });
399 } else {
400 let inUse = toHexArray(data.types, ticketTypes)
401 let options = [];
402 ticketTypes.forEach(type => {
403 options.push(new SelectMenuOption({
404 label: capitalize(type),
405 value: type,
PineappleFanb3dd83c2022-06-17 10:53:48 +0100406 emoji: client.emojis.cache.get(getEmojiByName(`TICKETS.${type.toUpperCase()}`, "id")),
pineafan6702cef2022-06-13 17:52:37 +0100407 default: inUse.includes(type)
408 }))
409 })
410 let selectPane = new MessageActionRow().addComponents([
411 new Discord.MessageSelectMenu()
412 .addOptions(options)
413 .setCustomId("types")
414 .setMaxValues(ticketTypes.length)
415 .setMinValues(1)
416 .setPlaceholder("Select types to use")
417 ])
pineafanc6158ab2022-06-17 16:34:07 +0100418 await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100419 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100420 .setTitle("Tickets > Types")
421 .setDescription(
422 "**Default types enabled**\n\n" +
423 "**Types in use:**\n" +
424 (inUse.map((t) => `> ${getEmojiByName("TICKETS." + t.toUpperCase())} ${capitalize(t)}`).join("\n"))
425 )
426 .setStatus("Success")
427 .setEmoji("GUILD.TICKET.OPEN")
428 ], components: [
429 selectPane,
430 new MessageActionRow().addComponents([
431 new MessageButton()
432 .setLabel("Back")
433 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
434 .setStyle("PRIMARY")
435 .setCustomId("back"),
436 new MessageButton()
437 .setLabel("Switch to custom types")
438 .setStyle("SECONDARY")
439 .setCustomId("switchToCustom"),
440 ])
441 ]
442 });
443 }
444 let i;
445 try {
pineafanc6158ab2022-06-17 16:34:07 +0100446 i = await m.awaitMessageComponent({ time: 300000 });
pineafan6702cef2022-06-13 17:52:37 +0100447 } catch (e) { break }
pineafane23c4ec2022-07-27 21:56:27 +0100448 if (i.component.customId === "types") {
pineafan6702cef2022-06-13 17:52:37 +0100449 i.deferUpdate()
450 let types = toHexInteger(i.values, ticketTypes);
pineafan4edb7762022-06-26 19:21:04 +0100451 await client.database.guilds.write(interaction.guild.id, { "tickets.types": types })
pineafan6702cef2022-06-13 17:52:37 +0100452 data.types = types;
pineafane23c4ec2022-07-27 21:56:27 +0100453 } else if (i.component.customId === "removeTypes") {
pineafan6702cef2022-06-13 17:52:37 +0100454 i.deferUpdate()
455 let types = i.values
456 let customTypes = data.customTypes;
457 if (customTypes) {
458 customTypes = customTypes.filter((t) => !types.includes(t));
459 customTypes = customTypes.length > 0 ? customTypes : null;
pineafan4edb7762022-06-26 19:21:04 +0100460 await client.database.guilds.write(interaction.guild.id, { "tickets.customTypes": customTypes })
pineafan6702cef2022-06-13 17:52:37 +0100461 data.customTypes = customTypes;
462 }
pineafane23c4ec2022-07-27 21:56:27 +0100463 } else if (i.component.customId === "addType") {
pineafan6702cef2022-06-13 17:52:37 +0100464 await i.showModal(new Discord.Modal().setCustomId("modal").setTitle("Enter a name for the new type").addComponents(
pineafan02ba0232022-07-24 22:16:15 +0100465 new MessageActionRow<TextInputComponent>().addComponents(new TextInputComponent()
pineafan6702cef2022-06-13 17:52:37 +0100466 .setCustomId("type")
467 .setLabel("Name")
468 .setMaxLength(100)
469 .setMinLength(1)
470 .setPlaceholder("E.g. \"Server Idea\"")
471 .setRequired(true)
472 .setStyle("SHORT")
473 )
474 ))
475 await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100476 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100477 .setTitle("Tickets > Types")
478 .setDescription("Modal opened. If you can't see it, click back and try again.")
479 .setStatus("Success")
480 .setEmoji("GUILD.TICKET.OPEN")
481 ], components: [new MessageActionRow().addComponents([new MessageButton()
482 .setLabel("Back")
483 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
484 .setStyle("PRIMARY")
485 .setCustomId("back")
486 ])]
487 });
pineafan4edb7762022-06-26 19:21:04 +0100488 let out;
pineafan6702cef2022-06-13 17:52:37 +0100489 try {
pineafane23c4ec2022-07-27 21:56:27 +0100490 out = await modalInteractionCollector(m, (m) => m.channel.id === interaction.channel.id, (m) => m.customId === "addType")
pineafan6702cef2022-06-13 17:52:37 +0100491 } catch (e) { continue }
492 if (out.fields) {
493 let toAdd = out.fields.getTextInputValue("type");
494 if (!toAdd) { continue }
pineafan4edb7762022-06-26 19:21:04 +0100495 toAdd = toAdd.substring(0, 80)
pineafan6702cef2022-06-13 17:52:37 +0100496 try {
pineafan4edb7762022-06-26 19:21:04 +0100497 await client.database.guilds.append(interaction.guild.id, "tickets.customTypes", toAdd)
pineafan6702cef2022-06-13 17:52:37 +0100498 } catch { continue }
499 data.customTypes = data.customTypes || [];
500 if (!data.customTypes.includes(toAdd)) {
501 data.customTypes.push(toAdd);
502 }
503 } else { continue }
pineafane23c4ec2022-07-27 21:56:27 +0100504 } else if (i.component.customId === "switchToDefault") {
pineafan6702cef2022-06-13 17:52:37 +0100505 i.deferUpdate()
pineafan4edb7762022-06-26 19:21:04 +0100506 await client.database.guilds.write(interaction.guild.id, { "tickets.useCustom": false }, [])
pineafan6702cef2022-06-13 17:52:37 +0100507 data.useCustom = false;
pineafane23c4ec2022-07-27 21:56:27 +0100508 } else if (i.component.customId === "switchToCustom") {
pineafan6702cef2022-06-13 17:52:37 +0100509 i.deferUpdate()
pineafan4edb7762022-06-26 19:21:04 +0100510 await client.database.guilds.write(interaction.guild.id, { "tickets.useCustom": true }, [])
pineafan6702cef2022-06-13 17:52:37 +0100511 data.useCustom = true;
512 } else {
513 i.deferUpdate()
514 break
515 }
516 }
517 return data
518}
519
520
pineafan4f164f32022-02-26 22:07:12 +0000521const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
pineafan6702cef2022-06-13 17:52:37 +0100522 let member = (interaction.member as Discord.GuildMember)
pineafane23c4ec2022-07-27 21:56:27 +0100523 if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the *Manage Server* permission to use this command"
pineafan6702cef2022-06-13 17:52:37 +0100524 return true;
pineafan4f164f32022-02-26 22:07:12 +0000525}
526
527export { command };
528export { callback };
529export { check };