blob: 595a5b3f9b00add6dfb8f8ff5551e4c9465b839c [file] [log] [blame]
PineaFan538d3752023-01-12 21:48:23 +00001import Discord, { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, ButtonInteraction } from "discord.js";
pineafan813bdf42022-07-24 10:39:10 +01002import { 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
PineaFan538d3752023-01-12 21:48:23 +000012export default async function (interaction: CommandInteraction | ButtonInteraction) {
PineaFana00db1b2023-01-02 15:32:54 +000013 if (!interaction.guild) return;
Skyler Grey11236ba2022-08-08 21:13:33 +010014 const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
pineafan813bdf42022-07-24 10:39:10 +010015
pineafan63fc5e22022-08-04 22:04:10 +010016 const config = await client.database.guilds.read(interaction.guild.id);
pineafan813bdf42022-07-24 10:39:10 +010017 if (!config.tickets.enabled || !config.tickets.category) {
Skyler Grey75ea9172022-08-06 10:22:23 +010018 return await interaction.reply({
19 embeds: [
20 new EmojiEmbed()
21 .setTitle("Tickets are disabled")
Skyler Grey11236ba2022-08-08 21:13:33 +010022 .setDescription("Please enable tickets in the configuration to use this command.")
Skyler Grey75ea9172022-08-06 10:22:23 +010023 .setFooter({
24 text: interaction.member.permissions.has("MANAGE_GUILD")
25 ? "You can enable it by running /settings tickets"
26 : ""
27 })
28 .setStatus("Danger")
29 .setEmoji("CONTROL.BLOCKCROSS")
30 ],
31 ephemeral: true
32 });
pineafan813bdf42022-07-24 10:39:10 +010033 }
Skyler Grey11236ba2022-08-08 21:13:33 +010034 const category = interaction.guild.channels.cache.get(config.tickets.category) as Discord.CategoryChannel;
pineafan813bdf42022-07-24 10:39:10 +010035 let count = 0;
Skyler Grey75ea9172022-08-06 10:22:23 +010036 category.children.forEach((element) => {
pineafane23c4ec2022-07-27 21:56:27 +010037 if (!(element.type === "GUILD_TEXT")) return;
Skyler Grey11236ba2022-08-08 21:13:33 +010038 if ((element as Discord.TextChannel).topic.includes(`${interaction.member.user.id}`)) {
pineafan813bdf42022-07-24 10:39:10 +010039 if ((element as Discord.TextChannel).topic.endsWith("Active")) {
40 count++;
41 }
42 }
43 });
44 if (count >= config.tickets.maxTickets) {
Skyler Grey75ea9172022-08-06 10:22:23 +010045 return await interaction.reply({
46 embeds: [
47 new EmojiEmbed()
48 .setTitle("Create Ticket")
49 .setDescription(
50 `You have reached the maximum amount of tickets (${config.tickets.maxTickets}). Please close one of your active tickets before creating a new one.`
51 )
52 .setStatus("Danger")
53 .setEmoji("CONTROL.BLOCKCROSS")
54 ],
55 ephemeral: true
56 });
pineafan813bdf42022-07-24 10:39:10 +010057 }
58 let ticketTypes;
pineafan63fc5e22022-08-04 22:04:10 +010059 let custom = false;
Skyler Grey75ea9172022-08-06 10:22:23 +010060 if (config.tickets.customTypes && config.tickets.useCustom) {
61 ticketTypes = config.tickets.customTypes;
62 custom = true;
Skyler Grey11236ba2022-08-08 21:13:33 +010063 } else if (config.tickets.types) ticketTypes = toHexArray(config.tickets.types, tickets);
pineafan813bdf42022-07-24 10:39:10 +010064 else ticketTypes = [];
65 let chosenType;
66 let splitFormattedTicketTypes = [];
67 if (ticketTypes.length > 0) {
68 let formattedTicketTypes = [];
Skyler Grey75ea9172022-08-06 10:22:23 +010069 formattedTicketTypes = ticketTypes.map((type) => {
pineafan813bdf42022-07-24 10:39:10 +010070 if (custom) {
TheCodedProf21c08592022-09-13 14:14:43 -040071 return new ButtonBuilder().setLabel(type).setStyle(ButtonStyle.Primary).setCustomId(type);
pineafan813bdf42022-07-24 10:39:10 +010072 } else {
TheCodedProf21c08592022-09-13 14:14:43 -040073 return new ButtonBuilder()
pineafan813bdf42022-07-24 10:39:10 +010074 .setLabel(capitalize(type))
TheCodedProf21c08592022-09-13 14:14:43 -040075 .setStyle(ButtonStyle.Primary)
pineafan813bdf42022-07-24 10:39:10 +010076 .setCustomId(type)
Skyler Grey11236ba2022-08-08 21:13:33 +010077 .setEmoji(getEmojiByName("TICKETS." + type.toString().toUpperCase(), "id"));
pineafan813bdf42022-07-24 10:39:10 +010078 }
79 });
80 for (let i = 0; i < formattedTicketTypes.length; i += 5) {
TheCodedProf21c08592022-09-13 14:14:43 -040081 splitFormattedTicketTypes.push(new ActionRowBuilder().addComponents(formattedTicketTypes.slice(i, i + 5)));
pineafan813bdf42022-07-24 10:39:10 +010082 }
Skyler Grey75ea9172022-08-06 10:22:23 +010083 const m = await interaction.reply({
84 embeds: [
85 new EmojiEmbed()
86 .setTitle("Create Ticket")
87 .setDescription("Select a ticket type")
88 .setStatus("Success")
89 .setEmoji("GUILD.TICKET.OPEN")
90 ],
91 ephemeral: true,
92 fetchReply: true,
93 components: splitFormattedTicketTypes
94 });
pineafan813bdf42022-07-24 10:39:10 +010095 let component;
96 try {
Skyler Grey75ea9172022-08-06 10:22:23 +010097 component = await m.awaitMessageComponent({ time: 300000 });
pineafan813bdf42022-07-24 10:39:10 +010098 } catch (e) {
99 return;
100 }
101 chosenType = component.customId;
102 splitFormattedTicketTypes = [];
103 formattedTicketTypes = [];
Skyler Grey75ea9172022-08-06 10:22:23 +0100104 formattedTicketTypes = ticketTypes.map((type) => {
pineafan813bdf42022-07-24 10:39:10 +0100105 if (custom) {
TheCodedProf21c08592022-09-13 14:14:43 -0400106 return new ButtonBuilder()
pineafan813bdf42022-07-24 10:39:10 +0100107 .setLabel(type)
TheCodedProf21c08592022-09-13 14:14:43 -0400108 .setStyle(chosenType === type ? ButtonStyle.Success : ButtonStyle.Secondary)
pineafan813bdf42022-07-24 10:39:10 +0100109 .setCustomId(type)
pineafan63fc5e22022-08-04 22:04:10 +0100110 .setDisabled(true);
111 } else {
TheCodedProf21c08592022-09-13 14:14:43 -0400112 return new ButtonBuilder()
pineafan813bdf42022-07-24 10:39:10 +0100113 .setLabel(capitalize(type))
TheCodedProf21c08592022-09-13 14:14:43 -0400114 .setStyle(chosenType === type ? ButtonStyle.Success : ButtonStyle.Secondary)
pineafan813bdf42022-07-24 10:39:10 +0100115 .setCustomId(type)
Skyler Grey11236ba2022-08-08 21:13:33 +0100116 .setEmoji(getEmojiByName("TICKETS." + type.toString().toUpperCase(), "id"))
pineafan63fc5e22022-08-04 22:04:10 +0100117 .setDisabled(true);
pineafan813bdf42022-07-24 10:39:10 +0100118 }
119 });
120 for (let i = 0; i < formattedTicketTypes.length; i += 5) {
TheCodedProf21c08592022-09-13 14:14:43 -0400121 splitFormattedTicketTypes.push(new ActionRowBuilder().addComponents(formattedTicketTypes.slice(i, i + 5)));
pineafan813bdf42022-07-24 10:39:10 +0100122 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100123 component.update({
124 embeds: [
125 new EmojiEmbed()
126 .setTitle("Create Ticket")
127 .setDescription("Select a ticket type")
128 .setStatus("Success")
129 .setEmoji("GUILD.TICKET.OPEN")
130 ],
131 components: splitFormattedTicketTypes
132 });
pineafan813bdf42022-07-24 10:39:10 +0100133 } else {
pineafan63fc5e22022-08-04 22:04:10 +0100134 chosenType = null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100135 await interaction.reply({
Skyler Grey11236ba2022-08-08 21:13:33 +0100136 embeds: [new EmojiEmbed().setTitle("Create Ticket").setEmoji("GUILD.TICKET.OPEN")],
Skyler Grey75ea9172022-08-06 10:22:23 +0100137 ephemeral: true,
138 components: splitFormattedTicketTypes
139 });
pineafan813bdf42022-07-24 10:39:10 +0100140 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100141 const overwrites = [
142 {
143 id: interaction.member,
Skyler Grey11236ba2022-08-08 21:13:33 +0100144 allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
Skyler Grey75ea9172022-08-06 10:22:23 +0100145 type: "member"
146 }
147 ] as Discord.OverwriteResolvable[];
pineafan813bdf42022-07-24 10:39:10 +0100148 overwrites.push({
149 id: interaction.guild.roles.everyone,
150 deny: ["VIEW_CHANNEL"],
151 type: "role"
pineafan63fc5e22022-08-04 22:04:10 +0100152 });
pineafane23c4ec2022-07-27 21:56:27 +0100153 if (config.tickets.supportRole !== null) {
pineafan813bdf42022-07-24 10:39:10 +0100154 overwrites.push({
155 id: interaction.guild.roles.cache.get(config.tickets.supportRole),
Skyler Grey11236ba2022-08-08 21:13:33 +0100156 allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
pineafan813bdf42022-07-24 10:39:10 +0100157 type: "role"
pineafan63fc5e22022-08-04 22:04:10 +0100158 });
pineafan813bdf42022-07-24 10:39:10 +0100159 }
160
161 let c;
162 try {
Skyler Grey11236ba2022-08-08 21:13:33 +0100163 c = await interaction.guild.channels.create(interaction.member.user.username, {
164 type: "GUILD_TEXT",
165 topic: `${interaction.member.user.id} Active`,
166 parent: config.tickets.category,
167 nsfw: false,
168 permissionOverwrites: overwrites as Discord.OverwriteResolvable[],
169 reason: "Creating ticket"
170 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100171 } catch (e) {
172 return await interaction.editReply({
173 embeds: [
174 new EmojiEmbed()
175 .setTitle("Create Ticket")
176 .setDescription("Failed to create ticket")
177 .setStatus("Danger")
178 .setEmoji("CONTROL.BLOCKCROSS")
179 ]
180 });
181 }
182 try {
183 await c.send({
184 content:
185 `<@${interaction.member.user.id}>` +
Skyler Grey11236ba2022-08-08 21:13:33 +0100186 (config.tickets.supportRole !== null ? ` • <@&${config.tickets.supportRole}>` : ""),
Skyler Grey75ea9172022-08-06 10:22:23 +0100187 allowedMentions: {
188 users: [(interaction.member as Discord.GuildMember).id],
Skyler Grey11236ba2022-08-08 21:13:33 +0100189 roles: config.tickets.supportRole !== null ? [config.tickets.supportRole] : []
Skyler Grey75ea9172022-08-06 10:22:23 +0100190 }
191 });
Skyler Grey11236ba2022-08-08 21:13:33 +0100192 let content = interaction.options ? interaction.options.getString("message") || "" : "";
pineafan813bdf42022-07-24 10:39:10 +0100193 if (content) content = `**Message:**\n> ${content}\n`;
Skyler Grey11236ba2022-08-08 21:13:33 +0100194 const emoji = custom ? "" : getEmojiByName("TICKETS." + chosenType.toUpperCase());
Skyler Grey75ea9172022-08-06 10:22:23 +0100195 await c.send({
196 embeds: [
197 new EmojiEmbed()
198 .setTitle("New Ticket")
199 .setDescription(
200 `Ticket created by <@${interaction.member.user.id}>\n` +
201 `**Support type:** ${
Skyler Grey11236ba2022-08-08 21:13:33 +0100202 chosenType !== null ? emoji + " " + capitalize(chosenType) : "General"
Skyler Grey75ea9172022-08-06 10:22:23 +0100203 }\n` +
204 `**Ticket ID:** \`${c.id}\`\n${content}\n` +
205 "Type `/ticket close` to close this ticket."
206 )
207 .setStatus("Success")
208 .setEmoji("GUILD.TICKET.OPEN")
209 ],
210 components: [
TheCodedProf21c08592022-09-13 14:14:43 -0400211 new ActionRowBuilder().addComponents([
212 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100213 .setLabel("Close")
TheCodedProf21c08592022-09-13 14:14:43 -0400214 .setStyle(ButtonStyle.Danger)
Skyler Grey75ea9172022-08-06 10:22:23 +0100215 .setCustomId("closeticket")
216 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
217 ])
218 ]
219 });
pineafan63fc5e22022-08-04 22:04:10 +0100220 const data = {
Skyler Grey75ea9172022-08-06 10:22:23 +0100221 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100222 type: "ticketCreate",
223 displayName: "Ticket Created",
pineafan813bdf42022-07-24 10:39:10 +0100224 calculateType: "ticketUpdate",
225 color: NucleusColors.green,
pineafan63fc5e22022-08-04 22:04:10 +0100226 emoji: "GUILD.TICKET.OPEN",
pineafan813bdf42022-07-24 10:39:10 +0100227 timestamp: new Date().getTime()
228 },
229 list: {
Skyler Grey11236ba2022-08-08 21:13:33 +0100230 ticketFor: entry(interaction.member.user.id, renderUser(interaction.member.user)),
231 created: entry(new Date().getTime(), renderDelta(new Date().getTime())),
pineafan63fc5e22022-08-04 22:04:10 +0100232 ticketChannel: entry(c.id, renderChannel(c))
pineafan813bdf42022-07-24 10:39:10 +0100233 },
234 hidden: {
235 guild: interaction.guild.id
236 }
pineafan63fc5e22022-08-04 22:04:10 +0100237 };
pineafan813bdf42022-07-24 10:39:10 +0100238 log(data);
Skyler Grey75ea9172022-08-06 10:22:23 +0100239 } catch (e) {
240 console.log(e);
241 }
242 await interaction.editReply({
243 embeds: [
244 new EmojiEmbed()
245 .setTitle("Create Ticket")
Skyler Grey11236ba2022-08-08 21:13:33 +0100246 .setDescription(`Ticket created. You can view it here: <#${c.id}>`)
Skyler Grey75ea9172022-08-06 10:22:23 +0100247 .setStatus("Success")
248 .setEmoji("GUILD.TICKET.OPEN")
249 ],
250 components: splitFormattedTicketTypes
251 });
252}