blob: d6bf822d28df2bcfabfd059281fa9dd376061acf [file] [log] [blame]
pineafan813bdf42022-07-24 10:39:10 +01001import Discord, { MessageActionRow, MessageButton } from "discord.js";
2import { tickets, toHexArray } from "../../utils/calculate.js";
3import client from "../../utils/client.js";
4import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
5import getEmojiByName from "../../utils/getEmojiByName.js";
6
7function capitalize(s: string) {
pineafan63fc5e22022-08-04 22:04:10 +01008 s = s.replace(/([A-Z])/g, " $1");
Skyler Grey11236ba2022-08-08 21:13:33 +01009 return s.length < 3 ? s.toUpperCase() : s[0].toUpperCase() + s.slice(1).toLowerCase();
pineafan813bdf42022-07-24 10:39:10 +010010}
11
12export default async function (interaction) {
Skyler Grey11236ba2022-08-08 21:13:33 +010013 const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
pineafan813bdf42022-07-24 10:39:10 +010014
pineafan63fc5e22022-08-04 22:04:10 +010015 const config = await client.database.guilds.read(interaction.guild.id);
pineafan813bdf42022-07-24 10:39:10 +010016 if (!config.tickets.enabled || !config.tickets.category) {
Skyler Grey75ea9172022-08-06 10:22:23 +010017 return await interaction.reply({
18 embeds: [
19 new EmojiEmbed()
20 .setTitle("Tickets are disabled")
Skyler Grey11236ba2022-08-08 21:13:33 +010021 .setDescription("Please enable tickets in the configuration to use this command.")
Skyler Grey75ea9172022-08-06 10:22:23 +010022 .setFooter({
23 text: interaction.member.permissions.has("MANAGE_GUILD")
24 ? "You can enable it by running /settings tickets"
25 : ""
26 })
27 .setStatus("Danger")
28 .setEmoji("CONTROL.BLOCKCROSS")
29 ],
30 ephemeral: true
31 });
pineafan813bdf42022-07-24 10:39:10 +010032 }
Skyler Grey11236ba2022-08-08 21:13:33 +010033 const category = interaction.guild.channels.cache.get(config.tickets.category) as Discord.CategoryChannel;
pineafan813bdf42022-07-24 10:39:10 +010034 let count = 0;
Skyler Grey75ea9172022-08-06 10:22:23 +010035 category.children.forEach((element) => {
pineafane23c4ec2022-07-27 21:56:27 +010036 if (!(element.type === "GUILD_TEXT")) return;
Skyler Grey11236ba2022-08-08 21:13:33 +010037 if ((element as Discord.TextChannel).topic.includes(`${interaction.member.user.id}`)) {
pineafan813bdf42022-07-24 10:39:10 +010038 if ((element as Discord.TextChannel).topic.endsWith("Active")) {
39 count++;
40 }
41 }
42 });
43 if (count >= config.tickets.maxTickets) {
Skyler Grey75ea9172022-08-06 10:22:23 +010044 return await interaction.reply({
45 embeds: [
46 new EmojiEmbed()
47 .setTitle("Create Ticket")
48 .setDescription(
49 `You have reached the maximum amount of tickets (${config.tickets.maxTickets}). Please close one of your active tickets before creating a new one.`
50 )
51 .setStatus("Danger")
52 .setEmoji("CONTROL.BLOCKCROSS")
53 ],
54 ephemeral: true
55 });
pineafan813bdf42022-07-24 10:39:10 +010056 }
57 let ticketTypes;
pineafan63fc5e22022-08-04 22:04:10 +010058 let custom = false;
Skyler Grey75ea9172022-08-06 10:22:23 +010059 if (config.tickets.customTypes && config.tickets.useCustom) {
60 ticketTypes = config.tickets.customTypes;
61 custom = true;
Skyler Grey11236ba2022-08-08 21:13:33 +010062 } else if (config.tickets.types) ticketTypes = toHexArray(config.tickets.types, tickets);
pineafan813bdf42022-07-24 10:39:10 +010063 else ticketTypes = [];
64 let chosenType;
65 let splitFormattedTicketTypes = [];
66 if (ticketTypes.length > 0) {
67 let formattedTicketTypes = [];
Skyler Grey75ea9172022-08-06 10:22:23 +010068 formattedTicketTypes = ticketTypes.map((type) => {
pineafan813bdf42022-07-24 10:39:10 +010069 if (custom) {
Skyler Grey11236ba2022-08-08 21:13:33 +010070 return new MessageButton().setLabel(type).setStyle("PRIMARY").setCustomId(type);
pineafan813bdf42022-07-24 10:39:10 +010071 } else {
72 return new MessageButton()
73 .setLabel(capitalize(type))
74 .setStyle("PRIMARY")
75 .setCustomId(type)
Skyler Grey11236ba2022-08-08 21:13:33 +010076 .setEmoji(getEmojiByName("TICKETS." + type.toString().toUpperCase(), "id"));
pineafan813bdf42022-07-24 10:39:10 +010077 }
78 });
79 for (let i = 0; i < formattedTicketTypes.length; i += 5) {
Skyler Grey11236ba2022-08-08 21:13:33 +010080 splitFormattedTicketTypes.push(new MessageActionRow().addComponents(formattedTicketTypes.slice(i, i + 5)));
pineafan813bdf42022-07-24 10:39:10 +010081 }
Skyler Grey75ea9172022-08-06 10:22:23 +010082 const m = await interaction.reply({
83 embeds: [
84 new EmojiEmbed()
85 .setTitle("Create Ticket")
86 .setDescription("Select a ticket type")
87 .setStatus("Success")
88 .setEmoji("GUILD.TICKET.OPEN")
89 ],
90 ephemeral: true,
91 fetchReply: true,
92 components: splitFormattedTicketTypes
93 });
pineafan813bdf42022-07-24 10:39:10 +010094 let component;
95 try {
Skyler Grey75ea9172022-08-06 10:22:23 +010096 component = await m.awaitMessageComponent({ time: 300000 });
pineafan813bdf42022-07-24 10:39:10 +010097 } catch (e) {
98 return;
99 }
100 chosenType = component.customId;
101 splitFormattedTicketTypes = [];
102 formattedTicketTypes = [];
Skyler Grey75ea9172022-08-06 10:22:23 +0100103 formattedTicketTypes = ticketTypes.map((type) => {
pineafan813bdf42022-07-24 10:39:10 +0100104 if (custom) {
105 return new MessageButton()
106 .setLabel(type)
pineafane23c4ec2022-07-27 21:56:27 +0100107 .setStyle(chosenType === type ? "SUCCESS" : "SECONDARY")
pineafan813bdf42022-07-24 10:39:10 +0100108 .setCustomId(type)
pineafan63fc5e22022-08-04 22:04:10 +0100109 .setDisabled(true);
110 } else {
111 return new MessageButton()
pineafan813bdf42022-07-24 10:39:10 +0100112 .setLabel(capitalize(type))
pineafane23c4ec2022-07-27 21:56:27 +0100113 .setStyle(chosenType === type ? "SUCCESS" : "SECONDARY")
pineafan813bdf42022-07-24 10:39:10 +0100114 .setCustomId(type)
Skyler Grey11236ba2022-08-08 21:13:33 +0100115 .setEmoji(getEmojiByName("TICKETS." + type.toString().toUpperCase(), "id"))
pineafan63fc5e22022-08-04 22:04:10 +0100116 .setDisabled(true);
pineafan813bdf42022-07-24 10:39:10 +0100117 }
118 });
119 for (let i = 0; i < formattedTicketTypes.length; i += 5) {
Skyler Grey11236ba2022-08-08 21:13:33 +0100120 splitFormattedTicketTypes.push(new MessageActionRow().addComponents(formattedTicketTypes.slice(i, i + 5)));
pineafan813bdf42022-07-24 10:39:10 +0100121 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100122 component.update({
123 embeds: [
124 new EmojiEmbed()
125 .setTitle("Create Ticket")
126 .setDescription("Select a ticket type")
127 .setStatus("Success")
128 .setEmoji("GUILD.TICKET.OPEN")
129 ],
130 components: splitFormattedTicketTypes
131 });
pineafan813bdf42022-07-24 10:39:10 +0100132 } else {
pineafan63fc5e22022-08-04 22:04:10 +0100133 chosenType = null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100134 await interaction.reply({
Skyler Grey11236ba2022-08-08 21:13:33 +0100135 embeds: [new EmojiEmbed().setTitle("Create Ticket").setEmoji("GUILD.TICKET.OPEN")],
Skyler Grey75ea9172022-08-06 10:22:23 +0100136 ephemeral: true,
137 components: splitFormattedTicketTypes
138 });
pineafan813bdf42022-07-24 10:39:10 +0100139 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100140 const overwrites = [
141 {
142 id: interaction.member,
Skyler Grey11236ba2022-08-08 21:13:33 +0100143 allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
Skyler Grey75ea9172022-08-06 10:22:23 +0100144 type: "member"
145 }
146 ] as Discord.OverwriteResolvable[];
pineafan813bdf42022-07-24 10:39:10 +0100147 overwrites.push({
148 id: interaction.guild.roles.everyone,
149 deny: ["VIEW_CHANNEL"],
150 type: "role"
pineafan63fc5e22022-08-04 22:04:10 +0100151 });
pineafane23c4ec2022-07-27 21:56:27 +0100152 if (config.tickets.supportRole !== null) {
pineafan813bdf42022-07-24 10:39:10 +0100153 overwrites.push({
154 id: interaction.guild.roles.cache.get(config.tickets.supportRole),
Skyler Grey11236ba2022-08-08 21:13:33 +0100155 allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
pineafan813bdf42022-07-24 10:39:10 +0100156 type: "role"
pineafan63fc5e22022-08-04 22:04:10 +0100157 });
pineafan813bdf42022-07-24 10:39:10 +0100158 }
159
160 let c;
161 try {
Skyler Grey11236ba2022-08-08 21:13:33 +0100162 c = await interaction.guild.channels.create(interaction.member.user.username, {
163 type: "GUILD_TEXT",
164 topic: `${interaction.member.user.id} Active`,
165 parent: config.tickets.category,
166 nsfw: false,
167 permissionOverwrites: overwrites as Discord.OverwriteResolvable[],
168 reason: "Creating ticket"
169 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100170 } catch (e) {
171 return await interaction.editReply({
172 embeds: [
173 new EmojiEmbed()
174 .setTitle("Create Ticket")
175 .setDescription("Failed to create ticket")
176 .setStatus("Danger")
177 .setEmoji("CONTROL.BLOCKCROSS")
178 ]
179 });
180 }
181 try {
182 await c.send({
183 content:
184 `<@${interaction.member.user.id}>` +
Skyler Grey11236ba2022-08-08 21:13:33 +0100185 (config.tickets.supportRole !== null ? ` • <@&${config.tickets.supportRole}>` : ""),
Skyler Grey75ea9172022-08-06 10:22:23 +0100186 allowedMentions: {
187 users: [(interaction.member as Discord.GuildMember).id],
Skyler Grey11236ba2022-08-08 21:13:33 +0100188 roles: config.tickets.supportRole !== null ? [config.tickets.supportRole] : []
Skyler Grey75ea9172022-08-06 10:22:23 +0100189 }
190 });
Skyler Grey11236ba2022-08-08 21:13:33 +0100191 let content = interaction.options ? interaction.options.getString("message") || "" : "";
pineafan813bdf42022-07-24 10:39:10 +0100192 if (content) content = `**Message:**\n> ${content}\n`;
Skyler Grey11236ba2022-08-08 21:13:33 +0100193 const emoji = custom ? "" : getEmojiByName("TICKETS." + chosenType.toUpperCase());
Skyler Grey75ea9172022-08-06 10:22:23 +0100194 await c.send({
195 embeds: [
196 new EmojiEmbed()
197 .setTitle("New Ticket")
198 .setDescription(
199 `Ticket created by <@${interaction.member.user.id}>\n` +
200 `**Support type:** ${
Skyler Grey11236ba2022-08-08 21:13:33 +0100201 chosenType !== null ? emoji + " " + capitalize(chosenType) : "General"
Skyler Grey75ea9172022-08-06 10:22:23 +0100202 }\n` +
203 `**Ticket ID:** \`${c.id}\`\n${content}\n` +
204 "Type `/ticket close` to close this ticket."
205 )
206 .setStatus("Success")
207 .setEmoji("GUILD.TICKET.OPEN")
208 ],
209 components: [
210 new MessageActionRow().addComponents([
211 new MessageButton()
212 .setLabel("Close")
213 .setStyle("DANGER")
214 .setCustomId("closeticket")
215 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
216 ])
217 ]
218 });
pineafan63fc5e22022-08-04 22:04:10 +0100219 const data = {
Skyler Grey75ea9172022-08-06 10:22:23 +0100220 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100221 type: "ticketCreate",
222 displayName: "Ticket Created",
pineafan813bdf42022-07-24 10:39:10 +0100223 calculateType: "ticketUpdate",
224 color: NucleusColors.green,
pineafan63fc5e22022-08-04 22:04:10 +0100225 emoji: "GUILD.TICKET.OPEN",
pineafan813bdf42022-07-24 10:39:10 +0100226 timestamp: new Date().getTime()
227 },
228 list: {
Skyler Grey11236ba2022-08-08 21:13:33 +0100229 ticketFor: entry(interaction.member.user.id, renderUser(interaction.member.user)),
230 created: entry(new Date().getTime(), renderDelta(new Date().getTime())),
pineafan63fc5e22022-08-04 22:04:10 +0100231 ticketChannel: entry(c.id, renderChannel(c))
pineafan813bdf42022-07-24 10:39:10 +0100232 },
233 hidden: {
234 guild: interaction.guild.id
235 }
pineafan63fc5e22022-08-04 22:04:10 +0100236 };
pineafan813bdf42022-07-24 10:39:10 +0100237 log(data);
Skyler Grey75ea9172022-08-06 10:22:23 +0100238 } catch (e) {
239 console.log(e);
240 }
241 await interaction.editReply({
242 embeds: [
243 new EmojiEmbed()
244 .setTitle("Create Ticket")
Skyler Grey11236ba2022-08-08 21:13:33 +0100245 .setDescription(`Ticket created. You can view it here: <#${c.id}>`)
Skyler Grey75ea9172022-08-06 10:22:23 +0100246 .setStatus("Success")
247 .setEmoji("GUILD.TICKET.OPEN")
248 ],
249 components: splitFormattedTicketTypes
250 });
251}