Implement guards for Supabase-dependent commands, refine error handling, and introduce feed synchronization capabilities. Replit-Commit-Author: Agent Replit-Commit-Session-Id: e72fc1b7-94bd-4d6c-801f-cbac2fae245c Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 48ccfc2d-e27b-4e3b-b0d2-25bdb3ece9c8 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/e72fc1b7-94bd-4d6c-801f-cbac2fae245c/NXjYRWJ Replit-Helium-Checkpoint-Created: true
139 lines
4.7 KiB
JavaScript
139 lines
4.7 KiB
JavaScript
const { SlashCommandBuilder, EmbedBuilder, ChannelType, PermissionFlagsBits, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
|
|
|
|
module.exports = {
|
|
data: new SlashCommandBuilder()
|
|
.setName('ticket')
|
|
.setDescription('Support ticket system')
|
|
.addSubcommand(subcommand =>
|
|
subcommand
|
|
.setName('create')
|
|
.setDescription('Create a support ticket')
|
|
.addStringOption(option =>
|
|
option.setName('reason')
|
|
.setDescription('Reason for the ticket')
|
|
.setRequired(false)
|
|
)
|
|
)
|
|
.addSubcommand(subcommand =>
|
|
subcommand
|
|
.setName('close')
|
|
.setDescription('Close the current ticket')
|
|
),
|
|
|
|
async execute(interaction, supabase, client) {
|
|
const subcommand = interaction.options.getSubcommand();
|
|
|
|
if (subcommand === 'create') {
|
|
const reason = interaction.options.getString('reason') || 'No reason provided';
|
|
|
|
const existingTicket = [...client.activeTickets.entries()].find(
|
|
([, data]) => data.userId === interaction.user.id && data.guildId === interaction.guildId
|
|
);
|
|
|
|
if (existingTicket) {
|
|
const embed = new EmbedBuilder()
|
|
.setColor(0xff0000)
|
|
.setTitle('Ticket Already Exists')
|
|
.setDescription(`You already have an open ticket: <#${existingTicket[0]}>`)
|
|
.setTimestamp();
|
|
|
|
await interaction.reply({ embeds: [embed], ephemeral: true });
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const ticketChannel = await interaction.guild.channels.create({
|
|
name: `ticket-${interaction.user.username}`,
|
|
type: ChannelType.GuildText,
|
|
permissionOverwrites: [
|
|
{
|
|
id: interaction.guild.id,
|
|
deny: [PermissionFlagsBits.ViewChannel],
|
|
},
|
|
{
|
|
id: interaction.user.id,
|
|
allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages],
|
|
},
|
|
],
|
|
});
|
|
|
|
client.activeTickets.set(ticketChannel.id, {
|
|
userId: interaction.user.id,
|
|
guildId: interaction.guildId,
|
|
reason: reason,
|
|
createdAt: Date.now(),
|
|
});
|
|
|
|
const closeButton = new ActionRowBuilder().addComponents(
|
|
new ButtonBuilder()
|
|
.setCustomId(`ticket_close_${ticketChannel.id}`)
|
|
.setLabel('Close Ticket')
|
|
.setStyle(ButtonStyle.Danger)
|
|
);
|
|
|
|
const ticketEmbed = new EmbedBuilder()
|
|
.setColor(0x7c3aed)
|
|
.setTitle('Support Ticket')
|
|
.setDescription(`Ticket created by ${interaction.user}`)
|
|
.addFields(
|
|
{ name: 'Reason', value: reason },
|
|
{ name: 'Created', value: `<t:${Math.floor(Date.now() / 1000)}:F>` }
|
|
)
|
|
.setFooter({ text: 'Click the button below to close this ticket' })
|
|
.setTimestamp();
|
|
|
|
await ticketChannel.send({ embeds: [ticketEmbed], components: [closeButton] });
|
|
|
|
const successEmbed = new EmbedBuilder()
|
|
.setColor(0x00ff00)
|
|
.setTitle('Ticket Created')
|
|
.setDescription(`Your ticket has been created: ${ticketChannel}`)
|
|
.setTimestamp();
|
|
|
|
await interaction.reply({ embeds: [successEmbed], ephemeral: true });
|
|
} catch (error) {
|
|
console.error('Ticket creation error:', error);
|
|
const errorEmbed = new EmbedBuilder()
|
|
.setColor(0xff0000)
|
|
.setTitle('Error')
|
|
.setDescription('Failed to create ticket. I may not have the required permissions.')
|
|
.setTimestamp();
|
|
|
|
await interaction.reply({ embeds: [errorEmbed], ephemeral: true });
|
|
}
|
|
}
|
|
|
|
if (subcommand === 'close') {
|
|
const ticketData = client.activeTickets.get(interaction.channelId);
|
|
|
|
if (!ticketData) {
|
|
const embed = new EmbedBuilder()
|
|
.setColor(0xff0000)
|
|
.setTitle('Not a Ticket')
|
|
.setDescription('This channel is not a support ticket.')
|
|
.setTimestamp();
|
|
|
|
await interaction.reply({ embeds: [embed], ephemeral: true });
|
|
return;
|
|
}
|
|
|
|
const embed = new EmbedBuilder()
|
|
.setColor(0xff6600)
|
|
.setTitle('Closing Ticket')
|
|
.setDescription('This ticket will be closed in 5 seconds...')
|
|
.setTimestamp();
|
|
|
|
await interaction.reply({ embeds: [embed] });
|
|
|
|
client.activeTickets.delete(interaction.channelId);
|
|
|
|
setTimeout(async () => {
|
|
try {
|
|
await interaction.channel.delete();
|
|
} catch (e) {
|
|
console.error('Failed to delete ticket channel:', e);
|
|
}
|
|
}, 5000);
|
|
}
|
|
},
|
|
};
|