Files
SupportBot/Commands/ticket.js
T
2024-06-12 12:54:31 +01:00

309 lines
10 KiB
JavaScript

const fs = require("fs");
const {
EmbedBuilder,
ApplicationCommandOptionType,
ApplicationCommandType,
ChannelType,
ActionRowBuilder,
ButtonBuilder,
StringSelectMenuBuilder,
StringSelectMenuOptionBuilder,
GuildMemberRoleManager,
} = require("discord.js");
const yaml = require("js-yaml");
const panelconfig = yaml.load(fs.readFileSync("./Configs/ticket-panel.yml", "utf8"));
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 department = interaction.customId?.split("-")[1] || null;
let TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
const { getRole, getChannel } = 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,
});
}
let ticketNumberID = await TicketNumberID.pad();
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,
});
const TicketCategory = interaction.guild.channels.cache.find(
(c) => c.name === supportbot.Ticket.TicketCategory || c.id === supportbot.Ticket.TicketCategory
);
const channel = await getChannel(panelconfig.Channel, interaction.guild);
const ticketChannel = await channel.threads.create({
name: `${supportbot.Ticket.Channel}${ticketNumberID}`,
type: ChannelType.PrivateThread,
parent: TicketCategory,
autoArchiveDuration: 60,
reason: 'support ticket',
});
if (supportbot.Ticket.ClaimTickets.Enabled === false) {
const InvStaff = await ticketChannel.send(`<@&${Staff.id}> <@&${Admin.id}>`)
setTimeout(() => {
InvStaff.delete();
}, 2000)
}
// TICKET CLAIMING SYSTEM [START]
if (supportbot.Ticket.ClaimTickets.Enabled) {
const InvStaff1 = await ticketChannel.send(`<@&${Admin.id}>`)
setTimeout(() => {
InvStaff1.delete();
}, 2000)
const claimChannel = await getChannel(
supportbot.Ticket.ClaimTickets.Channel,
interaction.guild
);
const claimEmbed = new EmbedBuilder()
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimTitle)
.setDescription(msgconfig.Ticket.ClaimTickets.ClaimMessage
.replace('%user%', interaction.user.id)
)
.setColor(supportbot.Embed.Colours.General);
const claimButton = new ButtonBuilder()
.setCustomId(`claimticket-${ticketChannel.id}`)
.setLabel(supportbot.Ticket.ClaimTickets.ButtonTitle)
.setStyle(supportbot.Ticket.ClaimTickets.Button);
const row = new ActionRowBuilder().addComponents(claimButton);
await claimChannel.send({
content: `<@&${Staff.id}>`,
embeds: [claimEmbed],
components: [row]
});
}
// TICKET CLAIMING SYSTEM [END]
if (!department) {
await ticketChannel.members.add(interaction.user.id);
}
TicketData.tickets.push({
id: ticketChannel.id,
name: ticketChannel.name,
user: interaction.user.id,
number: ticketNumberID,
reason: TicketSubject,
open: true,
subUsers: [],
createdAt: new Date().toISOString(),
claimedAt: null, // Will be updated when claimed
});
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()
.setAuthor({
name: msgconfig.Ticket.TicketAuthorTitle.replace(/%ticketauthor%/g, interaction.user.id)
.replace(/%ticketid%/g, ticketChannel.id)
.replace(/%ticketusername%/g, interaction.user.username),
iconURL: interaction.user.displayAvatarURL(),
})
.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);
const SelectMenus = new StringSelectMenuBuilder()
.setCustomId("ticketcontrolpanel")
.setPlaceholder("Ticket Control Panel")
.addOptions(
new StringSelectMenuOptionBuilder()
.setLabel("Add User")
.setDescription("Add a user to the ticket.")
.setEmoji(supportbot.SelectMenus.Tickets.AddUserEmoji)
.setValue("ticketadduser"),
new StringSelectMenuOptionBuilder()
.setLabel("Remove User")
.setDescription("Remove a user from the ticket.")
.setEmoji(supportbot.SelectMenus.Tickets.RemoveUserEmoji)
.setValue("ticketremoveuser"),
new StringSelectMenuOptionBuilder()
.setLabel("Close")
.setDescription("Close the ticket.")
.setEmoji(supportbot.SelectMenus.Tickets.CloseEmoji)
.setValue("ticketclose"),
new StringSelectMenuOptionBuilder()
.setLabel("Enable Invites")
.setDescription("Enable invites.")
.setEmoji(supportbot.SelectMenus.Tickets.EnableInvitesEmoji)
.setValue("enableinvites"),
new StringSelectMenuOptionBuilder()
.setLabel("Disable Invites")
.setDescription("Disable invites.")
.setEmoji(supportbot.SelectMenus.Tickets.DisableInvitesEmoji)
.setValue("disableinvites"),
);
const row2 = new ActionRowBuilder().addComponents(SelectMenus);
if (!department) {
try {
let buttons = supportbot.Departments.map((x) =>
new ButtonBuilder()
.setCustomId("Department" + supportbot.Departments.indexOf(x))
.setLabel(x.title)
.setStyle(x.color)
.setEmoji(x.emoji)
);
if (supportbot.Ticket.AllowMentions) {
await ticketChannel.send("<@&" + supportbot.Ticket.RoleMention + ">");
}
const row = new ActionRowBuilder().addComponents(buttons);
const m = await ticketChannel.send({
embeds: [TicketMessage],
components: [row2],
});
try {
const filter = (i) => i.user.id === interaction.user.id;
await m.awaitMessageComponent({
filter,
max: 1,
componentType: "BUTTON",
time: supportbot.Ticket.Timeout * 60000,
});
} catch (e) {
if (e.code === "COLLECTOR_ERROR") {
try {
let ticket = 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 (error) {
console.error("An error occurred while handling collector:", error);
}
return await ticketChannel.delete();
}
}
} catch (error) {
console.error("Error sending message:", error);
}
} else {
await ticketChannel.send({
embeds: [TicketMessage],
components: [row2],
});
}
},
});