├── LICENSE ├── config.json ├── index.js ├── package.json └── src ├── commands └── setup.js ├── events └── interactionCreate.js └── interactions ├── claimTicket.js ├── closeTicket.js ├── createTicket.js └── deleteTicket.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Wick Studio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "TOKEN": "توكن_البوت", 3 | "ticketCategoryID": "ايدي_الكاتاجوري", 4 | "ticketNumber": 2, 5 | "BACKGROUND": "صورة_الباجراوند", 6 | "SECTIONS": [ 7 | { 8 | "name": "اسم_القسم", 9 | "roleID": "ايدي_الرتبة", 10 | "image": "صورة_القسم" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { 2 | Client, 3 | GatewayIntentBits, 4 | Collection, 5 | Routes, 6 | REST, 7 | } = require("discord.js"); 8 | const client = new Client({ 9 | intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers], 10 | }); 11 | const fs = require("fs"); 12 | var http = require("http"); 13 | http 14 | .createServer(function (req, res) { 15 | res.write("I'm alive"); 16 | res.end(); 17 | }) 18 | .listen(8080); 19 | const config = require("./config.json"); 20 | 21 | client.commands = new Collection(); 22 | client.interactions = new Collection(); 23 | const commands = []; 24 | 25 | // Load commands 26 | const commandFiles = fs 27 | .readdirSync("./src/commands") 28 | .filter((file) => file.endsWith(".js")); 29 | for (const file of commandFiles) { 30 | const command = require(`./src/commands/${file}`); 31 | client.commands.set(command.name, command); 32 | commands.push(command.data); 33 | } 34 | 35 | // Load interactions 36 | const interactionsFiles = fs 37 | .readdirSync("./src/interactions") 38 | .filter((file) => file.endsWith(".js")); 39 | for (const file of interactionsFiles) { 40 | const interaction = require(`./src/interactions/${file}`); 41 | client.interactions.set(interaction.name, interaction); 42 | } 43 | 44 | // Load events 45 | const eventsFiles = fs 46 | .readdirSync("./src/events") 47 | .filter((file) => file.endsWith(".js")); 48 | 49 | for (const file of eventsFiles) { 50 | const event = require(`./src/events/${file}`); 51 | client.on(event.name, async (...args) => { 52 | event.execute(client, config, ...args); 53 | }); 54 | } 55 | const rest = new REST().setToken(process.env.TOKEN); 56 | 57 | client.once("ready", async () => { 58 | await rest.put(Routes.applicationCommands(client.user.id), { 59 | body: commands, 60 | }); 61 | console.log(`Bot is online! ${client.user.username}`); 62 | console.log("Code by Wick Studio"); 63 | console.log("discord.gg/wicks"); 64 | }); 65 | 66 | client.login(process.env.TOKEN); 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fivem-apply", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "Wick", 11 | "license": "MIT", 12 | "dependencies": { 13 | "discord.js": "^14.14.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/commands/setup.js: -------------------------------------------------------------------------------- 1 | const { 2 | SlashCommandBuilder, 3 | ActionRowBuilder, 4 | ButtonBuilder, 5 | AttachmentBuilder, 6 | ButtonStyle, 7 | CommandInteraction, 8 | PermissionsBitField, 9 | } = require('discord.js'); 10 | 11 | module.exports = { 12 | name: 'setup', 13 | data: new SlashCommandBuilder() 14 | .setName('setup') 15 | .setDescription('إعداد رسالة إنشاء التذاكر') 16 | .setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild), 17 | /** 18 | * @param {CommandInteraction} interaction 19 | * @param {Client} client 20 | */ 21 | async execute(client, config, interaction) { 22 | await interaction.deferReply({ ephemeral: true }); 23 | const Attachment = new AttachmentBuilder(config.BACKGROUND, { name: 'background.png' }); 24 | const row = new ActionRowBuilder().addComponents( 25 | ...config.SECTIONS.map((section) => 26 | new ButtonBuilder() 27 | .setCustomId(`create_ticket*_${config.SECTIONS.indexOf(section)}`) 28 | .setLabel(section.name) 29 | .setStyle(ButtonStyle.Primary), 30 | ), 31 | ); 32 | await interaction.channel.send({ files: [Attachment], components: [row] }); 33 | await interaction.editReply({ content: 'تم إرسال رسالة إعداد التذكرة.', ephemeral: true }); 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /src/events/interactionCreate.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'interactionCreate', 3 | async execute(client, config, interaction) { 4 | if (interaction.isCommand()) { 5 | const commandsRunner = client.commands.get(interaction.commandName); 6 | commandsRunner.execute(client, config, interaction); 7 | } 8 | if (!interaction.isSelectMenu() && !interaction.isButton() && !interaction.isModalSubmit()) return; 9 | 10 | const interactionRun = client.interactions.get(interaction.customId.split('*')[0]); 11 | if (interactionRun) interactionRun.execute(client, config, interaction); 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /src/interactions/claimTicket.js: -------------------------------------------------------------------------------- 1 | const { ButtonInteraction, PermissionsBitField } = require('discord.js'); 2 | 3 | module.exports = { 4 | name: 'claim_ticket', 5 | /** 6 | * @param {ButtonInteraction} interaction 7 | * @param {Client} client 8 | */ 9 | async execute(client, config, interaction) { 10 | try { 11 | await interaction.deferReply({}); 12 | if (interaction.user.id == interaction.channel.topic) { 13 | await interaction.editReply({ content: 'يمكن استخدام هذا الزر من قبل طاقم التذاكر فقط.', ephemeral: true }); 14 | return; 15 | } 16 | // Update the channel's permission overwrites 17 | await interaction.channel.permissionOverwrites.set([ 18 | { 19 | id: interaction.guildId, 20 | deny: [PermissionsBitField.Flags.ViewChannel], 21 | }, 22 | { 23 | id: interaction.user.id, 24 | allow: [ 25 | PermissionsBitField.Flags.ViewChannel, 26 | PermissionsBitField.Flags.SendMessages, 27 | PermissionsBitField.Flags.ReadMessageHistory, 28 | ], 29 | }, 30 | { 31 | id: interaction.channel.topic, 32 | allow: [ 33 | PermissionsBitField.Flags.ViewChannel, 34 | PermissionsBitField.Flags.SendMessages, 35 | PermissionsBitField.Flags.ReadMessageHistory, 36 | ], 37 | }, 38 | ]); 39 | interaction.message.components[0].components[1].data.disabled = true; 40 | interaction.message.edit({ components: interaction.message.components }); 41 | // Respond to the claim interaction 42 | await interaction.editReply({ 43 | content: `**تم استلام التذكرة**\nهذه التذكرة قد تم استلامها الآن بواسطة <@${interaction.user.id}>.`, 44 | }); 45 | } catch (error) { 46 | await interaction.editReply({ content: 'حدث خطأ أثناء استلام هذه التذكرة.', ephemeral: true }); 47 | } 48 | }, 49 | }; 50 | -------------------------------------------------------------------------------- /src/interactions/closeTicket.js: -------------------------------------------------------------------------------- 1 | const { ButtonInteraction, EmbedBuilder, ActionRowBuilder, ButtonBuilder, PermissionsBitField, ButtonStyle } = require('discord.js'); 2 | 3 | module.exports = { 4 | name: 'close_ticket', 5 | /** 6 | * @param {ButtonInteraction} interaction 7 | * @param {Client} client 8 | */ 9 | async execute(client, config, interaction) { 10 | try { 11 | const [, , roleID] = interaction.customId.split('_'); 12 | await interaction.deferReply({}); 13 | await interaction.channel.permissionOverwrites.set([ 14 | { 15 | id: interaction.guildId, 16 | deny: [PermissionsBitField.Flags.ViewChannel], 17 | }, 18 | { 19 | id: interaction.channel.topic, 20 | deny: [PermissionsBitField.Flags.ViewChannel], 21 | }, 22 | { 23 | id: roleID, 24 | allow: [ 25 | PermissionsBitField.Flags.ViewChannel, 26 | PermissionsBitField.Flags.SendMessages, 27 | PermissionsBitField.Flags.ReadMessageHistory, 28 | ], 29 | }, 30 | ]); 31 | // Embed message confirming ticket closure 32 | const embed = new EmbedBuilder() 33 | .setColor('#ff5555') 34 | .setTitle('تم إغلاق التذكرة') 35 | .setDescription('تم إغلاق هذه التذكرة. انقر على الزر أدناه إذا كنت ترغب في حذف هذه التذكرة.'); 36 | 37 | // Button to confirm ticket deletion 38 | const row = new ActionRowBuilder().addComponents( 39 | new ButtonBuilder().setCustomId('delete_ticket').setLabel('حذف التذكرة').setStyle(ButtonStyle.Secondary), 40 | ); 41 | interaction.message.components[0].components[0].data.disabled = true; 42 | interaction.message.components[0].components[1].data.disabled = true; 43 | interaction.message.edit({ components: interaction.message.components }); 44 | // Send embed and button 45 | await interaction.editReply({ embeds: [embed], components: [row] }); 46 | const user = await interaction.guild.members.fetch(interaction.channel.topic).catch(() => {}); 47 | // Create an embed with information about the closed ticket 48 | const userEmbed = new EmbedBuilder() 49 | .setTitle('تم اغلاق تذكرتك') // replaced locale.confirmYes.ticketClosed 50 | .setColor('#05131f') 51 | .addField('فتح التذكرة', `<@${interaction.channel.topic}>`, true) // replaced locale.confirmYes.openedBy 52 | .addField('اغلق التذكرة', `<@${interaction.user.id}>`, true) // replaced locale.confirmYes.closedBy 53 | .addField('وقت فتح التذكرة', new Date(interaction.channel.createdTimestamp).toLocaleString(), true) // replaced locale.confirmYes.openTime 54 | .addField('وقت اغلاق التذكرة', new Date().toLocaleString(), true); // replaced locale.confirmYes.closeTime 55 | 56 | if (user) user.send({ embeds: [userEmbed] }); 57 | } catch (error) { 58 | console.log(error); 59 | await interaction.editReply({ content: 'حدث خطأ أثناء إغلاق التذكرة.', ephemeral: true }); 60 | } 61 | }, 62 | }; 63 | -------------------------------------------------------------------------------- /src/interactions/createTicket.js: -------------------------------------------------------------------------------- 1 | const { 2 | ActionRowBuilder, 3 | ButtonBuilder, 4 | ButtonInteraction, 5 | PermissionsBitField, 6 | ButtonStyle, 7 | ChannelType, 8 | AttachmentBuilder, 9 | CategoryChannel, 10 | } = require("discord.js"); 11 | const fs = require("fs"); 12 | module.exports = { 13 | name: "create_ticket", 14 | /** 15 | * @param {ButtonInteraction} interaction 16 | * @param {Client} client 17 | */ 18 | async execute(client, config, interaction) { 19 | const { guild, user } = interaction; 20 | const [, , id] = interaction.customId.split("_"); 21 | await interaction.deferReply({ ephemeral: true }); 22 | try { 23 | const ticketCategory = interaction.guild.channels.cache.get( 24 | config.ticketCategoryID 25 | ); 26 | 27 | if (!ticketCategory) { 28 | return; 29 | } 30 | const hasTicket = await ticketCategory.children.cache.find( 31 | (ch) => ch.topic == interaction.user.id 32 | ); 33 | if (hasTicket) { 34 | interaction.editReply({ 35 | content: "لديك تذكرة بالفعل", 36 | ephemeral: true, 37 | }); 38 | return; 39 | } 40 | 41 | const { roleID, image } = config.SECTIONS[Number(id)]; 42 | config.ticketNumber++; 43 | fs.writeFileSync("config.json", JSON.stringify(config, 0, 1), () => {}); 44 | // Create a new channel for the ticket 45 | const ticketChannel = await guild.channels.create({ 46 | name: `ticket-${config.ticketNumber}`, 47 | type: ChannelType.GuildText, 48 | parent: config.ticketCategoryID, // Optional: Set a parent category for tickets 49 | topic: interaction.user.id, 50 | permissionOverwrites: [ 51 | { 52 | id: roleID, 53 | allow: [ 54 | PermissionsBitField.Flags.ViewChannel, 55 | PermissionsBitField.Flags.SendMessages, 56 | PermissionsBitField.Flags.ReadMessageHistory, 57 | ], 58 | }, 59 | { 60 | id: user.id, 61 | allow: [ 62 | PermissionsBitField.Flags.ViewChannel, 63 | PermissionsBitField.Flags.SendMessages, 64 | PermissionsBitField.Flags.ReadMessageHistory, 65 | ], 66 | }, 67 | { 68 | id: guild.id, 69 | deny: [PermissionsBitField.Flags.ViewChannel], 70 | }, 71 | ], 72 | }); 73 | const Attachment = new AttachmentBuilder(image, { name: "ticket.png" }); 74 | 75 | // Buttons for ticket actions 76 | const row = new ActionRowBuilder().addComponents( 77 | new ButtonBuilder() 78 | .setCustomId(`close_ticket*_${roleID}`) 79 | .setLabel("إغلاق التذكرة") 80 | .setStyle(ButtonStyle.Secondary), 81 | new ButtonBuilder() 82 | .setCustomId(`claim_ticket`) 83 | .setLabel("استلام التذكرة") 84 | .setStyle(ButtonStyle.Secondary) 85 | ); 86 | 87 | // Send an initial message in the ticket channel 88 | ticketChannel.send({ 89 | files: [Attachment], 90 | content: `**مرحباً بك في تذكرة الدعم الخاصة بك, <@${user.id}>. سيساعدك عضو من <@&${roleID}> قريباً.**`, 91 | components: [row], 92 | }); 93 | 94 | await interaction.editReply({ 95 | content: `تم إنشاء التذكرة! يرجى التحقق من ${ticketChannel}`, 96 | ephemeral: true, 97 | }); 98 | } catch (error) { 99 | console.error("Error creating a ticket channel:", error); 100 | await interaction.editReply({ 101 | content: "حدث خطأ أثناء إنشاء التذكرة!", 102 | ephemeral: true, 103 | }); 104 | } 105 | }, 106 | }; 107 | -------------------------------------------------------------------------------- /src/interactions/deleteTicket.js: -------------------------------------------------------------------------------- 1 | const { ButtonInteraction } = require('discord.js'); 2 | 3 | module.exports = { 4 | name: 'delete_ticket', 5 | /** 6 | * @param {ButtonInteraction} interaction 7 | */ 8 | async execute(client, config, interaction) { 9 | try { 10 | // Confirm deletion with a response 11 | await interaction.reply({ content: '**سيتم حذف التذكرة خلال 5 ثواني**', ephemeral: true }); 12 | 13 | // Delete the ticket channel after a short delay (optional) 14 | setTimeout(() => interaction.channel.delete(), 5000); // 5-second delay before deletion 15 | } catch (error) { 16 | await interaction.editReply({ content: 'حدث خطأ أثناء حذف التذكرة!', ephemeral: true }); 17 | } 18 | }, 19 | }; 20 | --------------------------------------------------------------------------------