AeThex-Bot-Master/aethex-bot/commands/ticket.js
sirpiglr 7ca85f433a Add persistent storage for federation mappings and tickets
Integrates Supabase for persistent storage of federation mappings and active tickets, along with adding new commands for announcements, audit logs, and polls.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: 110a0afc-77c3-48ac-afca-8e969438dafc
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/hHBt1No
Replit-Helium-Checkpoint-Created: true
2025-12-08 03:38:13 +00:00

148 lines
4.9 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],
},
],
});
const ticketData = {
userId: interaction.user.id,
guildId: interaction.guildId,
reason: reason,
createdAt: Date.now(),
};
client.activeTickets.set(ticketChannel.id, ticketData);
if (client.saveTicket) {
await client.saveTicket(ticketChannel.id, ticketData);
}
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);
if (client.closeTicket) {
await client.closeTicket(interaction.channelId);
}
setTimeout(async () => {
try {
await interaction.channel.delete();
} catch (e) {
console.error('Failed to delete ticket channel:', e);
}
}, 5000);
}
},
};