// SupportBot | Emerald Services // Ticket Command const fs = require("fs"); const { EmbedBuilder, Permissions, MessageButton, MessageActionRow, ApplicationCommandOptionType, ApplicationCommandType, ButtonStyle, InteractionType, DiscordAPIError, ChannelType, InteractionCollector } = require("discord.js"); const yaml = require("js-yaml"); const supportbot = yaml.load( fs.readFileSync("./Configs/supportbot.yml", "utf8") ); const cmdconfig = yaml.load( fs.readFileSync("./Configs/commands.yml", "utf8") ); const msgconfig = yaml.load( fs.readFileSync("./Configs/messages.yml", "utf8") ) const Command = require("../Structures/Command.js"); const TicketNumberID = require("../Structures/TicketID.js"); module.exports = new Command({ name: cmdconfig.OpenTicket.Command, description: cmdconfig.OpenTicket.Description, type: ApplicationCommandType.ChatInput, options: [ { name: "reason", description: "Ticket Reason", type: ApplicationCommandOptionType.String, }, ], permissions: cmdconfig.OpenTicket.Permission, async run(interaction) { let disableCommand = true; let department = interaction.customId?.split("-")[1] || null; let TicketData = await JSON.parse( fs.readFileSync("./Data/TicketData.json", "utf8") ); const { getRole, getCategory } = interaction.client; let User = interaction.guild.members.cache.get(interaction.user.id); if ( supportbot.Ticket.TicketsPerUser && TicketData.tickets.filter((t) => t.user === interaction.user.id && t.open) .length >= supportbot.Ticket.TicketsPerUser ) { return interaction.reply({ embeds: [ { title: "Too Many Tickets!", description: `You can't have more than ${supportbot.Ticket.TicketsPerUser} open tickets!`, color: supportbot.Embed.Colours.Warn, }, ], ephemeral: true, }); } if (User.roles.cache.has(supportbot.Roles.ModRoles.Blacklisted)) { return interaction.reply({ content: msgconfig.Ticket.Blacklisted, ephemeral: true, }) }; if (User.roles.cache.has(supportbot.Roles.ModRoles.Muted)) { return interaction.reply({ content: msgconfig.Ticket.Muted, ephemeral: true, }) }; // Ticket ID let ticketNumberID = await TicketNumberID.pad(); // Ticket Subject const TicketSubject = interaction.options?.getString("reason") || msgconfig.Ticket.InvalidSubject; const TicketExists = new EmbedBuilder() .setTitle("Ticket Exists!") .setDescription(msgconfig.Ticket.TicketExists); if ( await interaction.guild.channels.cache.find( (ticketChannel) => ticketChannel.name === `${supportbot.Ticket.Channel}${ticketNumberID}` ) ) { return await interaction.reply({ embeds: [TicketExists], ephemeral: true, }); } const Staff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild); const Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild); if (!Staff || !Admin) return interaction.reply({ content: "Some roles seem to be missing!\nPlease check for errors when starting the bot.", ephemeral: true, }); let TicketCategory = await getCategory( supportbot.Departments[department].category, interaction.guild ); const ticketChannel = await interaction.guild.channels.create( `${supportbot.TicketPrefix}${ticketNumberID}`, { type: ChannelType.GuildText, parent: TicketCategory.id, permissionOverwrites: [ { id: Admin.id, allow: [PermissionsBitField.Flags.ViewChannel], }, { id: interaction.user.id, allow: [PermissionsBitField.Flags.ViewChannel], }, { id: interaction.guild.id, deny: [PermissionsBitField.Flags.ViewChannel], }, ], } ); if (supportbot.Ticket.AllowAllStaff) { await ticketChannel.permissionOverwrites.edit(Staff.id, { ViewChannel: true, }); } if (!department) { await ticketChannel.permissionOverwrites.edit(interaction.user.id, { SendMessages: false, }); } await TicketData.tickets.push({ id: ticketChannel.id, name: ticketChannel.name, user: interaction.user.id, number: ticketNumberID, reason: TicketSubject, open: true, subUsers: [], }); fs.writeFileSync( "./Data/TicketData.json", JSON.stringify(TicketData, null, 4), (err) => { if (err) console.error(err); } ); const CreatedTicket = new EmbedBuilder() .setDescription( msgconfig.Ticket.TicketCreatedAlert.replace( /%ticketauthor%/g, interaction.user.id ) .replace(/%ticketid%/g, ticketChannel.id) .replace(/%ticketusername%/g, interaction.user.username) ) .setColor(supportbot.Embed.Colours.General); await interaction.reply({ embeds: [CreatedTicket], ephemeral: true }); if (supportbot.Ticket.AllowMentions) { await ticketChannel.send(`${interaction.user}`); } const TicketMessage = new EmbedBuilder() .setTitle( msgconfig.Ticket.TicketTitle.replace(/%ticketauthor%/g, interaction.user.id) .replace(/%ticketid%/g, ticketChannel.id) .replace(/%ticketusername%/g, interaction.user.username) ) .setDescription( msgconfig.Ticket.TicketMessage.replace(/%ticketauthor%/g, interaction.user.id) .replace(/%ticketid%/g, ticketChannel.id) .replace(/%ticketusername%/g, interaction.user.username) ) .setColor(supportbot.Embed.Colours.General); if (supportbot.Ticket.TicketSubject === "embed") { if (TicketSubject !== "No Reason Provided.") { TicketMessage.addFields({ name: "Reason", value: TicketSubject }); } } if (supportbot.Ticket.TicketSubject === "description") { if (TicketSubject !== "No Reason Provided.") { await ticketChannel.setTopic( `Reason: ${TicketSubject} - User ID: ${interaction.user.id} - Ticket: ${ticketChannel.name}` ); } } if (!department) { TicketMessage.addFields({ name: "Departments", value: ` **${supportbot.Departments.map((X) => X.title).join("\n")}**`, }); } const CloseButton = new MessageButton() .setCustomId("ticketclose") .setLabel("Close") .setStyle(supportbot.Buttons.Tickets.CloseStyle) .setEmoji(supportbot.Buttons.Tickets.CloseEmoji); const LockButton = new MessageButton() .setCustomId("ticketlock") .setLabel("Lock") .setStyle(supportbot.Buttons.Tickets.LockStyle) .setEmoji(supportbot.Buttons.Tickets.LockEmoji); const row2 = new MessageActionRow().addComponents(CloseButton, LockButton); if (!department) { try { let buttons = await supportbot.Departments.map((x) => new MessageButton() .setCustomId("Department" + supportbot.Departments.indexOf(x)) .setLabel(x.title) .setStyle(x.color) .setEmoji(x.emoji) ); const row = new MessageActionRow().addComponents(buttons); const m = await ticketChannel.send({ embeds: [TicketMessage], components: [row], }); let collector; try { const filter = (i) => i.user.id === interaction.user.id; collector = await m.awaitMessageComponent({ filter, max: 1, componentType: "BUTTON", time: supportbot.Ticket.Timeout * 60000, }); } catch (e) { if (e.code === "INTERACTION_COLLECTOR_ERROR") { try { TicketData = await JSON.parse( fs.readFileSync("./Data/TicketData.json", "utf8") ); let ticket = await TicketData.tickets.findIndex( (t) => t.id === ticketChannel.id ); TicketData.tickets[ticket].open = false; fs.writeFileSync( "./Data/TicketData.json", JSON.stringify(TicketData, null, 4), (err) => { if (err) console.error(err); } ); interaction.user.send( "Your ticket has timed out. Please open a new one, and select a department." ); } catch (e) {} return await ticketChannel.delete(); } } let num = collector.customId.split("Department")[1]; let role = getRole(supportbot.Departments[num].role, interaction.guild); let title = supportbot.Departments[num].title; await ticketChannel.permissionOverwrites.edit(role.id, { ViewChannel: true, }); await ticketChannel.permissionOverwrites.edit(interaction.user.id, { SendMessages: true, }); await collector.reply({ embeds: [ { description: `> Thank for reaching out to the **${title} Department**. Please provide us information regarding your query.`, color: supportbot.Embed.Colours.General, }, ], }); if (supportbot.Ticket.AllowMentions) { await ticketChannel.send("@here"); } await collector.message.edit({ embeds: [TicketMessage], components: [row2], }); } catch (error) {} } else { await ticketChannel.send({ embeds: [TicketMessage], components: [row2], }); if (department) { let role = await getRole( supportbot.Departments[department].role, interaction.guild ); let title = supportbot.Departments[department].title; await ticketChannel.permissionOverwrites.edit(role.id, { ViewChannel: true, }); let TicketCat = await getCategory( supportbot.Departments[department].category, interaction.guild ); await ticketChannel.setParent(TicketCat.id, { lockPermissions: false }); if (supportbot.TicketAllowThanksForReachingOutMessage) { await ticketChannel.send({ embeds: [ { description: `> Thank for reaching out to the **${title} Department**. Please provide us information regarding your query.`, color: supportbot.Embed.Colours.General, }, ], }); } } if (supportbot.Ticket.AllowMentions) { await ticketChannel.send(supportbot.Ticket.RoleMention); } } }, });