Files
SupportBot/Events/interactionCreate.js
T

1035 lines
35 KiB
JavaScript
Raw Permalink Normal View History

2021-10-24 22:48:25 +01:00
const Discord = require("discord.js");
2022-08-12 01:35:36 +01:00
2026-05-16 15:10:27 +01:00
const supportbot = require("../Structures/ConfigStore").supportbot;
const cmdconfig = require("../Structures/ConfigStore").commands;
const msgconfig = require("../Structures/ConfigStore").messages;
2021-10-24 22:48:25 +01:00
const Event = require("../Structures/Event.js");
2025-09-20 23:09:22 +01:00
const db = require("../Structures/Database.js");
2024-06-13 17:36:44 +01:00
2021-11-10 21:41:12 -06:00
module.exports = new Event("interactionCreate", async (client, interaction) => {
2024-07-09 22:49:49 +01:00
if (interaction.type === Discord.InteractionType.ApplicationCommand) {
2021-10-24 22:48:25 +01:00
const command = client.commands.find(
2026-03-10 20:02:43 +00:00
(cmd) => cmd.name.toLowerCase() === interaction.commandName,
2021-10-24 22:48:25 +01:00
);
2021-11-23 18:08:45 -06:00
if (interaction.user.bot || !interaction.guild) return;
2021-10-24 22:48:25 +01:00
2022-07-22 13:19:05 +01:00
const NotValid = new Discord.EmbedBuilder()
2024-07-09 22:49:49 +01:00
.setDescription(`:x: \`Invalid Command\``)
2022-08-12 01:35:36 +01:00
.setColor(supportbot.Embed.Colours.Error);
2021-10-24 22:48:25 +01:00
if (!command)
return interaction.reply({
embeds: [NotValid],
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2021-10-24 22:48:25 +01:00
});
2022-02-04 17:49:02 -06:00
const permission = interaction.member.permissions.has(command.permissions);
2021-10-24 22:48:25 +01:00
2022-07-22 13:19:05 +01:00
const ValidPerms = new Discord.EmbedBuilder()
2021-10-24 22:48:25 +01:00
.setDescription(
2026-03-10 20:02:43 +00:00
"> :x: `Invalid Permissions` Do you have the correct permissions to execute this command?",
2021-10-24 22:48:25 +01:00
)
2022-08-12 01:35:36 +01:00
.setColor(supportbot.Embed.Colours.Error);
2021-10-24 22:48:25 +01:00
if (!permission)
return interaction.reply({
embeds: [ValidPerms],
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2024-07-09 22:49:49 +01:00
});
try {
2026-03-10 20:02:43 +00:00
if (
command.name === cmdconfig.OpenTicket.Command &&
supportbot.Ticket.TicketReason
) {
2024-07-09 22:49:49 +01:00
const modal = new Discord.ModalBuilder()
.setCustomId("ticketReasonModal")
.setTitle("Ticket Reason")
.addComponents(
new Discord.ActionRowBuilder().addComponents(
new Discord.TextInputBuilder()
.setCustomId("reasonInput")
.setLabel("Reason")
.setStyle(Discord.TextInputStyle.Paragraph)
2026-03-10 20:02:43 +00:00
.setRequired(true),
),
2024-07-09 22:49:49 +01:00
);
await interaction.showModal(modal);
} else {
2026-03-10 20:02:43 +00:00
console.log(
"\u001b[32m",
"[Executed]",
"\u001b[37;1m",
`${interaction.user.username} has executed ${command.name}`,
);
2026-05-26 20:11:22 +01:00
2024-07-09 22:49:49 +01:00
await command.run(interaction);
}
} catch (error) {
console.error("Error executing command:", error);
await interaction.reply({
content: "An error occurred while executing the command.",
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2021-10-24 22:48:25 +01:00
});
2024-07-09 22:49:49 +01:00
}
}
if (interaction.isModalSubmit()) {
2026-03-10 20:02:43 +00:00
if (interaction.customId.startsWith("ticketReasonModal")) {
2024-07-09 22:49:49 +01:00
const reason = interaction.fields.getTextInputValue("reasonInput");
2026-03-10 20:02:43 +00:00
const department = interaction.customId.includes(":")
? interaction.customId.split(":")[1]
: supportbot.Ticket.DepartmentSystem?.DefaultDepartment || "general";
2024-07-09 22:49:49 +01:00
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
2026-03-10 20:02:43 +00:00
if (!cmd) {
return interaction.reply({
content: "Open ticket command not found.",
flags: Discord.MessageFlags.Ephemeral,
});
2024-07-09 22:49:49 +01:00
}
2026-03-10 20:02:43 +00:00
interaction.reason = reason;
interaction.department = department;
interaction.priority =
supportbot.Ticket.DepartmentSystem?.Departments?.[department]
?.DefaultPriority ||
supportbot.Ticket.PrioritySystem?.DefaultPriority ||
"medium";
return await cmd.run(interaction);
2024-07-09 22:49:49 +01:00
}
2021-10-24 22:48:25 +01:00
}
2024-06-12 12:54:31 +01:00
2024-10-10 19:14:45 +01:00
if (interaction.customId === "renameTicketModal") {
const newTicketName = interaction.fields.getTextInputValue("renameTicket");
const ticketChannelId = interaction.channel.id;
let ticketChannel;
if (supportbot.Ticket.TicketType === "threads") {
2026-03-10 20:02:43 +00:00
ticketChannel = interaction.guild.channels.cache.get(ticketChannelId);
2024-10-10 19:14:45 +01:00
} else if (supportbot.Ticket.TicketType === "channels") {
2026-03-10 20:02:43 +00:00
ticketChannel = interaction.guild.channels.cache.get(ticketChannelId);
2024-10-10 19:14:45 +01:00
}
if (!ticketChannel) {
2026-03-10 20:02:43 +00:00
return interaction.reply({
content: "Ticket channel not found.",
flags: Discord.MessageFlags.Ephemeral,
});
2024-10-10 19:14:45 +01:00
}
try {
2026-03-10 20:02:43 +00:00
await ticketChannel.setName(newTicketName);
const renamedsuccess = new Discord.EmbedBuilder()
.setDescription(msgconfig.Ticket.RenamedSuccess)
.setColor(supportbot.Embed.Colours.Success);
return interaction.reply({
embeds: [renamedsuccess],
flags: Discord.MessageFlags.Ephemeral,
});
2024-10-10 19:14:45 +01:00
} catch (error) {
2026-03-10 20:02:43 +00:00
console.error("Error renaming the ticket:", error);
return interaction.reply({
content: "There was an error renaming the ticket.",
flags: Discord.MessageFlags.Ephemeral,
});
}
}
if (interaction.isStringSelectMenu()) {
if (interaction.customId === "ticketdepartmentselect") {
const selectedDepartment = interaction.values[0];
if (supportbot.Ticket.TicketReason) {
const modal = new Discord.ModalBuilder()
.setCustomId(`ticketReasonModal:${selectedDepartment}`)
.setTitle("Ticket Reason")
.addComponents(
new Discord.ActionRowBuilder().addComponents(
new Discord.TextInputBuilder()
.setCustomId("reasonInput")
.setLabel("Reason")
.setStyle(Discord.TextInputStyle.Paragraph)
.setRequired(true),
),
);
return await interaction.showModal(modal);
}
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
if (!cmd) {
2024-10-10 19:14:45 +01:00
return interaction.reply({
2026-03-10 20:02:43 +00:00
content: "Open ticket command not found.",
flags: Discord.MessageFlags.Ephemeral,
2024-10-10 19:14:45 +01:00
});
2026-03-10 20:02:43 +00:00
}
interaction.department = selectedDepartment;
interaction.priority =
supportbot.Ticket.DepartmentSystem?.Departments?.[selectedDepartment]
?.DefaultPriority ||
supportbot.Ticket.PrioritySystem?.DefaultPriority ||
"medium";
return await cmd.run(interaction);
2024-10-10 19:14:45 +01:00
}
2025-09-22 18:36:04 +01:00
2024-06-12 12:54:31 +01:00
if (interaction.customId === "ticketcontrolpanel") {
const selectedOption = interaction.values[0];
const { getRole, getChannel } = interaction.client;
switch (selectedOption) {
case "ticketclose":
2026-03-10 20:02:43 +00:00
const closeCommand = client.commands.get(
cmdconfig.CloseTicket.Command,
);
2024-06-12 12:54:31 +01:00
if (closeCommand) {
2024-07-09 22:49:49 +01:00
await closeCommand.run(interaction);
2024-06-12 12:54:31 +01:00
} else {
console.error("[X] Close Command Not Found");
}
break;
2026-03-10 20:02:43 +00:00
case "supportvc":
const ticketInfo = db.getTicket(interaction.channel.id);
if (!ticketInfo) {
return interaction.reply({
content: "⚠️ This channel isn’t a valid ticket.",
flags: Discord.MessageFlags.Ephemeral,
});
}
2024-11-09 00:37:51 +00:00
2026-03-10 20:02:43 +00:00
const user =
interaction.guild.members.cache.get(ticketInfo.user_id) ||
ticketInfo.user_id;
const username = user?.user?.username || "Unknown User";
2025-09-20 23:09:22 +01:00
2026-03-10 20:02:43 +00:00
const VCcategory = interaction.guild.channels.cache.find(
(c) =>
c.name === supportbot.VoiceTickets.Category ||
c.id === supportbot.VoiceTickets.Category,
);
2025-09-20 23:09:22 +01:00
2026-03-10 20:02:43 +00:00
if (!VCcategory) {
return interaction.reply({
content: "⚠️ The Support VC category does not exist!",
flags: Discord.MessageFlags.Ephemeral,
2025-09-20 23:09:22 +01:00
});
2026-03-10 20:02:43 +00:00
}
2025-09-20 23:09:22 +01:00
2026-03-10 20:02:43 +00:00
const SupportVoice = await interaction.guild.channels.create({
name: supportbot.VoiceTickets.Name.replace(/%username%/g, username),
type: Discord.ChannelType.GuildVoice,
parent: VCcategory,
permissionOverwrites: [
{
id: interaction.guild.id,
deny: [Discord.PermissionsBitField.Flags.Connect],
},
{
id: user.id || user, // works if user is a Member or just ID
allow: [
Discord.PermissionsBitField.Flags.Connect,
Discord.PermissionsBitField.Flags.Speak,
Discord.PermissionsBitField.Flags.ViewChannel,
],
},
],
});
2025-09-20 23:09:22 +01:00
2026-03-10 20:02:43 +00:00
db.updateTicketVoice(ticketInfo.ticket_id, SupportVoice.id);
2025-09-20 23:09:22 +01:00
2026-03-10 20:02:43 +00:00
const vcmadeembed = new Discord.EmbedBuilder()
.setDescription(`> **Support VC Created:** <#${SupportVoice.id}>`)
.setColor(supportbot.Embed.Colours.Success);
2025-09-20 23:09:22 +01:00
2026-03-10 20:02:43 +00:00
const VCDeleteButton = new Discord.ButtonBuilder()
.setCustomId("deleteSupportVC")
.setLabel(supportbot.Buttons.Voice.TicketDeleteText)
.setEmoji(supportbot.Buttons.General.Delete)
.setStyle(supportbot.Buttons.General.DeleteStyle);
2025-09-20 23:09:22 +01:00
2026-03-10 20:02:43 +00:00
const VCDeleteRow = new Discord.ActionRowBuilder().addComponents(
VCDeleteButton,
);
await interaction.reply({
embeds: [vcmadeembed],
components: [VCDeleteRow],
});
break;
case "archiveticket":
const arcembed = new Discord.EmbedBuilder()
.setDescription(msgconfig.Ticket.TicketArchived)
.setColor(supportbot.Embed.Colours.Success);
const CloseButton = new Discord.ButtonBuilder()
.setCustomId("confirmCloseTicket")
.setLabel(supportbot.Ticket.Close.Confirmation_Button)
.setEmoji(supportbot.Ticket.Close.Confirmation_Emoji)
.setStyle(supportbot.Ticket.Close.Confirmation_Style);
const unarchiveButton = new Discord.ButtonBuilder()
.setCustomId("unarchiveTicket")
.setLabel(supportbot.Buttons.Tickets.Unarchive)
.setEmoji(supportbot.Buttons.Tickets.Unarchive_Emoji)
.setStyle(supportbot.Buttons.Tickets.Unarchive_Style);
const ArchivedOptions = new Discord.ActionRowBuilder().addComponents(
CloseButton,
unarchiveButton,
);
await interaction.channel.send({
embeds: [arcembed],
components: [ArchivedOptions],
});
if (supportbot.Ticket.TicketType === "threads") {
await interaction.channel.setArchived(true);
}
if (supportbot.Ticket.TicketType === "channels") {
const { getRole, getChannel } = interaction.client;
await interaction.channel.setParent(
supportbot.Ticket.TicketArchiveCategory,
);
const tickets = db.getAllTickets();
const ticketInfo = tickets.find(
(t) => t.ticket_id === interaction.channel.id,
);
if (ticketInfo) {
const user =
interaction.guild.members.cache.get(ticketInfo.user_id) ||
ticketInfo.user_id;
const claimedBy =
interaction.guild.members.cache.get(ticketInfo.claimed_by) ||
ticketInfo.claimed_by;
const Admin = await interaction.guild.roles.fetch(
supportbot.Roles.StaffMember.Admin,
);
const Staff = await interaction.guild.roles.fetch(
supportbot.Roles.StaffMember.Staff,
);
if (user && user.id) {
await interaction.channel.permissionOverwrites.edit(user.id, {
ViewChannel: false,
SendMessages: false,
2024-07-30 17:45:35 +01:00
});
2026-03-10 20:02:43 +00:00
}
if (supportbot.ClaimTickets === true) {
if (claimedBy && claimedBy.id) {
await interaction.channel.permissionOverwrites.edit(
claimedBy.id,
{
ViewChannel: true,
SendMessages: true,
ReadMessageHistory: true,
},
);
2024-10-10 19:14:45 +01:00
}
2026-03-10 20:02:43 +00:00
}
if (supportbot.ClaimTickets === false) {
if (Staff && Staff.id) {
await interaction.channel.permissionOverwrites.edit(
claimedBy.id,
{
ViewChannel: true,
SendMessages: true,
ReadMessageHistory: true,
},
);
2024-10-10 19:14:45 +01:00
}
2026-03-10 20:02:43 +00:00
}
if (Admin && Admin.id) {
await interaction.channel.permissionOverwrites.edit(Admin.id, {
ViewChannel: true,
SendMessages: true,
ReadMessageHistory: true,
});
}
await interaction.channel.permissionOverwrites.edit(
interaction.guild.roles.everyone.id,
{
ViewChannel: false,
SendMessages: false,
ReadMessageHistory: false,
},
);
}
}
break;
case "lockticket":
const lockembed = new Discord.EmbedBuilder()
.setDescription(msgconfig.Ticket.TicketLocked)
.setColor(supportbot.Embed.Colours.Success);
const unlockButton = new Discord.ButtonBuilder()
.setCustomId("unlockTicket")
.setLabel(supportbot.Buttons.Tickets.Unlock)
.setEmoji(supportbot.Buttons.Tickets.Unlock_Emoji)
.setStyle(supportbot.Buttons.Tickets.Unlock_Style);
const LockedOptions = new Discord.ActionRowBuilder().addComponents(
unlockButton,
);
await interaction.channel.send({
embeds: [lockembed],
components: [LockedOptions],
ephemeral: false,
});
if (supportbot.Ticket.TicketType === "threads") {
await interaction.channel.setLocked(true);
}
break;
case "unlockTicket":
const unlockEmbed = new Discord.EmbedBuilder()
.setDescription(msgconfig.Ticket.TicketUnlocked)
.setColor(supportbot.Embed.Colours.Success);
await interaction.channel.send({
embeds: [unlockEmbed],
ephemeral: false,
});
if (supportbot.Ticket.TicketType === "threads") {
await interaction.channel.setLocked(false);
}
break;
2024-06-12 12:54:31 +01:00
case "enableinvites":
await handleInvites(interaction, true);
break;
case "disableinvites":
await handleInvites(interaction, false);
break;
2024-10-10 19:14:45 +01:00
case "renameticket":
const modal = new Discord.ModalBuilder()
2026-03-10 20:02:43 +00:00
.setCustomId("renameTicketModal")
.setTitle("Rename Channel")
.addComponents(
new Discord.ActionRowBuilder().addComponents(
2024-10-10 19:14:45 +01:00
new Discord.TextInputBuilder()
.setCustomId("renameTicket")
.setLabel("New Channel Name")
.setStyle(Discord.TextInputStyle.Short)
2026-03-10 20:02:43 +00:00
.setRequired(true),
),
);
await interaction.showModal(modal);
break;
2024-06-12 12:54:31 +01:00
}
}
}
2026-03-10 20:02:43 +00:00
if (interaction.customId === "deleteSupportVC") {
2025-09-20 23:09:22 +01:00
const ticketData = db.getAllTickets();
2026-03-10 20:02:43 +00:00
const ticketInfo = ticketData.find(
(t) => t.ticket_id === interaction.channel.id,
);
2024-11-09 00:37:51 +00:00
if (ticketInfo && ticketInfo.voiceChannelId) {
try {
2026-03-10 20:02:43 +00:00
const voiceChannel = await interaction.guild.channels
.fetch(ticketInfo.voiceChannelId)
.catch(() => null);
2024-11-09 00:37:51 +00:00
if (voiceChannel) {
await voiceChannel.delete();
const successEmbed = new Discord.EmbedBuilder()
2026-03-10 20:02:43 +00:00
.setDescription(
"✅ Support voice channel has been successfully deleted!",
)
2024-11-09 00:37:51 +00:00
.setColor(supportbot.Embed.Colours.Success);
await interaction.reply({
embeds: [successEmbed],
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2024-11-09 00:37:51 +00:00
});
} else {
const errorEmbed = new Discord.EmbedBuilder()
2026-03-10 20:02:43 +00:00
.setDescription(
"❌ The associated voice channel could not be found.",
)
2024-11-09 00:37:51 +00:00
.setColor(supportbot.Embed.Colours.Error);
await interaction.reply({
embeds: [errorEmbed],
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2024-11-09 00:37:51 +00:00
});
}
} catch (error) {
2026-03-10 20:02:43 +00:00
console.error("Error deleting the Voice Channel:", error);
2024-11-09 00:37:51 +00:00
const errorEmbed = new Discord.EmbedBuilder()
2026-03-10 20:02:43 +00:00
.setDescription(
"❌ **There was an error trying to delete this voice channel. Please try again later.**",
)
2024-11-09 00:37:51 +00:00
.setColor(supportbot.Embed.Colours.Error);
await interaction.reply({
embeds: [errorEmbed],
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2024-11-09 00:37:51 +00:00
});
}
} else {
const errorEmbed = new Discord.EmbedBuilder()
2026-03-10 20:02:43 +00:00
.setDescription(
"⚠️ This button is not linked to a valid voice channel.",
)
2024-11-09 00:37:51 +00:00
.setColor(supportbot.Embed.Colours.Warn);
await interaction.reply({
embeds: [errorEmbed],
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2024-11-09 00:37:51 +00:00
});
}
}
2021-10-24 22:48:25 +01:00
if (interaction.isButton()) {
2026-03-11 18:58:15 +00:00
if (interaction.customId.startsWith("ticket_ai_enable:")) {
const ticketId = interaction.customId.split(":")[1];
const ticket = db.getTicket(ticketId);
if (!ticket) {
return interaction.reply({
content: msgconfig.Ticket.AIMode.TicketNotFound,
flags: Discord.MessageFlags.Ephemeral,
});
}
try {
const usingThreads = supportbot.Ticket.TicketType === "threads";
if (usingThreads) {
db.setTicketAIState(ticketId, {
enabled: true,
aiChannelId: interaction.channel.id,
aiType: "thread",
enabledBy: interaction.user.id,
enabledAt: new Date().toISOString(),
});
const embed = new Discord.EmbedBuilder()
.setDescription(msgconfig.Ticket.AIMode.EnabledMessage)
.setColor(supportbot.Embed.Colours.Success);
return interaction.reply({
embeds: [embed],
flags: Discord.MessageFlags.Ephemeral,
});
}
let aiChannelId = ticket.aiChannelId;
if (!aiChannelId) {
const threadName =
supportbot.Ticket.AIMode?.ThreadName || "Chat with SupportBot AI";
const aiThread = await interaction.channel.threads.create({
name: threadName,
autoArchiveDuration: 60,
reason: "ticket ai mode thread",
});
await aiThread.members.add(interaction.user.id).catch(() => {});
aiChannelId = aiThread.id;
const welcomeEmbed = new Discord.EmbedBuilder()
.setTitle(msgconfig.Ticket.AIMode.ThreadWelcomeTitle)
.setDescription(msgconfig.Ticket.AIMode.ThreadWelcomeMessage)
.setColor(supportbot.Embed.Colours.General);
await aiThread.send({ embeds: [welcomeEmbed] });
}
db.setTicketAIState(ticketId, {
enabled: true,
aiChannelId,
aiType: "thread",
enabledBy: interaction.user.id,
enabledAt: new Date().toISOString(),
});
const embed = new Discord.EmbedBuilder()
.setDescription(msgconfig.Ticket.AIMode.EnabledMessage)
.setColor(supportbot.Embed.Colours.Success);
return interaction.reply({
embeds: [embed],
flags: Discord.MessageFlags.Ephemeral,
});
} catch (error) {
console.error("Error enabling ticket AI:", error);
return interaction.reply({
content: msgconfig.Ticket.AIMode.EnableError,
flags: Discord.MessageFlags.Ephemeral,
});
}
}
if (interaction.customId.startsWith("ticket_ai_disable:")) {
const ticketId = interaction.customId.split(":")[1];
const ticket = db.getTicket(ticketId);
if (!ticket) {
return interaction.reply({
content: msgconfig.Ticket.AIMode.TicketNotFound,
flags: Discord.MessageFlags.Ephemeral,
});
}
try {
db.setTicketAIState(ticketId, {
enabled: false,
aiChannelId: null,
aiType: null,
enabledBy: interaction.user.id,
enabledAt: null,
});
const embed = new Discord.EmbedBuilder()
.setDescription(msgconfig.Ticket.AIMode.DisabledMessage)
.setColor(supportbot.Embed.Colours.Success);
return interaction.reply({
embeds: [embed],
flags: Discord.MessageFlags.Ephemeral,
});
} catch (error) {
console.error("Error disabling ticket AI:", error);
return interaction.reply({
content: msgconfig.Ticket.AIMode.DisableError,
flags: Discord.MessageFlags.Ephemeral,
});
}
}
2024-07-30 17:45:35 +01:00
if (interaction.customId === "unarchiveTicket") {
2024-10-10 19:14:45 +01:00
if (supportbot.Ticket.TicketType === "threads") {
await interaction.channel.setArchived(false);
}
if (supportbot.Ticket.TicketType === "channels") {
const { getRole, getChannel } = interaction.client;
2026-03-10 20:02:43 +00:00
await interaction.channel.setParent(
supportbot.Ticket.TicketChannelsCategory,
);
2025-09-20 23:09:22 +01:00
const ticketData = db.getAllTickets();
2026-03-10 20:02:43 +00:00
const ticketInfo = ticketData.find(
(t) => t.ticket_id === interaction.channel.id,
);
2024-10-10 19:14:45 +01:00
if (ticketInfo) {
2026-03-10 20:02:43 +00:00
const user =
interaction.guild.members.cache.get(ticketInfo.user_id) ||
ticketInfo.user_id;
const claimedBy =
interaction.guild.members.cache.get(ticketInfo.claimed_by) ||
ticketInfo.claimed_by;
const Admin = await interaction.guild.roles.fetch(
supportbot.Roles.StaffMember.Admin,
);
const Staff = await interaction.guild.roles.fetch(
supportbot.Roles.StaffMember.Staff,
);
2024-10-10 19:14:45 +01:00
if (user && user.id) {
await interaction.channel.permissionOverwrites.edit(user.id, {
ViewChannel: true,
SendMessages: true,
ReadMessageHistory: true,
});
}
if (supportbot.ClaimTickets === true) {
if (claimedBy && claimedBy.id) {
2026-03-10 20:02:43 +00:00
await interaction.channel.permissionOverwrites.edit(
claimedBy.id,
{
ViewChannel: true,
SendMessages: true,
ReadMessageHistory: true,
},
);
}
2024-10-10 19:14:45 +01:00
}
if (supportbot.ClaimTickets === false) {
if (Staff && Staff.id) {
2026-03-10 20:02:43 +00:00
await interaction.channel.permissionOverwrites.edit(
claimedBy.id,
{
ViewChannel: true,
SendMessages: true,
ReadMessageHistory: true,
},
);
}
2024-10-10 19:14:45 +01:00
}
if (Admin && Admin.id) {
await interaction.channel.permissionOverwrites.edit(Admin.id, {
ViewChannel: true,
SendMessages: true,
ReadMessageHistory: true,
});
}
2026-03-10 20:02:43 +00:00
await interaction.channel.permissionOverwrites.edit(
interaction.guild.roles.everyone.id,
{
ViewChannel: false,
SendMessages: false,
ReadMessageHistory: false,
},
);
2024-10-10 19:14:45 +01:00
}
}
const unrcembed = new Discord.EmbedBuilder()
.setDescription(msgconfig.Ticket.TicketUnarchived)
.setColor(supportbot.Embed.Colours.Success);
2024-07-30 17:45:35 +01:00
await interaction.update({
embeds: [unrcembed],
components: [],
});
}
2024-07-09 22:49:49 +01:00
if (interaction.customId === "createticket") {
if (supportbot.Ticket.TicketReason) {
const modal = new Discord.ModalBuilder()
.setCustomId("ticketReasonModal")
.setTitle("Ticket Reason")
.addComponents(
new Discord.ActionRowBuilder().addComponents(
new Discord.TextInputBuilder()
.setCustomId("reasonInput")
.setLabel("Reason")
.setStyle(Discord.TextInputStyle.Paragraph)
2026-03-10 20:02:43 +00:00
.setRequired(true),
),
2024-07-09 22:49:49 +01:00
);
await interaction.showModal(modal);
} else {
try {
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
if (!cmd) return;
await cmd.run(interaction);
} catch (error) {
console.error("Error executing the ticket command:", error);
await interaction.reply({
content: "An error occurred while creating the ticket.",
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2024-07-09 22:49:49 +01:00
});
}
2021-10-24 22:48:25 +01:00
}
}
2024-06-12 12:54:31 +01:00
if (interaction.customId === "openticket") {
2024-07-09 22:49:49 +01:00
if (supportbot.Ticket.TicketReason) {
const modal = new Discord.ModalBuilder()
.setCustomId("ticketReasonModal")
.setTitle("Ticket Reason")
.addComponents(
new Discord.ActionRowBuilder().addComponents(
new Discord.TextInputBuilder()
.setCustomId("reasonInput")
.setLabel("Reason")
.setStyle(Discord.TextInputStyle.Paragraph)
2026-03-10 20:02:43 +00:00
.setRequired(true),
),
2024-07-09 22:49:49 +01:00
);
await interaction.showModal(modal);
} else {
try {
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
if (!cmd) return;
await cmd.run(interaction);
} catch (error) {
console.error(error);
}
2021-10-24 22:48:25 +01:00
}
}
2024-06-12 12:54:31 +01:00
2024-07-09 22:49:49 +01:00
if (interaction.customId.startsWith("claimticket-")) {
const ticketChannelId = interaction.customId.split("-")[1];
2026-03-10 20:02:43 +00:00
const ticketChannel =
interaction.guild.channels.cache.get(ticketChannelId);
2024-06-12 12:54:31 +01:00
if (!ticketChannel) {
return interaction.reply({
content: "Ticket channel not found.",
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2021-10-24 22:48:25 +01:00
});
2024-06-12 12:54:31 +01:00
}
2025-09-20 23:09:22 +01:00
const { getRole } = interaction.client;
2026-03-10 20:02:43 +00:00
const Staff = await getRole(
supportbot.Roles.StaffMember.Staff,
interaction.guild,
);
const Admin = await getRole(
supportbot.Roles.StaffMember.Admin,
interaction.guild,
);
2024-06-12 12:54:31 +01:00
const RolePerms = new Discord.EmbedBuilder()
.setTitle("Invalid Permissions!")
.setDescription(
2026-03-10 20:02:43 +00:00
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``,
2024-06-12 12:54:31 +01:00
)
.setColor(supportbot.Embed.Colours.Warn);
if (!Staff || !Admin) {
2025-09-20 23:09:22 +01:00
return interaction.reply({ embeds: [RolePerms], ephemeral: true });
2024-06-12 12:54:31 +01:00
}
2021-10-24 22:48:25 +01:00
2024-06-12 12:54:31 +01:00
const NoPermsClaim = new Discord.EmbedBuilder()
.setTitle(msgconfig.Ticket.ClaimTickets.NoPermsToClaimTitle)
.setDescription(
2026-03-10 20:02:43 +00:00
msgconfig.Ticket.ClaimTickets.NoPermsToClaim.replace(
"%channel%",
ticketChannel.name,
),
2024-06-12 12:54:31 +01:00
)
.setColor(supportbot.Embed.Colours.Error);
2026-03-10 20:02:43 +00:00
if (
!interaction.member.roles.cache.has(Staff.id) &&
!interaction.member.roles.cache.has(Admin.id)
) {
2025-09-20 23:09:22 +01:00
return interaction.reply({ embeds: [NoPermsClaim], ephemeral: true });
2024-06-12 12:54:31 +01:00
}
2024-10-10 19:14:45 +01:00
if (supportbot.Ticket.TicketType === "threads") {
2025-09-20 23:09:22 +01:00
await ticketChannel.members.add(interaction.user.id);
} else {
2024-10-10 19:14:45 +01:00
await ticketChannel.permissionOverwrites.create(interaction.user.id, {
2025-09-20 23:09:22 +01:00
ViewChannel: true,
SendMessages: true,
ReadMessageHistory: true,
});
2024-10-10 19:14:45 +01:00
await ticketChannel.permissionOverwrites.create(Admin, {
2025-09-20 23:09:22 +01:00
ViewChannel: true,
SendMessages: true,
ReadMessageHistory: true,
});
2026-03-10 20:02:43 +00:00
await ticketChannel.permissionOverwrites.create(
interaction.guild.roles.everyone,
{
ViewChannel: false,
},
);
2025-09-20 23:09:22 +01:00
}
2024-06-12 12:54:31 +01:00
2026-03-10 20:02:43 +00:00
const pingclaimedstaff = await ticketChannel.send(
`<@${interaction.user.id}>`,
);
2025-09-20 23:09:22 +01:00
setTimeout(() => pingclaimedstaff.delete(), 2000);
2024-06-12 12:54:31 +01:00
2025-09-20 23:09:22 +01:00
const ticketInfo = db.getTicket(ticketChannelId);
if (ticketInfo) {
db.updateTicketStatus(ticketChannelId, ticketInfo.status);
ticketInfo.claimed_by = interaction.user.id;
2021-10-24 22:48:25 +01:00
}
2024-06-12 12:54:31 +01:00
const claimMessage = await interaction.message.fetch();
const claimedEmbed = new Discord.EmbedBuilder(claimMessage.embeds[0].data)
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimedTitle)
.setDescription(
2026-03-10 20:02:43 +00:00
msgconfig.Ticket.ClaimTickets.ClaimMessage_Edit.replace(
"%user%",
`${interaction.user.id}`,
).replace("%channel%", `${ticketChannel.id}`),
2024-06-12 12:54:31 +01:00
)
.setColor(supportbot.Embed.Colours.Success);
const successfullyClaimed = new Discord.EmbedBuilder()
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimedTitle)
2026-03-10 20:02:43 +00:00
.setDescription(
msgconfig.Ticket.ClaimTickets.Claimed.replace(
"%channel%",
`${ticketChannel.id}`,
),
2025-09-20 23:09:22 +01:00
)
2024-06-12 12:54:31 +01:00
.setColor(supportbot.Embed.Colours.Success);
await claimMessage.edit({ embeds: [claimedEmbed], components: [] });
2026-03-10 20:02:43 +00:00
await interaction.reply({
embeds: [successfullyClaimed],
ephemeral: true,
});
2021-10-24 22:48:25 +01:00
}
2024-06-13 17:36:44 +01:00
// SUGGESTION INTERACTIONS [START]
2024-07-09 22:49:49 +01:00
if (
interaction.customId === "upvote" ||
interaction.customId === "downvote" ||
interaction.customId === "removevote"
) {
2024-06-13 17:36:44 +01:00
const suggestion = suggestions[interaction.message.id];
2024-07-09 22:49:49 +01:00
if (!suggestion)
2026-03-10 20:02:43 +00:00
return interaction.reply({
content: "Suggestion not found.",
ephemeral: true,
});
2024-06-13 17:36:44 +01:00
const userId = interaction.user.id;
const hasUpvoted = suggestion.upvotes.includes(userId);
const hasDownvoted = suggestion.downvotes.includes(userId);
2024-07-09 22:49:49 +01:00
if (interaction.customId === "upvote") {
2024-06-13 17:36:44 +01:00
if (hasUpvoted) {
2024-07-09 22:49:49 +01:00
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
2024-06-13 17:36:44 +01:00
} else {
suggestion.upvotes.push(userId);
if (hasDownvoted) {
2026-03-10 20:02:43 +00:00
suggestion.downvotes = suggestion.downvotes.filter(
(id) => id !== userId,
);
2024-06-13 17:36:44 +01:00
}
}
2024-07-09 22:49:49 +01:00
} else if (interaction.customId === "downvote") {
2024-06-13 17:36:44 +01:00
if (hasDownvoted) {
2026-03-10 20:02:43 +00:00
suggestion.downvotes = suggestion.downvotes.filter(
(id) => id !== userId,
);
2024-06-13 17:36:44 +01:00
} else {
suggestion.downvotes.push(userId);
if (hasUpvoted) {
2026-03-10 20:02:43 +00:00
suggestion.upvotes = suggestion.upvotes.filter(
(id) => id !== userId,
);
2024-06-13 17:36:44 +01:00
}
}
2024-07-09 22:49:49 +01:00
} else if (interaction.customId === "removevote") {
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
2026-03-10 20:02:43 +00:00
suggestion.downvotes = suggestion.downvotes.filter(
(id) => id !== userId,
);
2024-06-13 17:36:44 +01:00
}
2026-03-10 20:02:43 +00:00
fs.writeFileSync(
"./Data/SuggestionData.json",
JSON.stringify(suggestions, null, 2),
);
2024-06-13 17:36:44 +01:00
const upvoteCount = suggestion.upvotes.length;
const downvoteCount = suggestion.downvotes.length;
2026-03-10 20:02:43 +00:00
const updatedEmbed = new Discord.EmbedBuilder(
interaction.message.embeds[0].data,
).setFields([
2024-07-09 22:49:49 +01:00
{ name: "Suggestion", value: suggestion.suggestion, inline: true },
{ name: "From", value: `<@${suggestion.author}>` },
{
name: `${supportbot.Suggestions.UpvoteEmoji} ${supportbot.Suggestions.UpvoteTitle}`,
value: `${upvoteCount}`,
inline: true,
},
{
name: `${supportbot.Suggestions.DownvoteEmoji} ${supportbot.Suggestions.DownvoteTitle}`,
value: `${downvoteCount}`,
inline: true,
},
]);
2024-06-13 17:36:44 +01:00
await interaction.update({ embeds: [updatedEmbed] });
}
2021-10-24 22:48:25 +01:00
}
2024-06-12 12:54:31 +01:00
async function handleInvites(interaction, enable) {
if (supportbot.Ticket.Invites.StaffOnly) {
2024-07-30 17:45:35 +01:00
const { getRole, getChannel } = interaction.client;
2026-03-10 20:02:43 +00:00
const SupportStaff = await getRole(
supportbot.Roles.StaffMember.Staff,
interaction.guild,
);
const Admin = await getRole(
supportbot.Roles.StaffMember.Admin,
interaction.guild,
);
2024-06-12 12:54:31 +01:00
if (!SupportStaff || !Admin) {
2024-07-09 22:49:49 +01:00
return interaction.reply(
2026-03-10 20:02:43 +00:00
"Some roles seem to be missing!\nPlease check for errors when starting the bot.",
2024-07-09 22:49:49 +01:00
);
2024-06-12 12:54:31 +01:00
}
const NoPerms = new Discord.EmbedBuilder()
.setTitle("Invalid Permissions!")
.setDescription(
2026-03-10 20:02:43 +00:00
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``,
2024-06-12 12:54:31 +01:00
)
.setColor(supportbot.Embed.Colours.Warn);
2024-07-09 22:49:49 +01:00
if (
!interaction.member.roles.cache.has(SupportStaff.id) &&
!interaction.member.roles.cache.has(Admin.id)
) {
2024-06-12 12:54:31 +01:00
return interaction.reply({ embeds: [NoPerms] });
}
}
await interaction.channel.setInvitable(enable);
2026-03-10 20:02:43 +00:00
const message = enable
? msgconfig.Ticket.EnableInvites
: msgconfig.Ticket.DisableInvites;
const embed = new Discord.EmbedBuilder()
.setDescription(message)
.setColor(supportbot.Embed.Colours.General);
2024-06-12 12:54:31 +01:00
await interaction.reply({
embeds: [embed],
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2024-06-12 12:54:31 +01:00
});
}
2024-06-13 17:36:44 +01:00
2026-03-10 20:02:43 +00:00
if (
interaction.type === Discord.InteractionType.ModalSubmit &&
interaction.customId === "editProfileModal"
) {
2024-07-03 13:46:57 +01:00
const userId = interaction.user.id;
const profilePath = `./Data/Profiles/${userId}.json`;
let profileData;
if (fs.existsSync(profilePath)) {
profileData = JSON.parse(fs.readFileSync(profilePath, "utf8"));
} else {
profileData = {
bio: "",
timezone: "",
2024-07-09 22:49:49 +01:00
clockedIn: false,
2024-07-03 13:46:57 +01:00
};
}
try {
2024-07-09 22:49:49 +01:00
const newBio = interaction.fields.getTextInputValue("bio");
const newTimezone = interaction.fields.getTextInputValue("timezone");
2024-07-03 13:46:57 +01:00
profileData.bio = newBio;
profileData.timezone = newTimezone;
fs.writeFileSync(profilePath, JSON.stringify(profileData, null, 2));
const updatedProfileEmbed = new Discord.EmbedBuilder()
.setTitle(`${interaction.user.username}'s Profile`)
.setColor(supportbot.Embed.Colours.General)
.setThumbnail(interaction.user.displayAvatarURL())
.addFields(
2024-07-09 22:49:49 +01:00
{ name: "Bio", value: newBio || "No bio set.", inline: false },
2026-03-10 20:02:43 +00:00
{
name: "Timezone",
value: newTimezone || "No timezone set.",
inline: true,
},
2024-07-03 13:46:57 +01:00
);
if (profileData.clockedIn !== undefined) {
updatedProfileEmbed.addFields({
2024-07-09 22:49:49 +01:00
name: "Clocked In Status",
value: profileData.clockedIn ? "✅ Clocked In" : "❌ Clocked Out",
inline: true,
2024-07-03 13:46:57 +01:00
});
}
2024-06-13 17:36:44 +01:00
2026-03-10 20:02:43 +00:00
await interaction.reply({
embeds: [updatedProfileEmbed],
ephemeral: true,
});
2024-07-03 13:46:57 +01:00
} catch (error) {
console.error("Failed to update profile data: ", error);
2024-07-09 22:49:49 +01:00
await interaction.reply({
2026-03-10 20:02:43 +00:00
content:
"There was an error while updating your profile. Please try again later.",
2025-09-22 18:36:04 +01:00
flags: Discord.MessageFlags.Ephemeral,
2024-07-09 22:49:49 +01:00
});
2024-07-03 13:46:57 +01:00
}
}
2024-06-13 17:36:44 +01:00
});