blob: 8ebcf30146b2f28b3aa403aff698c4829bbbd170 [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;
pineafanc1c18792022-08-03 21:41:36 +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 }
pineafanc1c18792022-08-03 21:41:36 +010032 console.log(m)
pineafan6702cef2022-06-13 17:52:37 +010033 if (options.enabled !== null || options.category || options.maxtickets || options.supportping) {
34 options.enabled = options.enabled === "yes" ? true : false;
35 if (options.category) {
36 let channel
37 try {
38 channel = interaction.guild.channels.cache.get(options.category.id)
39 } catch {
40 return await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010041 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +010042 .setEmoji("CHANNEL.TEXT.DELETE")
43 .setTitle("Tickets > Category")
44 .setDescription("The channel you provided is not a valid category")
45 .setStatus("Danger")
46 ]
47 })
48 }
49 channel = channel as Discord.CategoryChannel
pineafane23c4ec2022-07-27 21:56:27 +010050 if (channel.guild.id !== interaction.guild.id) return interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010051 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +010052 .setTitle("Tickets > Category")
53 .setDescription(`You must choose a category in this server`)
54 .setStatus("Danger")
55 .setEmoji("CHANNEL.TEXT.DELETE")
56 ]
57 });
58 }
59 if (options.maxtickets) {
60 if (options.maxtickets < 1) return interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010061 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +010062 .setTitle("Tickets > Max Tickets")
63 .setDescription(`You must choose a number greater than 0`)
64 .setStatus("Danger")
65 .setEmoji("CHANNEL.TEXT.DELETE")
66 ]
67 });
68 }
69 let role
70 if (options.supportping) {
71 try {
72 role = interaction.guild.roles.cache.get(options.supportping.id)
73 } catch {
74 return await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010075 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +010076 .setEmoji("GUILD.ROLE.DELETE")
77 .setTitle("Tickets > Support Ping")
78 .setDescription("The role you provided is not a valid role")
79 .setStatus("Danger")
80 ]
81 })
82 }
83 role = role as Discord.Role
pineafane23c4ec2022-07-27 21:56:27 +010084 if (role.guild.id !== interaction.guild.id) return interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010085 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +010086 .setTitle("Tickets > Support Ping")
87 .setDescription(`You must choose a role in this server`)
88 .setStatus("Danger")
89 .setEmoji("GUILD.ROLE.DELETE")
90 ]
91 });
92 }
93
94 let confirmation = await new confirmationMessage(interaction)
95 .setEmoji("GUILD.TICKET.ARCHIVED")
96 .setTitle("Tickets")
97 .setDescription(
98 (options.category ? `**Category:** ${options.category.name}\n` : "") +
99 (options.maxtickets ? `**Max Tickets:** ${options.maxtickets}\n` : "") +
100 (options.supportping ? `**Support Ping:** ${options.supportping.name}\n` : "") +
101 (options.enabled !== null ? `**Enabled:** ${options.enabled ? `${getEmojiByName("CONTROL.TICK")} Yes` : `${getEmojiByName("CONTROL.CROSS")} No`
102 }\n` : "") +
103 `\nAre you sure you want to apply these settings?`
104 )
105 .setColor("Warning")
106 .setInverted(true)
107 .send(true)
pineafan02ba0232022-07-24 22:16:15 +0100108 if (confirmation.cancelled) return
pineafan6702cef2022-06-13 17:52:37 +0100109 if (confirmation.success) {
110 let toUpdate = {}
111 if (options.enabled !== null) toUpdate["tickets.enabled"] = options.enabled
112 if (options.category) toUpdate["tickets.category"] = options.category.id
113 if (options.maxtickets) toUpdate["tickets.maxTickets"] = options.maxtickets
114 if (options.supportping) toUpdate["tickets.supportRole"] = options.supportping.id
115 try {
pineafan4edb7762022-06-26 19:21:04 +0100116 await client.database.guilds.write(interaction.guild.id, toUpdate)
pineafan6702cef2022-06-13 17:52:37 +0100117 } catch (e) {
118 return interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100119 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100120 .setTitle("Tickets")
121 .setDescription(`Something went wrong and the staff notifications channel could not be set`)
122 .setStatus("Danger")
123 .setEmoji("GUILD.TICKET.DELETE")
124 ], components: []
125 });
126 }
127 } else {
128 return interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100129 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100130 .setTitle("Tickets")
131 .setDescription(`No changes were made`)
132 .setStatus("Success")
133 .setEmoji("GUILD.TICKET.OPEN")
134 ], components: []
135 });
136 }
137 }
pineafan4edb7762022-06-26 19:21:04 +0100138 let data = await client.database.guilds.read(interaction.guild.id);
pineafan73a7c4a2022-07-24 10:38:04 +0100139 data.tickets.customTypes = (data.tickets.customTypes || []).filter((v, i, a) => a.indexOf(v) === i)
pineafan6702cef2022-06-13 17:52:37 +0100140 let lastClicked = "";
141 let embed;
142 data = {
143 enabled: data.tickets.enabled,
144 category: data.tickets.category,
145 maxTickets: data.tickets.maxTickets,
146 supportRole: data.tickets.supportRole,
147 useCustom: data.tickets.useCustom,
148 types: data.tickets.types,
149 customTypes: data.tickets.customTypes
150 }
151 while (true) {
pineafan4edb7762022-06-26 19:21:04 +0100152 embed = new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100153 .setTitle("Tickets")
154 .setDescription(
155 `${data.enabled ? "" : getEmojiByName("TICKETS.REPORT")} **Enabled:** ${data.enabled ? `${getEmojiByName("CONTROL.TICK")} Yes` : `${getEmojiByName("CONTROL.CROSS")} No`}\n` +
156 `${data.category ? "" : getEmojiByName("TICKETS.REPORT")} **Category:** ${data.category ? `<#${data.category}>` : "*None set*"}\n` +
157 `**Max Tickets:** ${data.maxTickets ? data.maxTickets : "*No limit*"}\n` +
158 `**Support Ping:** ${data.supportRole ? `<@&${data.supportRole}>` : "*None set*"}\n\n` +
159 ((data.useCustom && data.customTypes === null) ? `${getEmojiByName("TICKETS.REPORT")} ` : "") +
160 `${data.useCustom ? "Custom" : "Default"} types in use` + "\n\n" +
161 `${getEmojiByName("TICKETS.REPORT")} *Indicates a setting stopping tickets from being used*`
162 )
163 .setStatus("Success")
164 .setEmoji("GUILD.TICKET.OPEN")
165 m = await interaction.editReply({
166 embeds: [embed], components: [new MessageActionRow().addComponents([
167 new MessageButton()
168 .setLabel("Tickets " + (data.enabled ? "enabled" : "disabled"))
169 .setEmoji(getEmojiByName("CONTROL." + (data.enabled ? "TICK" : "CROSS"), "id"))
170 .setStyle(data.enabled ? "SUCCESS" : "DANGER")
171 .setCustomId("enabled"),
172 new MessageButton()
pineafane23c4ec2022-07-27 21:56:27 +0100173 .setLabel(lastClicked === "cat" ? "Click again to confirm" : "Clear category")
pineafan6702cef2022-06-13 17:52:37 +0100174 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
175 .setStyle("DANGER")
176 .setCustomId("clearCategory")
pineafane23c4ec2022-07-27 21:56:27 +0100177 .setDisabled(data.category === null),
pineafan6702cef2022-06-13 17:52:37 +0100178 new MessageButton()
pineafane23c4ec2022-07-27 21:56:27 +0100179 .setLabel(lastClicked === "max" ? "Click again to confirm" : "Reset max tickets")
pineafan6702cef2022-06-13 17:52:37 +0100180 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
181 .setStyle("DANGER")
182 .setCustomId("clearMaxTickets")
pineafane23c4ec2022-07-27 21:56:27 +0100183 .setDisabled(data.maxTickets === 5),
pineafan6702cef2022-06-13 17:52:37 +0100184 new MessageButton()
pineafane23c4ec2022-07-27 21:56:27 +0100185 .setLabel(lastClicked === "sup" ? "Click again to confirm" : "Clear support ping")
pineafan6702cef2022-06-13 17:52:37 +0100186 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
187 .setStyle("DANGER")
188 .setCustomId("clearSupportPing")
pineafane23c4ec2022-07-27 21:56:27 +0100189 .setDisabled(data.supportRole === null),
pineafan6702cef2022-06-13 17:52:37 +0100190 ]), new MessageActionRow().addComponents([
191 new MessageButton()
192 .setLabel("Manage types")
193 .setEmoji(getEmojiByName("TICKETS.OTHER", "id"))
194 .setStyle("SECONDARY")
195 .setCustomId("manageTypes"),
pineafan41d93562022-07-30 22:10:15 +0100196 new MessageButton()
197 .setLabel("Add create ticket button")
198 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
199 .setStyle("PRIMARY")
200 .setCustomId("send"),
pineafan6702cef2022-06-13 17:52:37 +0100201 ])]
202 });
203 let i;
204 try {
pineafanc6158ab2022-06-17 16:34:07 +0100205 i = await m.awaitMessageComponent({ time: 300000 });
pineafan6702cef2022-06-13 17:52:37 +0100206 } catch (e) { break }
207 i.deferUpdate()
pineafane23c4ec2022-07-27 21:56:27 +0100208 if (i.component.customId === "clearCategory") {
209 if (lastClicked === "cat") {
pineafan6702cef2022-06-13 17:52:37 +0100210 lastClicked = "";
pineafane23c4ec2022-07-27 21:56:27 +0100211 await client.database.guilds.write(interaction.guild.id, null, ["tickets.category"])
pineafan6702cef2022-06-13 17:52:37 +0100212 data.category = undefined;
213 } else lastClicked = "cat";
pineafane23c4ec2022-07-27 21:56:27 +0100214 } else if (i.component.customId === "clearMaxTickets") {
215 if (lastClicked === "max") {
pineafan6702cef2022-06-13 17:52:37 +0100216 lastClicked = "";
pineafane23c4ec2022-07-27 21:56:27 +0100217 await client.database.guilds.write(interaction.guild.id, null, ["tickets.maxTickets"])
pineafan6702cef2022-06-13 17:52:37 +0100218 data.maxTickets = 5;
219 } else lastClicked = "max";
pineafane23c4ec2022-07-27 21:56:27 +0100220 } else if (i.component.customId === "clearSupportPing") {
221 if (lastClicked === "sup") {
pineafan6702cef2022-06-13 17:52:37 +0100222 lastClicked = "";
pineafane23c4ec2022-07-27 21:56:27 +0100223 await client.database.guilds.write(interaction.guild.id, null, ["tickets.supportRole"])
pineafan6702cef2022-06-13 17:52:37 +0100224 data.supportRole = undefined;
225 } else lastClicked = "sup";
pineafan41d93562022-07-30 22:10:15 +0100226 } else if (i.component.customId === "send") {
227 const ticketMessages = [
228 {label: "Create ticket", description: "Click the button below to create a ticket"},
229 {label: "Issues, questions or feedback?", description: "Click below to open a ticket and get help from our staff team"},
230 {label: "Contact Us", description: "Click the button below to speak to us privately"},
231 ]
232 while (true) {
233 let enabled = data.enabled && data.category !== null;
234 await interaction.editReply({embeds: [new EmojiEmbed()
235 .setTitle("Ticket Button")
236 .setDescription("Select a message template to send in this channel")
237 .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."})
238 .setStatus(enabled ? "Success" : "Warning")
239 .setEmoji("GUILD.ROLES.CREATE")
240 ], components: [
241 new MessageActionRow().addComponents([
242 new MessageSelectMenu().setOptions(ticketMessages.map((t: {label: string, description: string, value?: string}, index) => {
243 t.value = index.toString(); return t as {value: string, label: string, description: string}
244 })).setCustomId("template").setMaxValues(1).setMinValues(1).setPlaceholder("Select a message template"),
245 ]),
246 new MessageActionRow().addComponents([
247 new MessageButton()
248 .setCustomId("back")
249 .setLabel("Back")
250 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
251 .setStyle("DANGER"),
252 new MessageButton()
253 .setCustomId("blank")
254 .setLabel("Empty")
255 .setStyle("SECONDARY"),
256 new MessageButton()
257 .setCustomId("custom")
258 .setLabel("Custom")
259 .setEmoji(getEmojiByName("TICKETS.OTHER", "id"))
260 .setStyle("PRIMARY")
261 ])
262 ]});
263 let i;
264 try {
265 i = await m.awaitMessageComponent({time: 300000});
266 } catch(e) { break }
267 if (i.component.customId === "template") {
268 i.deferUpdate()
269 await interaction.channel.send({embeds: [new EmojiEmbed()
270 .setTitle(ticketMessages[parseInt(i.values[0])].label)
271 .setDescription(ticketMessages[parseInt(i.values[0])].description)
272 .setStatus("Success")
273 .setEmoji("GUILD.TICKET.OPEN")
274 ], components: [new MessageActionRow().addComponents([new MessageButton()
275 .setLabel("Create Ticket")
276 .setEmoji(getEmojiByName("CONTROL.TICK", "id"))
277 .setStyle("SUCCESS")
278 .setCustomId("createticket")
279 ])]});
280 break
281 } else if (i.component.customId === "blank") {
282 i.deferUpdate()
283 await interaction.channel.send({components: [new MessageActionRow().addComponents([new MessageButton()
284 .setLabel("Create Ticket")
285 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
286 .setStyle("SUCCESS")
287 .setCustomId("createticket")
288 ])]});
289 break
290 } else if (i.component.customId === "custom") {
291 await i.showModal(new Discord.Modal().setCustomId("modal").setTitle(`Enter embed details`).addComponents(
292 new MessageActionRow<TextInputComponent>().addComponents(new TextInputComponent()
293 .setCustomId("title")
294 .setLabel("Title")
295 .setMaxLength(256)
296 .setRequired(true)
297 .setStyle("SHORT")
298 ),
299 new MessageActionRow<TextInputComponent>().addComponents(new TextInputComponent()
300 .setCustomId("description")
301 .setLabel("Description")
302 .setMaxLength(4000)
303 .setRequired(true)
304 .setStyle("PARAGRAPH")
305 )
306 ))
307 await interaction.editReply({
308 embeds: [new EmojiEmbed()
309 .setTitle("Ticket Button")
310 .setDescription("Modal opened. If you can't see it, click back and try again.")
311 .setStatus("Success")
312 .setEmoji("GUILD.TICKET.OPEN")
313 ], components: [new MessageActionRow().addComponents([new MessageButton()
314 .setLabel("Back")
315 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
316 .setStyle("PRIMARY")
317 .setCustomId("back")
318 ])]
319 });
320 let out;
321 try {
322 out = await modalInteractionCollector(m, (m) => m.channel.id === interaction.channel.id, (m) => m.customId === "modify")
323 } catch (e) { break }
324 if (out.fields) {
325 let title = out.fields.getTextInputValue("title");
326 let description = out.fields.getTextInputValue("description");
327 await interaction.channel.send({embeds: [new EmojiEmbed()
328 .setTitle(title)
329 .setDescription(description)
330 .setStatus("Success")
331 .setEmoji("GUILD.TICKET.OPEN")
332 ], components: [new MessageActionRow().addComponents([new MessageButton()
333 .setLabel("Create Ticket")
334 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
335 .setStyle("SUCCESS")
336 .setCustomId("createticket")
337 ])]});
338 break
339 } else { continue }
340 }
341 }
pineafane23c4ec2022-07-27 21:56:27 +0100342 } else if (i.component.customId === "enabled") {
pineafan4edb7762022-06-26 19:21:04 +0100343 await client.database.guilds.write(interaction.guild.id, { "tickets.enabled": !data.enabled })
pineafan6702cef2022-06-13 17:52:37 +0100344 data.enabled = !data.enabled;
pineafane23c4ec2022-07-27 21:56:27 +0100345 } else if (i.component.customId === "manageTypes") {
pineafan6702cef2022-06-13 17:52:37 +0100346 data = await manageTypes(interaction, data, m);
347 } else {
348 break
349 }
350 }
351 await interaction.editReply({ embeds: [embed.setFooter({ text: "Message closed" })], components: [] });
pineafan4f164f32022-02-26 22:07:12 +0000352}
353
pineafan6702cef2022-06-13 17:52:37 +0100354async function manageTypes(interaction, data, m) {
355 while (true) {
356 if (data.useCustom) {
357 let customTypes = data.customTypes;
pineafanc6158ab2022-06-17 16:34:07 +0100358 await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100359 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100360 .setTitle("Tickets > Types")
361 .setDescription(
362 "**Custom types enabled**\n\n" +
363 "**Types in use:**\n" + ((customTypes !== null) ?
364 (customTypes.map((t) => `> ${t}`).join("\n")) :
365 "*None set*"
366 ) + "\n\n" + (customTypes === null ?
367 `${getEmojiByName("TICKETS.REPORT")} Having no types will disable tickets. Please add at least 1 type or use default types` : ""
368 )
369 )
370 .setStatus("Success")
371 .setEmoji("GUILD.TICKET.OPEN")
372 ], components: (customTypes ? [
373 new MessageActionRow().addComponents([new Discord.MessageSelectMenu()
374 .setCustomId("removeTypes")
375 .setPlaceholder("Select types to remove")
376 .setMaxValues(customTypes.length)
377 .setMinValues(1)
378 .addOptions(customTypes.map((t) => new SelectMenuOption().setLabel(t).setValue(t)))
379 ])
380 ] : []).concat([
381 new MessageActionRow().addComponents([
382 new MessageButton()
383 .setLabel("Back")
384 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
385 .setStyle("PRIMARY")
386 .setCustomId("back"),
387 new MessageButton()
388 .setLabel("Add new type")
389 .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
390 .setStyle("PRIMARY")
391 .setCustomId("addType")
392 .setDisabled(customTypes !== null && customTypes.length >= 25),
393 new MessageButton()
394 .setLabel("Switch to default types")
395 .setStyle("SECONDARY")
396 .setCustomId("switchToDefault"),
397 ])
398 ])
399 });
400 } else {
401 let inUse = toHexArray(data.types, ticketTypes)
402 let options = [];
403 ticketTypes.forEach(type => {
404 options.push(new SelectMenuOption({
405 label: capitalize(type),
406 value: type,
PineappleFanb3dd83c2022-06-17 10:53:48 +0100407 emoji: client.emojis.cache.get(getEmojiByName(`TICKETS.${type.toUpperCase()}`, "id")),
pineafan6702cef2022-06-13 17:52:37 +0100408 default: inUse.includes(type)
409 }))
410 })
411 let selectPane = new MessageActionRow().addComponents([
412 new Discord.MessageSelectMenu()
413 .addOptions(options)
414 .setCustomId("types")
415 .setMaxValues(ticketTypes.length)
416 .setMinValues(1)
417 .setPlaceholder("Select types to use")
418 ])
pineafanc6158ab2022-06-17 16:34:07 +0100419 await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100420 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100421 .setTitle("Tickets > Types")
422 .setDescription(
423 "**Default types enabled**\n\n" +
424 "**Types in use:**\n" +
425 (inUse.map((t) => `> ${getEmojiByName("TICKETS." + t.toUpperCase())} ${capitalize(t)}`).join("\n"))
426 )
427 .setStatus("Success")
428 .setEmoji("GUILD.TICKET.OPEN")
429 ], components: [
430 selectPane,
431 new MessageActionRow().addComponents([
432 new MessageButton()
433 .setLabel("Back")
434 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
435 .setStyle("PRIMARY")
436 .setCustomId("back"),
437 new MessageButton()
438 .setLabel("Switch to custom types")
439 .setStyle("SECONDARY")
440 .setCustomId("switchToCustom"),
441 ])
442 ]
443 });
444 }
445 let i;
446 try {
pineafanc6158ab2022-06-17 16:34:07 +0100447 i = await m.awaitMessageComponent({ time: 300000 });
pineafan6702cef2022-06-13 17:52:37 +0100448 } catch (e) { break }
pineafane23c4ec2022-07-27 21:56:27 +0100449 if (i.component.customId === "types") {
pineafan6702cef2022-06-13 17:52:37 +0100450 i.deferUpdate()
451 let types = toHexInteger(i.values, ticketTypes);
pineafan4edb7762022-06-26 19:21:04 +0100452 await client.database.guilds.write(interaction.guild.id, { "tickets.types": types })
pineafan6702cef2022-06-13 17:52:37 +0100453 data.types = types;
pineafane23c4ec2022-07-27 21:56:27 +0100454 } else if (i.component.customId === "removeTypes") {
pineafan6702cef2022-06-13 17:52:37 +0100455 i.deferUpdate()
456 let types = i.values
457 let customTypes = data.customTypes;
458 if (customTypes) {
459 customTypes = customTypes.filter((t) => !types.includes(t));
460 customTypes = customTypes.length > 0 ? customTypes : null;
pineafan4edb7762022-06-26 19:21:04 +0100461 await client.database.guilds.write(interaction.guild.id, { "tickets.customTypes": customTypes })
pineafan6702cef2022-06-13 17:52:37 +0100462 data.customTypes = customTypes;
463 }
pineafane23c4ec2022-07-27 21:56:27 +0100464 } else if (i.component.customId === "addType") {
pineafan6702cef2022-06-13 17:52:37 +0100465 await i.showModal(new Discord.Modal().setCustomId("modal").setTitle("Enter a name for the new type").addComponents(
pineafan02ba0232022-07-24 22:16:15 +0100466 new MessageActionRow<TextInputComponent>().addComponents(new TextInputComponent()
pineafan6702cef2022-06-13 17:52:37 +0100467 .setCustomId("type")
468 .setLabel("Name")
469 .setMaxLength(100)
470 .setMinLength(1)
471 .setPlaceholder("E.g. \"Server Idea\"")
472 .setRequired(true)
473 .setStyle("SHORT")
474 )
475 ))
476 await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100477 embeds: [new EmojiEmbed()
pineafan6702cef2022-06-13 17:52:37 +0100478 .setTitle("Tickets > Types")
479 .setDescription("Modal opened. If you can't see it, click back and try again.")
480 .setStatus("Success")
481 .setEmoji("GUILD.TICKET.OPEN")
482 ], components: [new MessageActionRow().addComponents([new MessageButton()
483 .setLabel("Back")
484 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
485 .setStyle("PRIMARY")
486 .setCustomId("back")
487 ])]
488 });
pineafan4edb7762022-06-26 19:21:04 +0100489 let out;
pineafan6702cef2022-06-13 17:52:37 +0100490 try {
pineafane23c4ec2022-07-27 21:56:27 +0100491 out = await modalInteractionCollector(m, (m) => m.channel.id === interaction.channel.id, (m) => m.customId === "addType")
pineafan6702cef2022-06-13 17:52:37 +0100492 } catch (e) { continue }
493 if (out.fields) {
494 let toAdd = out.fields.getTextInputValue("type");
495 if (!toAdd) { continue }
pineafan4edb7762022-06-26 19:21:04 +0100496 toAdd = toAdd.substring(0, 80)
pineafan6702cef2022-06-13 17:52:37 +0100497 try {
pineafan4edb7762022-06-26 19:21:04 +0100498 await client.database.guilds.append(interaction.guild.id, "tickets.customTypes", toAdd)
pineafan6702cef2022-06-13 17:52:37 +0100499 } catch { continue }
500 data.customTypes = data.customTypes || [];
501 if (!data.customTypes.includes(toAdd)) {
502 data.customTypes.push(toAdd);
503 }
504 } else { continue }
pineafane23c4ec2022-07-27 21:56:27 +0100505 } else if (i.component.customId === "switchToDefault") {
pineafan6702cef2022-06-13 17:52:37 +0100506 i.deferUpdate()
pineafan4edb7762022-06-26 19:21:04 +0100507 await client.database.guilds.write(interaction.guild.id, { "tickets.useCustom": false }, [])
pineafan6702cef2022-06-13 17:52:37 +0100508 data.useCustom = false;
pineafane23c4ec2022-07-27 21:56:27 +0100509 } else if (i.component.customId === "switchToCustom") {
pineafan6702cef2022-06-13 17:52:37 +0100510 i.deferUpdate()
pineafan4edb7762022-06-26 19:21:04 +0100511 await client.database.guilds.write(interaction.guild.id, { "tickets.useCustom": true }, [])
pineafan6702cef2022-06-13 17:52:37 +0100512 data.useCustom = true;
513 } else {
514 i.deferUpdate()
515 break
516 }
517 }
518 return data
519}
520
521
pineafan4f164f32022-02-26 22:07:12 +0000522const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
pineafan6702cef2022-06-13 17:52:37 +0100523 let member = (interaction.member as Discord.GuildMember)
pineafane23c4ec2022-07-27 21:56:27 +0100524 if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the *Manage Server* permission to use this command"
pineafan6702cef2022-06-13 17:52:37 +0100525 return true;
pineafan4f164f32022-02-26 22:07:12 +0000526}
527
528export { command };
529export { callback };
530export { check };