const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType, Events, Modal, ModalBuilder, TextInputBuilder, TextInputStyle, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, SlashCommandBuilder } = require('discord.js'); module.exports = { name: 'ticket', aliases: ["tickets"], description: 'Create ticket for SkyHikerMC', cooldown: 5, permissions: { bot: '', user: '', }, mode: { developerOnly: false, ownerGuildOnly: false, }, category: "Staff Ultility", async run(bot, interaction, args, timecooldown, prefix) { try { const ticketChannel = interaction.mentions.channels.first(); const managementRole = bot.config.settings.management; // Required user have management Role if (!interaction.member.roles.cache.has(managementRole)) { setTimeout(() => { interaction.channel.messages.delete(interaction); }, 1000); const noPermEmbed = new EmbedBuilder() .setColor(bot.config.embed.error) .setTitle(`<:alert:861479518811979786> No Permission to Access`) .setDescription("You do not have the necessary permissions to use this command.") .setFooter({ text: bot.config.embed.footer, iconURL: bot.config.embed.serverIcon }) .setTimestamp(); return interaction.channel.send({ embeds: [noPermEmbed] }) .then((message) => { setTimeout(() => { message.delete(); }, 10000); }); } // Required command to have following the length if (!args.length) { setTimeout(() => { interaction.channel.messages.delete(interaction); }, 3000); const instructionEmbed = new EmbedBuilder() .setColor(bot.config.embed.instrucColor) .setTitle(`<:info:875347263558389800> Command Info`) .setDescription("Please follow the command:```-ticket ```") .setFooter({ text: bot.config.embed.footer, iconURL: bot.config.embed.serverIcon }) .setTimestamp(); return interaction.channel.send({ embeds: [instructionEmbed] }) .then((message) => { setTimeout(() => { message.delete(); }, 10000); }); } // If Channel not existing if (!ticketChannel) { setTimeout(() => { interaction.channel.messages.delete(interaction); }, 3000); const channelNotExistEmbed = new EmbedBuilder() .setColor(bot.config.embed.error) .setTitle(`<:alert:861479518811979786> Channel is not Existing`) .setDescription("Please specified the channel you want to send the ticket Panel at.") .setFooter({ text: bot.config.embed.footer, iconURL: bot.config.embed.serverIcon }) .setTimestamp(); return interaction.channel.send({ embeds: [channelNotExistEmbed] }) .then((message) => { setTimeout(() => { message.delete(); }, 10000); }); } // Create menu for Panel _____________________________________________________________________________________________ const ticketSelection = new StringSelectMenuBuilder() .setCustomId('ticket_selection') .setPlaceholder('Select a Ticket category you want to create.') .addOptions( new StringSelectMenuOptionBuilder() .setLabel('Support Ticket') .setValue('supportselection') .setEmoji('🛠'), new StringSelectMenuOptionBuilder() .setLabel('Billing Ticket') .setValue('billingselection') .setEmoji('💵'), ); const ticketSelectionRow = new ActionRowBuilder().addComponents(ticketSelection); // Create Modal for Ticket Categories _______________________________________________________________________________ // Create the support modal ================================ const supportModal = new ModalBuilder() .setCustomId('supportmodal') .setTitle('Support Ticket Form'); // support Forms: const supportFirst = new TextInputBuilder() .setCustomId('support_first') .setLabel("🔹 Your In-game name?") .setPlaceholder('FG') .setStyle(TextInputStyle.Short) .setRequired(true); const supportSecond = new TextInputBuilder() .setCustomId('support_second') .setLabel("🔹 What are you looking for in this ticket?") .setPlaceholder('Questions / Bug / Reporting / Prize Claim / Others') .setStyle(TextInputStyle.Short) .setRequired(true); const supportThird = new TextInputBuilder() .setCustomId('support_third') .setLabel("🔹 The title of the report?") .setPlaceholder('Plugin Bug / Report others or hack / Any') .setStyle(TextInputStyle.Short) .setRequired(true); const supportForth = new TextInputBuilder() .setCustomId('support_forth') .setLabel("🔹 Please describe your question here 😉") .setStyle(TextInputStyle.Paragraph) .setRequired(true); // An action row only holds one text input, // so you need one action row per text input. const supportFirstActionRow = new ActionRowBuilder().addComponents(supportFirst); const supportSecondActionRow = new ActionRowBuilder().addComponents(supportSecond); const supportThirdActionRow = new ActionRowBuilder().addComponents(supportThird); const supportForthActionRow = new ActionRowBuilder().addComponents(supportForth); // Add inputs to the modal supportModal.addComponents(supportFirstActionRow, supportSecondActionRow, supportThirdActionRow, supportForthActionRow); // Create the billing modal ================================ const billingModal = new ModalBuilder() .setCustomId('billingmodal') .setTitle('Billing Ticket Form'); // Billing Forms: const billingFirst = new TextInputBuilder() .setCustomId('billing_first') .setLabel("🔸 Your In-game name?") .setPlaceholder('FG') .setStyle(TextInputStyle.Short) .setRequired(true); const billingSecond = new TextInputBuilder() .setCustomId('billing_second') .setLabel("🔸 Your e-mail for purchasing?") .setPlaceholder('@gmail.com / @hotmail.com...') .setStyle(TextInputStyle.Short) .setRequired(true); const billingThird = new TextInputBuilder() .setCustomId('billing_third') .setLabel("🔸 Your prefered payment gateway?") .setPlaceholder('PayPal / Credit or Debit Cards / TNG / Bank-in / Others') .setStyle(TextInputStyle.Short) .setRequired(true); const billingForth = new TextInputBuilder() .setCustomId('billing_forth') .setLabel("🔸 What you would like to purchase?") .setPlaceholder('In-game Items / Donations') .setStyle(TextInputStyle.Short) .setRequired(true); const billingFifth = new TextInputBuilder() .setCustomId('billing_fifth') .setLabel("🔸 Please describe your question here 😉") .setStyle(TextInputStyle.Paragraph) .setRequired(true); // An action row only holds one text input, // so you need one action row per text input. const billingFirstActionRow = new ActionRowBuilder().addComponents(billingFirst); const billingSecondActionRow = new ActionRowBuilder().addComponents(billingSecond); const billingThirdActionRow = new ActionRowBuilder().addComponents(billingThird); const billingForthActionRow = new ActionRowBuilder().addComponents(billingForth); const billingFifthActionRow = new ActionRowBuilder().addComponents(billingFifth); // Add inputs to the modal billingModal.addComponents(billingFirstActionRow, billingSecondActionRow, billingThirdActionRow, billingForthActionRow, billingFifthActionRow); // Create buttons for Ticket ________________________________________________________________________________________ const ticketResolveButton = new ButtonBuilder() .setStyle(ButtonStyle.Success) .setLabel('Resolve') .setCustomId('ticket_resolve') .setEmoji('✅'); const ticketCloseButton = new ButtonBuilder() .setStyle(ButtonStyle.Danger) .setLabel('Close') .setCustomId('ticket_close') .setEmoji('⛔️'); const ticketReceiptButton = new ButtonBuilder() .setStyle(ButtonStyle.Danger) .setLabel('Logging') .setCustomId('ticket_receipt') .setEmoji('📩'); const ticketActionRow = new ActionRowBuilder().addComponents(ticketResolveButton, ticketCloseButton, ticketReceiptButton); //Start creating Ticket ________________________________________________________________________________________ //Create panel for user to choose what ticket they want const ticketPanelEmbed = new EmbedBuilder() .setDescription(`## **💌 ‎ ‎ ‎| ‎ ‎ ‎ SUPPORT TICKET** \nGet support from our staff immediately!\nPlease fill in the form accordingly ☺️`) .setColor('#499D6C') .setImage('https://s10.gifyu.com/images/S4VYM.gif') .addFields( { name: ' ', value: `\n` + `🔹 **ɢᴇɴᴇʀᴀʟ ꜱᴜᴘᴘᴏʀᴛ**\n` + `🔸 **ʙɪʟʟɪɴɢ ꜱᴜᴘᴘᴏʀᴛ**\n` }, { name: ' ', value: `\n\n` + `[**ᴡɪᴋɪ**](https://wiki.skyhikermc.com/) **·** [**ꜱᴛᴏʀᴇ**](http://store.skyhikermc.com/) **·** ` + `[**ʀᴜʟᴇꜱ**](https://wiki.skyhikermc.com/rules) **·** [**ꜰᴀᴄᴇʙᴏᴏᴋ**](https://www.facebook.com/SkyHikerMC/) **·** ` + `[**ᴅɪꜱᴄᴏʀᴅ**](https://discord.skyhikermc.com/) ` } ) .setFooter({ text: `${bot.config.embed.footer} ‎ ‎ ‎ | ‎‎ ‎𝘏𝘰𝘮𝘦 𝘰𝘧 𝘚𝘬𝘺𝘉𝘭𝘰𝘤𝘬𝘦𝘳𝘴, 𝘏𝘰𝘮𝘦 𝘧𝘰𝘳 𝘚𝘬𝘺𝘏𝘪𝘬𝘦𝘳𝘴`, iconURL: bot.config.embed.serverIcon }) // Send the panel to the specified channel const panelMessage = await ticketChannel.send({ embeds: [ticketPanelEmbed], components: [ticketSelectionRow] }); interaction.channel.messages.delete(interaction); console.log('New Ticket Panel Created.'); // Selection button interaction ________________________________________________________________________________________ const selectCollector = interaction.channel.createMessageComponentCollector({ componentType: ComponentType.StringSelect }); selectCollector.on('collect', async (i) => { // Handle ticket creation based on the selected ticket type // Support Ticket ================================================================ if (i.values[0] === 'supportselection') { // Show the modal to the user i.showModal(supportModal); await supportModal.isModalSubmit(); const ticketName = `Support-${i.user.id}`; const ticketroom = await ticketChannel.threads.create({ name: ticketName, type: ChannelType.PrivateThread }); console.log(`! New support ticket thread: ${ticketroom.name}`); // Send ticket Created Embed to Panel, acknowledge user the ticket successfully created. const supportCreatedEmbed = new EmbedBuilder() .setColor('#499D6C') .setDescription(`**💌 | Ticket Created**\nOpened a new ticket: ${ticketroom}`) .setFooter({ text: bot.config.embed.footer, iconURL: bot.config.embed.serverIcon }) .setTimestamp(); await panelMessage.reply({ embeds: [supportCreatedEmbed], ephemeral: true }); // Then send the ticket Welcome Embed to the ticket room const supportWelcomeEmbed = new EmbedBuilder() .setColor('#499D6C') .setDescription(`## **💌 TICKET CREATED - SUPPORT**`) .addFields( { name: ' ', value: `Hello @${i.user.id}` + `Thank you for contacting support.` + `Please describe your issue and support team will response as soon as possible!` }, { name: ' ', value: `\n\n` + `[**ᴡɪᴋɪ**](https://wiki.skyhikermc.com/) **·** [**ꜱᴛᴏʀᴇ**](http://store.skyhikermc.com/) **·** ` + `[**ʀᴜʟᴇꜱ**](https://wiki.skyhikermc.com/rules) **·** [**ꜰᴀᴄᴇʙᴏᴏᴋ**](https://www.facebook.com/SkyHikerMC/) **·** ` + `[**ᴅɪꜱᴄᴏʀᴅ**](https://discord.skyhikermc.com/) ` } ) .setImage('https://s10.gifyu.com/images/S4VYM.gif') .setFooter({ text: bot.config.embed.footer, iconURL: bot.config.embed.serverIcon }) .setTimestamp(); await ticketroom.send({ embeds: [supportWelcomeEmbed], components: [ticketActionRow] }); // Send the user's filled form to the ticket room const userFormData = new EmbedBuilder() .setTitle('User Form Data') .setDescription('Form data goes here') .setFooter({ text: bot.config.embed.footer, iconURL: bot.config.embed.serverIcon }) .setTimestamp(); await ticketroom.send({ embeds: [userFormData] }); // Billing Ticket ================================================================ } else if (i.values[0] === 'billingselection') { // Show the modal to the user i.showModal(billingModal); await billingModal.isModalSubmit(); const ticketName = `Billing-${i.user.id}`; const ticketroom = await ticketChannel.threads.create({ name: ticketName, type: ChannelType.PrivateThread }); console.log(`! New billing ticket thread: ${ticketroom.name}`); // Send ticket Created Embed to Panel, acknowledge user the ticket successfully created. const billingCreatedEmbed = new EmbedBuilder() .setColor('#4E5DBC') .setDescription(`**💌 | Ticket Created**\nOpened a new ticket: ${ticketroom}`) .setFooter({ text: bot.config.embed.footer, iconURL: bot.config.embed.serverIcon }) .setTimestamp(); await panelMessage.reply({ embeds: [billingCreatedEmbed], ephemeral: true }); // Then send the ticket Welcome Embed to the ticket room const billingWelcomeEmbed = new EmbedBuilder() .setColor('#4E5DBC') .setDescription(`## **💳 TICKET CREATED - BILLING**`) .addFields( { name: ' ', value: `Hello @${i.user.id}` + `Thank you for contacting support.` + `Please describe your issue and support team will response as soon as possible!` }, { name: ' ', value: `\n\n` + `[**ᴡɪᴋɪ**](https://wiki.skyhikermc.com/) **·** [**ꜱᴛᴏʀᴇ**](http://store.skyhikermc.com/) **·** ` + `[**ʀᴜʟᴇꜱ**](https://wiki.skyhikermc.com/rules) **·** [**ꜰᴀᴄᴇʙᴏᴏᴋ**](https://www.facebook.com/SkyHikerMC/) **·** ` + `[**ᴅɪꜱᴄᴏʀᴅ**](https://discord.skyhikermc.com/) ` } ) .setImage('https://s10.gifyu.com/images/S4VYz.gif') .setFooter({ text: bot.config.embed.footer, iconURL: bot.config.embed.serverIcon }) .setTimestamp(); await ticketroom.send({ embeds: [billingWelcomeEmbed], components: [ticketActionRow] }); // Send the user's filled form to the ticket room const userFormData = new EmbedBuilder() .setTitle('User Form Data') .setDescription('Form data goes here') .setFooter({ text: bot.config.embed.footer, iconURL: bot.config.embed.serverIcon }) .setTimestamp(); await ticketroom.send({ embeds: [userFormData] }); } else { console.log(error); } }); selectCollector.on('end', collected => { console.log(`Ticket: Collected ${collected.size} items`); }); } catch (error) { console.error('Ticket error occurred:', error); } } }