feat: mise à jour du code

This commit is contained in:
UltraLionFr
2025-08-26 01:21:58 +02:00
parent 944845cd11
commit d3d3642ec3
29 changed files with 487 additions and 320 deletions
+6
View File
@@ -0,0 +1,6 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5"
}
+15 -12
View File
@@ -1,32 +1,35 @@
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js"); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName("help") .setName('help')
.setDescription("Affiche la liste des commandes disponibles"), .setDescription('Affiche la liste des commandes disponibles'),
async execute(interaction, client) { async execute(interaction, client) {
const globalCommands = await client.application.commands.fetch(); const globalCommands = await client.application.commands.fetch();
const commandList = globalCommands.map( const commandList = globalCommands
cmd => `</${cmd.name}:${cmd.id}> — ${cmd.description || "Pas de description"}` .map(
).join("\n"); (cmd) =>
`</${cmd.name}:${cmd.id}> — ${cmd.description || 'Pas de description'}`
)
.join('\n');
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
.setTitle("📖 Aide du bot") .setTitle('📖 Aide du bot')
.setDescription( .setDescription(
commandList.length > 0 commandList.length > 0
? "Voici la liste des commandes disponibles :\n\n" + commandList ? 'Voici la liste des commandes disponibles :\n\n' + commandList
: "❌ Aucune commande trouvée." : '❌ Aucune commande trouvée.'
) )
.setColor(0x5e99ff) .setColor(0x5e99ff)
.setThumbnail(client.user.displayAvatarURL()) .setThumbnail(client.user.displayAvatarURL())
.setFooter({ .setFooter({
text: `QuantumCraft Studios • Demandé par ${interaction.user.tag}`, text: `QuantumCraft Studios • Demandé par ${interaction.user.tag}`,
iconURL: interaction.user.displayAvatarURL() iconURL: interaction.user.displayAvatarURL(),
}) })
.setTimestamp(); .setTimestamp();
await interaction.reply({ embeds: [embed], flags: 64 }); await interaction.reply({ embeds: [embed], flags: 64 });
} },
}; };
+6 -6
View File
@@ -1,11 +1,11 @@
const { SlashCommandBuilder } = require("discord.js"); const { SlashCommandBuilder } = require('discord.js');
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName("ping") .setName('ping')
.setDescription("Répond avec Pong !"), .setDescription('Répond avec Pong !'),
async execute(interaction) { async execute(interaction) {
await interaction.reply("🏓 Pong !"); await interaction.reply('🏓 Pong !');
} },
}; };
+30 -23
View File
@@ -1,13 +1,14 @@
const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js"); const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
const { config, lang } = require("../../handlers/configLoader"); const { config, lang } = require('../../handlers/configLoader');
const { getTicketByChannel } = require("../../handlers/database"); const { getTicketByChannel } = require('../../handlers/database');
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName("add") .setName('add')
.setDescription(lang.commands.add.description) .setDescription(lang.commands.add.description)
.addUserOption(option => .addUserOption((option) =>
option.setName("utilisateur") option
.setName('utilisateur')
.setDescription("L'utilisateur à ajouter au ticket") .setDescription("L'utilisateur à ajouter au ticket")
.setRequired(true) .setRequired(true)
), ),
@@ -15,13 +16,16 @@ module.exports = {
async execute(interaction) { async execute(interaction) {
const member = interaction.member; const member = interaction.member;
const staffRoles = (Array.isArray(config.staffRoles) ? config.staffRoles : [config.staffRole || config.staffRoles]) const staffRoles = (
.filter(r => r && r.trim() !== ""); Array.isArray(config.staffRoles)
? config.staffRoles
: [config.staffRole || config.staffRoles]
).filter((r) => r && r.trim() !== '');
if (!staffRoles.some(roleId => member.roles.cache.has(roleId))) { if (!staffRoles.some((roleId) => member.roles.cache.has(roleId))) {
return interaction.reply({ return interaction.reply({
content: lang.permissions.staff_only, content: lang.permissions.staff_only,
flags: 64 flags: 64,
}); });
} }
@@ -29,17 +33,21 @@ module.exports = {
if (!ticket) { if (!ticket) {
return interaction.reply({ return interaction.reply({
content: lang.ticket.not_in_ticket, content: lang.ticket.not_in_ticket,
flags: 64 flags: 64,
}); });
} }
const userToAdd = interaction.options.getUser("utilisateur"); const userToAdd = interaction.options.getUser('utilisateur');
const existingOverwrite = interaction.channel.permissionOverwrites.cache.get(userToAdd.id); const existingOverwrite =
if (existingOverwrite && existingOverwrite.allow.has(PermissionFlagsBits.ViewChannel)) { interaction.channel.permissionOverwrites.cache.get(userToAdd.id);
if (
existingOverwrite &&
existingOverwrite.allow.has(PermissionFlagsBits.ViewChannel)
) {
return interaction.reply({ return interaction.reply({
content: lang.commands.add.already_added.replace("{user}", userToAdd), content: lang.commands.add.already_added.replace('{user}', userToAdd),
flags: 64 flags: 64,
}); });
} }
@@ -51,20 +59,19 @@ module.exports = {
}); });
await interaction.reply({ await interaction.reply({
content: lang.commands.add.success.replace("{user}", userToAdd), content: lang.commands.add.success.replace('{user}', userToAdd),
flags: 64 flags: 64,
}); });
await interaction.channel.send( await interaction.channel.send(
lang.commands.add.welcome.replace("{user}", userToAdd) lang.commands.add.welcome.replace('{user}', userToAdd)
); );
} catch (err) { } catch (err) {
console.error(err); console.error(err);
await interaction.reply({ await interaction.reply({
content: lang.commands.add.error, content: lang.commands.add.error,
flags: 64 flags: 64,
}); });
} }
} },
}; };
+37 -25
View File
@@ -3,16 +3,16 @@ const {
EmbedBuilder, EmbedBuilder,
ButtonBuilder, ButtonBuilder,
ButtonStyle, ButtonStyle,
ActionRowBuilder ActionRowBuilder,
} = require("discord.js"); } = require('discord.js');
const { config, lang } = require("../../handlers/configLoader"); const { config, lang } = require('../../handlers/configLoader');
const { getTicketByChannel, closeTicket } = require("../../handlers/database"); const { getTicketByChannel, closeTicket } = require('../../handlers/database');
const { scheduleTicketClosure } = require("../../handlers/alertManager"); const { scheduleTicketClosure } = require('../../handlers/alertManager');
const ms = require("ms"); const ms = require('ms');
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName("alert") .setName('alert')
.setDescription(lang.commands.alert.description), .setDescription(lang.commands.alert.description),
async execute(interaction, client) { async execute(interaction, client) {
@@ -20,38 +20,42 @@ module.exports = {
if (!ticket) { if (!ticket) {
return interaction.reply({ return interaction.reply({
content: lang.ticket.not_in_ticket, content: lang.ticket.not_in_ticket,
flags: 64 flags: 64,
}); });
} }
const member = interaction.member; const member = interaction.member;
const isStaff = config.staffRoles.some(roleId => member.roles.cache.has(roleId)); const isStaff = config.staffRoles.some((roleId) =>
member.roles.cache.has(roleId)
);
if (!isStaff) { if (!isStaff) {
return interaction.reply({ return interaction.reply({
content: lang.permissions.staff_only, content: lang.permissions.staff_only,
flags: 64 flags: 64,
}); });
} }
const alertDuration = ms(config.TicketAlert.Time || "1h"); const alertDuration = ms(config.TicketAlert.Time || '1h');
const now = Date.now(); const now = Date.now();
const inactiveTime = `<t:${Math.floor(now / 1000)}:R>`; const inactiveTime = `<t:${Math.floor(now / 1000)}:R>`;
// === Boutons === // === Boutons ===
const closeBtn = new ButtonBuilder() const closeBtn = new ButtonBuilder()
.setCustomId("closeTicket") .setCustomId('closeTicket')
.setLabel(lang.commands.alert.close_now_label || "🔒 Fermer maintenant") .setLabel(lang.commands.alert.close_now_label || '🔒 Fermer maintenant')
.setStyle(ButtonStyle.Danger); .setStyle(ButtonStyle.Danger);
const cancelBtn = new ButtonBuilder() const cancelBtn = new ButtonBuilder()
.setCustomId("cancelClosure") .setCustomId('cancelClosure')
.setLabel(lang.commands.alert.cancel_label || "🚫 Annuler la fermeture") .setLabel(lang.commands.alert.cancel_label || '🚫 Annuler la fermeture')
.setStyle(ButtonStyle.Secondary); .setStyle(ButtonStyle.Secondary);
const linkBtn = new ButtonBuilder() const linkBtn = new ButtonBuilder()
.setLabel("🔗 Voir le ticket") .setLabel('🔗 Voir le ticket')
.setStyle(ButtonStyle.Link) .setStyle(ButtonStyle.Link)
.setURL(`https://discord.com/channels/${interaction.guild.id}/${interaction.channel.id}`); .setURL(
`https://discord.com/channels/${interaction.guild.id}/${interaction.channel.id}`
);
const row1 = new ActionRowBuilder().addComponents(closeBtn, cancelBtn); const row1 = new ActionRowBuilder().addComponents(closeBtn, cancelBtn);
const row2 = new ActionRowBuilder().addComponents(linkBtn); const row2 = new ActionRowBuilder().addComponents(linkBtn);
@@ -61,8 +65,11 @@ module.exports = {
.setColor(0xe67e22) .setColor(0xe67e22)
.setDescription( .setDescription(
lang.commands.alert.sent lang.commands.alert.sent
.replace("{time}", `<t:${Math.floor((now + alertDuration) / 1000)}:R>`) .replace(
.replace("{inactive-time}", inactiveTime) '{time}',
`<t:${Math.floor((now + alertDuration) / 1000)}:R>`
)
.replace('{inactive-time}', inactiveTime)
) )
.setTimestamp(); .setTimestamp();
@@ -70,21 +77,26 @@ module.exports = {
.setColor(0xe67e22) .setColor(0xe67e22)
.setDescription( .setDescription(
lang.commands.alert.sent lang.commands.alert.sent
.replace("{time}", `<t:${Math.floor((now + alertDuration) / 1000)}:R>`) .replace(
.replace("{inactive-time}", inactiveTime) '{time}',
`<t:${Math.floor((now + alertDuration) / 1000)}:R>`
)
.replace('{inactive-time}', inactiveTime)
) )
.setTimestamp(); .setTimestamp();
// === Envoi DM si activé === // === Envoi DM si activé ===
if (config.TicketAlert?.DMUser && ticket.userId) { if (config.TicketAlert?.DMUser && ticket.userId) {
const ticketCreator = await client.users.fetch(ticket.userId).catch(() => null); const ticketCreator = await client.users
.fetch(ticket.userId)
.catch(() => null);
if (ticketCreator) { if (ticketCreator) {
try { try {
await ticketCreator.send({ embeds: [dmEmbed], components: [row2] }); await ticketCreator.send({ embeds: [dmEmbed], components: [row2] });
} catch { } catch {
await interaction.reply({ await interaction.reply({
content: lang.commands.alert.dm_unreachable, content: lang.commands.alert.dm_unreachable,
flags: 64 flags: 64,
}); });
} }
} }
@@ -94,7 +106,7 @@ module.exports = {
await interaction.reply({ await interaction.reply({
content: ticket.userId ? `<@${ticket.userId}>` : null, content: ticket.userId ? `<@${ticket.userId}>` : null,
embeds: [alertEmbed], embeds: [alertEmbed],
components: [row1] components: [row1],
}); });
// === Planification de la fermeture auto === // === Planification de la fermeture auto ===
@@ -102,5 +114,5 @@ module.exports = {
closeTicket(interaction.channel.id); closeTicket(interaction.channel.id);
await interaction.channel.delete().catch(() => {}); await interaction.channel.delete().catch(() => {});
}); });
} },
}; };
+24 -11
View File
@@ -1,17 +1,24 @@
const { SlashCommandBuilder, EmbedBuilder, MessageFlags } = require("discord.js"); const {
const { getTicketByChannel, closeTicket } = require("../../handlers/database"); SlashCommandBuilder,
const { config, lang } = require("../../handlers/configLoader"); EmbedBuilder,
MessageFlags,
} = require('discord.js');
const { getTicketByChannel, closeTicket } = require('../../handlers/database');
const { config, lang } = require('../../handlers/configLoader');
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName("close") .setName('close')
.setDescription("Fermer un ticket"), .setDescription('Fermer un ticket'),
async execute(interaction) { async execute(interaction) {
const ticket = getTicketByChannel(interaction.channel.id); const ticket = getTicketByChannel(interaction.channel.id);
if (!ticket) { if (!ticket) {
return interaction.reply({ content: lang.ticket.not_in_ticket, flags: MessageFlags.Ephemeral }); return interaction.reply({
content: lang.ticket.not_in_ticket,
flags: MessageFlags.Ephemeral,
});
} }
closeTicket(interaction.channel.id); closeTicket(interaction.channel.id);
@@ -19,13 +26,19 @@ module.exports = {
await interaction.reply(lang.ticket.closing); await interaction.reply(lang.ticket.closing);
// Log fermeture // Log fermeture
const logChannel = await interaction.client.channels.fetch(config.logsChannel).catch(() => null); const logChannel = await interaction.client.channels
.fetch(config.logsChannel)
.catch(() => null);
if (logChannel) { if (logChannel) {
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
.setTitle("🔒 Ticket fermé") .setTitle('🔒 Ticket fermé')
.addFields( .addFields(
{ name: "Salon", value: `${interaction.channel.name}`, inline: true }, { name: 'Salon', value: `${interaction.channel.name}`, inline: true },
{ name: "Fermé par", value: `${interaction.user.tag} (${interaction.user.id})`, inline: true } {
name: 'Fermé par',
value: `${interaction.user.tag} (${interaction.user.id})`,
inline: true,
}
) )
.setColor(0xe74c3c) .setColor(0xe74c3c)
.setTimestamp(); .setTimestamp();
@@ -35,5 +48,5 @@ module.exports = {
setTimeout(() => { setTimeout(() => {
interaction.channel.delete().catch(() => {}); interaction.channel.delete().catch(() => {});
}, 5000); }, 5000);
} },
}; };
+33 -23
View File
@@ -1,13 +1,14 @@
const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js"); const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
const { config, lang } = require("../../handlers/configLoader"); const { config, lang } = require('../../handlers/configLoader');
const { getTicketByChannel } = require("../../handlers/database"); const { getTicketByChannel } = require('../../handlers/database');
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName("remove") .setName('remove')
.setDescription(lang.commands.remove.description) .setDescription(lang.commands.remove.description)
.addUserOption(option => .addUserOption((option) =>
option.setName("utilisateur") option
.setName('utilisateur')
.setDescription("L'utilisateur à retirer du ticket") .setDescription("L'utilisateur à retirer du ticket")
.setRequired(true) .setRequired(true)
), ),
@@ -15,13 +16,16 @@ module.exports = {
async execute(interaction) { async execute(interaction) {
const member = interaction.member; const member = interaction.member;
const staffRoles = (Array.isArray(config.staffRoles) ? config.staffRoles : [config.staffRole || config.staffRoles]) const staffRoles = (
.filter(r => r && r.trim() !== ""); Array.isArray(config.staffRoles)
? config.staffRoles
: [config.staffRole || config.staffRoles]
).filter((r) => r && r.trim() !== '');
if (!staffRoles.some(roleId => member.roles.cache.has(roleId))) { if (!staffRoles.some((roleId) => member.roles.cache.has(roleId))) {
return interaction.reply({ return interaction.reply({
content: lang.permissions.staff_only, content: lang.permissions.staff_only,
flags: 64 flags: 64,
}); });
} }
@@ -29,17 +33,24 @@ module.exports = {
if (!ticket) { if (!ticket) {
return interaction.reply({ return interaction.reply({
content: lang.ticket.not_in_ticket, content: lang.ticket.not_in_ticket,
flags: 64 flags: 64,
}); });
} }
const userToRemove = interaction.options.getUser("utilisateur"); const userToRemove = interaction.options.getUser('utilisateur');
const existingOverwrite = interaction.channel.permissionOverwrites.cache.get(userToRemove.id); const existingOverwrite =
if (!existingOverwrite || !existingOverwrite.allow.has(PermissionFlagsBits.ViewChannel)) { interaction.channel.permissionOverwrites.cache.get(userToRemove.id);
if (
!existingOverwrite ||
!existingOverwrite.allow.has(PermissionFlagsBits.ViewChannel)
) {
return interaction.reply({ return interaction.reply({
content: lang.commands.remove.not_in_ticket.replace("{user}", userToRemove), content: lang.commands.remove.not_in_ticket.replace(
flags: 64 '{user}',
userToRemove
),
flags: 64,
}); });
} }
@@ -51,20 +62,19 @@ module.exports = {
}); });
await interaction.reply({ await interaction.reply({
content: lang.commands.remove.success.replace("{user}", userToRemove), content: lang.commands.remove.success.replace('{user}', userToRemove),
flags: 64 flags: 64,
}); });
await interaction.channel.send( await interaction.channel.send(
lang.commands.remove.goodbye.replace("{user}", userToRemove) lang.commands.remove.goodbye.replace('{user}', userToRemove)
); );
} catch (err) { } catch (err) {
console.error(err); console.error(err);
await interaction.reply({ await interaction.reply({
content: lang.commands.remove.error, content: lang.commands.remove.error,
flags: 64 flags: 64,
}); });
} }
} },
}; };
+31
View File
@@ -0,0 +1,31 @@
import js from "@eslint/js";
import prettierConfig from "eslint-config-prettier";
import prettier from "eslint-plugin-prettier";
import globals from "globals";
export default [
{
ignores: ["eslint.config.mjs"],
},
js.configs.recommended,
{
files: ["**/*.{js,mjs,cjs}"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "commonjs",
globals: globals.node,
},
plugins: {
prettier,
},
rules: {
"prettier/prettier": "error",
"no-console": "off",
"no-empty-function": "off",
"no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
"prefer-const": "error",
"no-var": "error"
},
},
prettierConfig,
];
+18 -13
View File
@@ -1,23 +1,28 @@
const { REST, Routes } = require("discord.js"); const { REST, Routes } = require('discord.js');
const { getCommandsJSON } = require("../../handlers/commandHandler"); const { getCommandsJSON } = require('../../handlers/commandHandler');
const logger = require("../../handlers/logger"); const logger = require('../../handlers/logger');
module.exports = { module.exports = {
name: "clientReady", name: 'clientReady',
once: true, once: true,
async execute(client) { async execute(client) {
const commands = getCommandsJSON(); const commands = getCommandsJSON();
const rest = new REST({ version: "10" }).setToken(process.env.DISCORD_TOKEN); const rest = new REST({ version: '10' }).setToken(
process.env.DISCORD_TOKEN
);
try { try {
logger.info("⏳ Déploiement des slash commands..."); logger.info('⏳ Déploiement des slash commands...');
await rest.put( await rest.put(Routes.applicationCommands(process.env.CLIENT_ID), {
Routes.applicationCommands(process.env.CLIENT_ID), body: commands,
{ body: commands } });
logger.success(
`${commands.length} slash commands déployées avec succès !`
); );
logger.success(`${commands.length} slash commands déployées avec succès !`);
} catch (error) { } catch (error) {
logger.error(`❌ Erreur lors du déploiement des commandes : ${error.message}`); logger.error(
`❌ Erreur lors du déploiement des commandes : ${error.message}`
);
} }
} },
}; };
+29 -24
View File
@@ -3,25 +3,25 @@ const {
ButtonBuilder, ButtonBuilder,
ButtonStyle, ButtonStyle,
EmbedBuilder, EmbedBuilder,
StringSelectMenuBuilder StringSelectMenuBuilder,
} = require("discord.js"); } = require('discord.js');
const { config } = require("../../handlers/configLoader"); const { config } = require('../../handlers/configLoader');
const logger = require("../../handlers/logger"); const logger = require('../../handlers/logger');
function parseColor(raw) { function parseColor(raw) {
if (!raw) return 0x5865F2; if (!raw) return 0x5865f2;
if (typeof raw === "number") return raw; if (typeof raw === 'number') return raw;
if (typeof raw === "string") { if (typeof raw === 'string') {
if (raw.startsWith("0x")) return parseInt(raw, 16); if (raw.startsWith('0x')) return parseInt(raw, 16);
if (raw.startsWith("#")) return parseInt(raw.slice(1), 16); if (raw.startsWith('#')) return parseInt(raw.slice(1), 16);
const asInt = parseInt(raw); const asInt = parseInt(raw);
if (!isNaN(asInt)) return asInt; if (!isNaN(asInt)) return asInt;
} }
return 0x5865F2; return 0x5865f2;
} }
module.exports = { module.exports = {
name: "clientReady", name: 'clientReady',
once: true, once: true,
async execute(client) { async execute(client) {
const panelConfig = config.TicketPanel.Panel; const panelConfig = config.TicketPanel.Panel;
@@ -32,34 +32,40 @@ module.exports = {
const channel = await client.channels.fetch(channelId).catch(() => null); const channel = await client.channels.fetch(channelId).catch(() => null);
if (!channel) { if (!channel) {
return logger.error("❌ Impossible de trouver le salon défini pour le panel de ticket."); return logger.error(
'❌ Impossible de trouver le salon défini pour le panel de ticket.'
);
} }
// === Embed principal === // === Embed principal ===
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
.setTitle(panelConfig.Embed.Title || "") .setTitle(panelConfig.Embed.Title || '')
.setDescription(panelConfig.Embed.Description || "") .setDescription(panelConfig.Embed.Description || '')
.setColor(parseColor(panelConfig.Embed.Color)); .setColor(parseColor(panelConfig.Embed.Color));
if (panelConfig.Embed.PanelImage) embed.setImage(panelConfig.Embed.PanelImage); if (panelConfig.Embed.PanelImage)
if (panelConfig.Embed.CustomThumbnailURL) embed.setThumbnail(panelConfig.Embed.CustomThumbnailURL); embed.setImage(panelConfig.Embed.PanelImage);
if (panelConfig.Embed.CustomThumbnailURL)
embed.setThumbnail(panelConfig.Embed.CustomThumbnailURL);
if (panelConfig.Embed.Timestamp) embed.setTimestamp(); if (panelConfig.Embed.Timestamp) embed.setTimestamp();
if (panelConfig.Embed.Footer && panelConfig.Embed.Footer.Enabled) { if (panelConfig.Embed.Footer && panelConfig.Embed.Footer.Enabled) {
embed.setFooter({ embed.setFooter({
text: panelConfig.Embed.Footer.Text || "", text: panelConfig.Embed.Footer.Text || '',
iconURL: panelConfig.Embed.Footer.CustomIconURL || null iconURL: panelConfig.Embed.Footer.CustomIconURL || null,
}); });
} }
let row; let row;
// === Gestion des interactions === // === Gestion des interactions ===
if (panelConfig.InteractionType === "select" && panelConfig.SelectMenu) { if (panelConfig.InteractionType === 'select' && panelConfig.SelectMenu) {
// 📌 Mode Select Menu // 📌 Mode Select Menu
const menu = new StringSelectMenuBuilder() const menu = new StringSelectMenuBuilder()
.setCustomId("ticket_select") .setCustomId('ticket_select')
.setPlaceholder(panelConfig.SelectMenu.Placeholder || "Choisis une option..."); .setPlaceholder(
panelConfig.SelectMenu.Placeholder || 'Choisis une option...'
);
for (const opt of panelConfig.SelectMenu.Options) { for (const opt of panelConfig.SelectMenu.Options) {
const option = { const option = {
@@ -74,7 +80,6 @@ module.exports = {
} }
row = new ActionRowBuilder().addComponents(menu); row = new ActionRowBuilder().addComponents(menu);
} else { } else {
// 📌 Mode Boutons par défaut // 📌 Mode Boutons par défaut
row = new ActionRowBuilder(); row = new ActionRowBuilder();
@@ -95,5 +100,5 @@ module.exports = {
await channel.send({ embeds: [embed], components: [row] }); await channel.send({ embeds: [embed], components: [row] });
logger.success(`✅ Panel "${panelConfig.Name}" envoyé avec succès !`); logger.success(`✅ Panel "${panelConfig.Name}" envoyé avec succès !`);
} },
}; };
+4 -4
View File
@@ -1,9 +1,9 @@
const logger = require("../../handlers/logger"); const logger = require('../../handlers/logger');
module.exports = { module.exports = {
name: "clientReady", name: 'clientReady',
once: true, once: true,
execute(client) { execute(client) {
logger.success(`Connecté en tant que ${client.user.tag}`); logger.success(`Connecté en tant que ${client.user.tag}`);
} },
}; };
+28 -10
View File
@@ -1,5 +1,5 @@
module.exports = { module.exports = {
name: "interactionCreate", name: 'interactionCreate',
once: false, once: false,
async execute(interaction, client) { async execute(interaction, client) {
try { try {
@@ -12,10 +12,16 @@ module.exports = {
// Buttons // Buttons
if (interaction.isButton()) { if (interaction.isButton()) {
for (const button of client.buttons.values()) { for (const button of client.buttons.values()) {
if (typeof button.id === "string" && button.id === interaction.customId) { if (
typeof button.id === 'string' &&
button.id === interaction.customId
) {
return button.execute(interaction, client); return button.execute(interaction, client);
} }
if (button.id instanceof RegExp && button.id.test(interaction.customId)) { if (
button.id instanceof RegExp &&
button.id.test(interaction.customId)
) {
return button.execute(interaction, client); return button.execute(interaction, client);
} }
} }
@@ -24,10 +30,16 @@ module.exports = {
// Modals // Modals
if (interaction.isModalSubmit()) { if (interaction.isModalSubmit()) {
for (const modal of client.modals.values()) { for (const modal of client.modals.values()) {
if (typeof modal.id === "string" && modal.id === interaction.customId) { if (
typeof modal.id === 'string' &&
modal.id === interaction.customId
) {
return modal.execute(interaction, client); return modal.execute(interaction, client);
} }
if (modal.id instanceof RegExp && modal.id.test(interaction.customId)) { if (
modal.id instanceof RegExp &&
modal.id.test(interaction.customId)
) {
return modal.execute(interaction, client); return modal.execute(interaction, client);
} }
} }
@@ -41,7 +53,7 @@ module.exports = {
interaction.isChannelSelectMenu() interaction.isChannelSelectMenu()
) { ) {
for (const menu of client.menus.values()) { for (const menu of client.menus.values()) {
if (typeof menu.id === "string" && menu.id === interaction.customId) { if (typeof menu.id === 'string' && menu.id === interaction.customId) {
return menu.execute(interaction, client); return menu.execute(interaction, client);
} }
if (menu.id instanceof RegExp && menu.id.test(interaction.customId)) { if (menu.id instanceof RegExp && menu.id.test(interaction.customId)) {
@@ -52,10 +64,16 @@ module.exports = {
} catch (error) { } catch (error) {
console.error(error); console.error(error);
if (interaction.replied || interaction.deferred) { if (interaction.replied || interaction.deferred) {
await interaction.followUp({ content: "❌ Une erreur est survenue.", flags: 64 }); await interaction.followUp({
content: '❌ Une erreur est survenue.',
flags: 64,
});
} else { } else {
await interaction.reply({ content: "❌ Une erreur est survenue.", flags: 64 }); await interaction.reply({
content: '❌ Une erreur est survenue.',
flags: 64,
});
} }
} }
} },
}; };
+6 -6
View File
@@ -1,10 +1,10 @@
const { getTicketByChannel } = require("../../handlers/database"); const { getTicketByChannel } = require('../../handlers/database');
const { cancelTicketClosure } = require("../../handlers/alertManager"); const { cancelTicketClosure } = require('../../handlers/alertManager');
const { lang } = require("../../handlers/configLoader"); const { lang } = require('../../handlers/configLoader');
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require('discord.js');
module.exports = { module.exports = {
name: "messageCreate", name: 'messageCreate',
once: false, once: false,
async execute(message) { async execute(message) {
if (message.author.bot) return; if (message.author.bot) return;
@@ -22,5 +22,5 @@ module.exports = {
await message.channel.send({ embeds: [embed] }); await message.channel.send({ embeds: [embed] });
} }
} }
} },
}; };
+1 -2
View File
@@ -1,6 +1,5 @@
const activeAlerts = new Map(); const activeAlerts = new Map();
function scheduleTicketClosure(channel, duration, closeFn) { function scheduleTicketClosure(channel, duration, closeFn) {
if (activeAlerts.has(channel.id)) { if (activeAlerts.has(channel.id)) {
clearTimeout(activeAlerts.get(channel.id)); clearTimeout(activeAlerts.get(channel.id));
@@ -24,4 +23,4 @@ function cancelTicketClosure(channelId) {
return false; return false;
} }
module.exports = { scheduleTicketClosure, cancelTicketClosure }; module.exports = { scheduleTicketClosure, cancelTicketClosure };
+8 -6
View File
@@ -1,14 +1,16 @@
const fs = require("fs"); const fs = require('fs');
const path = require("path"); const path = require('path');
const { Collection } = require("discord.js"); const { Collection } = require('discord.js');
function loadButtons(client) { function loadButtons(client) {
const interactionsPath = path.join(__dirname, "../interactions"); const interactionsPath = path.join(__dirname, '../interactions');
client.buttons = new Collection(); client.buttons = new Collection();
if (!fs.existsSync(interactionsPath)) return client.buttons; if (!fs.existsSync(interactionsPath)) return client.buttons;
const files = fs.readdirSync(interactionsPath).filter(f => f.endsWith(".js")); const files = fs
.readdirSync(interactionsPath)
.filter((f) => f.endsWith('.js'));
for (const file of files) { for (const file of files) {
const button = require(path.join(interactionsPath, file)); const button = require(path.join(interactionsPath, file));
@@ -33,4 +35,4 @@ async function handleButton(interaction, client) {
} }
} }
module.exports = { loadButtons, handleButton }; module.exports = { loadButtons, handleButton };
+7 -7
View File
@@ -1,6 +1,6 @@
const fs = require("fs"); const fs = require('fs');
const path = require("path"); const path = require('path');
const { Collection } = require("discord.js"); const { Collection } = require('discord.js');
function walkCommands(dir, callback) { function walkCommands(dir, callback) {
const files = fs.readdirSync(dir, { withFileTypes: true }); const files = fs.readdirSync(dir, { withFileTypes: true });
@@ -10,7 +10,7 @@ function walkCommands(dir, callback) {
if (file.isDirectory()) { if (file.isDirectory()) {
walkCommands(filePath, callback); walkCommands(filePath, callback);
} else if (file.name.endsWith(".js")) { } else if (file.name.endsWith('.js')) {
const command = require(filePath); const command = require(filePath);
callback(command); callback(command);
} }
@@ -18,7 +18,7 @@ function walkCommands(dir, callback) {
} }
function loadCommands(client) { function loadCommands(client) {
const commandsPath = path.join(__dirname, "../SlashCommand"); const commandsPath = path.join(__dirname, '../SlashCommand');
client.commands = new Collection(); client.commands = new Collection();
walkCommands(commandsPath, (command) => { walkCommands(commandsPath, (command) => {
@@ -29,7 +29,7 @@ function loadCommands(client) {
} }
function getCommandsJSON() { function getCommandsJSON() {
const commandsPath = path.join(__dirname, "../SlashCommand"); const commandsPath = path.join(__dirname, '../SlashCommand');
const commands = []; const commands = [];
walkCommands(commandsPath, (command) => { walkCommands(commandsPath, (command) => {
@@ -39,4 +39,4 @@ function getCommandsJSON() {
return commands; return commands;
} }
module.exports = { loadCommands, getCommandsJSON }; module.exports = { loadCommands, getCommandsJSON };
+8 -8
View File
@@ -1,14 +1,14 @@
const fs = require("fs"); const fs = require('fs');
const path = require("path"); const path = require('path');
const YAML = require("yaml"); const YAML = require('yaml');
function loadYAML(file) { function loadYAML(file) {
const filePath = path.join(__dirname, "..", file); const filePath = path.join(__dirname, '..', file);
const content = fs.readFileSync(filePath, "utf8"); const content = fs.readFileSync(filePath, 'utf8');
return YAML.parse(content); return YAML.parse(content);
} }
const config = loadYAML("config.yml"); const config = loadYAML('config.yml');
const lang = loadYAML("lang.yml"); const lang = loadYAML('lang.yml');
module.exports = { config, lang }; module.exports = { config, lang };
+5 -5
View File
@@ -1,8 +1,8 @@
const fs = require("fs"); const fs = require('fs');
const path = require("path"); const path = require('path');
const initSqlJs = require("sql.js"); const initSqlJs = require('sql.js');
const dbPath = path.join(__dirname, "../tickets.db"); const dbPath = path.join(__dirname, '../tickets.db');
let db; let db;
@@ -56,4 +56,4 @@ function closeTicket(channelId) {
saveDB(); saveDB();
} }
module.exports = { initDB, createTicket, getTicketByChannel, closeTicket }; module.exports = { initDB, createTicket, getTicketByChannel, closeTicket };
+5 -5
View File
@@ -1,8 +1,8 @@
const fs = require("fs"); const fs = require('fs');
const path = require("path"); const path = require('path');
function loadEvents(client) { function loadEvents(client) {
const eventsPath = path.join(__dirname, "../events"); const eventsPath = path.join(__dirname, '../events');
function walk(dir) { function walk(dir) {
const files = fs.readdirSync(dir, { withFileTypes: true }); const files = fs.readdirSync(dir, { withFileTypes: true });
@@ -12,7 +12,7 @@ function loadEvents(client) {
if (file.isDirectory()) { if (file.isDirectory()) {
walk(filePath); walk(filePath);
} else if (file.name.endsWith(".js")) { } else if (file.name.endsWith('.js')) {
const event = require(filePath); const event = require(filePath);
if (event.once) { if (event.once) {
@@ -27,4 +27,4 @@ function loadEvents(client) {
walk(eventsPath); walk(eventsPath);
} }
module.exports = { loadEvents }; module.exports = { loadEvents };
+10 -10
View File
@@ -1,27 +1,27 @@
const chalk = require("chalk"); const chalk = require('chalk');
function timestamp() { function timestamp() {
return chalk.gray(`[${new Date().toLocaleTimeString("fr-FR")}]`); return chalk.gray(`[${new Date().toLocaleTimeString('fr-FR')}]`);
} }
const logger = { const logger = {
info: (msg) => { info: (msg) => {
console.log(`${timestamp()} ${chalk.blue("[INFO]")} ${msg}`); console.log(`${timestamp()} ${chalk.blue('[INFO]')} ${msg}`);
}, },
success: (msg) => { success: (msg) => {
console.log(`${timestamp()} ${chalk.green("[SUCCESS]")} ${msg}`); console.log(`${timestamp()} ${chalk.green('[SUCCESS]')} ${msg}`);
}, },
warn: (msg) => { warn: (msg) => {
console.warn(`${timestamp()} ${chalk.yellow("[WARN]")} ${msg}`); console.warn(`${timestamp()} ${chalk.yellow('[WARN]')} ${msg}`);
}, },
error: (msg) => { error: (msg) => {
console.error(`${timestamp()} ${chalk.red("[ERROR]")} ${msg}`); console.error(`${timestamp()} ${chalk.red('[ERROR]')} ${msg}`);
}, },
debug: (msg) => { debug: (msg) => {
if (process.env.DEBUG === "true") { if (process.env.DEBUG === 'true') {
console.log(`${timestamp()} ${chalk.magenta("[DEBUG]")} ${msg}`); console.log(`${timestamp()} ${chalk.magenta('[DEBUG]')} ${msg}`);
} }
} },
}; };
module.exports = logger; module.exports = logger;
+9 -7
View File
@@ -1,14 +1,16 @@
const fs = require("fs"); const fs = require('fs');
const path = require("path"); const path = require('path');
const { Collection } = require("discord.js"); const { Collection } = require('discord.js');
function loadMenus(client) { function loadMenus(client) {
const interactionsPath = path.join(__dirname, "../interactions"); const interactionsPath = path.join(__dirname, '../interactions');
client.menus = new Collection(); client.menus = new Collection();
if (!fs.existsSync(interactionsPath)) return client.menus; if (!fs.existsSync(interactionsPath)) return client.menus;
const files = fs.readdirSync(interactionsPath).filter(f => f.toLowerCase().includes("menu") && f.endsWith(".js")); const files = fs
.readdirSync(interactionsPath)
.filter((f) => f.toLowerCase().includes('menu') && f.endsWith('.js'));
for (const file of files) { for (const file of files) {
const menu = require(path.join(interactionsPath, file)); const menu = require(path.join(interactionsPath, file));
@@ -20,7 +22,7 @@ function loadMenus(client) {
async function handleMenu(interaction, client) { async function handleMenu(interaction, client) {
for (const menu of client.menus.values()) { for (const menu of client.menus.values()) {
if (typeof menu.id === "string" && menu.id === interaction.customId) { if (typeof menu.id === 'string' && menu.id === interaction.customId) {
return menu.execute(interaction, client); return menu.execute(interaction, client);
} }
if (menu.id instanceof RegExp && menu.id.test(interaction.customId)) { if (menu.id instanceof RegExp && menu.id.test(interaction.customId)) {
@@ -29,4 +31,4 @@ async function handleMenu(interaction, client) {
} }
} }
module.exports = { loadMenus, handleMenu }; module.exports = { loadMenus, handleMenu };
+9 -7
View File
@@ -1,13 +1,15 @@
const fs = require("fs"); const fs = require('fs');
const path = require("path"); const path = require('path');
const { Collection } = require("discord.js"); const { Collection } = require('discord.js');
const { config } = require("./configLoader"); const { config } = require('./configLoader');
function loadModals(client) { function loadModals(client) {
const interactionsPath = path.join(__dirname, "../interactions"); const interactionsPath = path.join(__dirname, '../interactions');
client.modals = new Collection(); client.modals = new Collection();
const files = fs.readdirSync(interactionsPath).filter(f => f.toLowerCase().includes("modal") && f.endsWith(".js")); const files = fs
.readdirSync(interactionsPath)
.filter((f) => f.toLowerCase().includes('modal') && f.endsWith('.js'));
for (const file of files) { for (const file of files) {
const modal = require(path.join(interactionsPath, file)); const modal = require(path.join(interactionsPath, file));
@@ -21,4 +23,4 @@ function getModal(customId) {
return config.TicketPanel?.Modals?.[customId] || null; return config.TicketPanel?.Modals?.[customId] || null;
} }
module.exports = { loadModals, getModal }; module.exports = { loadModals, getModal };
+29 -15
View File
@@ -1,24 +1,38 @@
const env = require("@dotenvx/dotenvx").config(); const env = require('@dotenvx/dotenvx').config();
const { Client, GatewayIntentBits } = require("discord.js"); const { Client, GatewayIntentBits } = require('discord.js');
const { loadEvents } = require("./handlers/eventHandler"); const { loadEvents } = require('./handlers/eventHandler');
const { loadCommands } = require("./handlers/commandHandler"); const { loadCommands } = require('./handlers/commandHandler');
const { loadButtons } = require("./handlers/buttonHandler"); const { loadButtons } = require('./handlers/buttonHandler');
const { loadModals } = require("./handlers/modalHandler"); const { loadModals } = require('./handlers/modalHandler');
const { loadMenus } = require("./handlers/menuHandler"); const { loadMenus } = require('./handlers/menuHandler');
const { initDB } = require("./handlers/database"); const { initDB } = require('./handlers/database');
const logger = require("./handlers/logger"); const logger = require('./handlers/logger');
const chalk = require("chalk"); const chalk = require('chalk');
const count = Object.keys(env.parsed || {}).length; const count = Object.keys(env.parsed || {}).length;
const keys = Object.keys(env.parsed || {}).join(", "); const keys = Object.keys(env.parsed || {}).join(', ');
const colors = [chalk.red, chalk.green, chalk.yellow, chalk.blue, chalk.magenta, chalk.cyan, chalk.white]; const colors = [
const coloredKeys = Object.keys(env.parsed || {}).map((key, i) => colors[i % colors.length](key)).join(", "); chalk.red,
chalk.green,
chalk.yellow,
chalk.blue,
chalk.magenta,
chalk.cyan,
chalk.white,
];
const coloredKeys = Object.keys(env.parsed || {})
.map((key, i) => colors[i % colors.length](key))
.join(', ');
logger.success(`🚀 ${process.env.BOT_START_MESSAGE}`); logger.success(`🚀 ${process.env.BOT_START_MESSAGE}`);
logger.info(`🔑 Variables .env détectées (${count}) : ${coloredKeys}`); logger.info(`🔑 Variables .env détectées (${count}) : ${coloredKeys}`);
const client = new Client({ const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
}); });
loadEvents(client); loadEvents(client);
@@ -35,4 +49,4 @@ loadMenus(client);
logger.error(`Erreur au démarrage : ${error.message}`); logger.error(`Erreur au démarrage : ${error.message}`);
process.exit(1); process.exit(1);
} }
})(); })();
+8 -6
View File
@@ -1,21 +1,23 @@
const { config, lang } = require("../handlers/configLoader"); const { config, lang } = require('../handlers/configLoader');
module.exports = { module.exports = {
id: "cancelClosure", id: 'cancelClosure',
async execute(interaction) { async execute(interaction) {
const member = interaction.member; const member = interaction.member;
const isStaff = config.staffRoles.some(roleId => member.roles.cache.has(roleId)); const isStaff = config.staffRoles.some((roleId) =>
member.roles.cache.has(roleId)
);
if (!isStaff) { if (!isStaff) {
return interaction.reply({ return interaction.reply({
content: lang.permissions.staff_only, content: lang.permissions.staff_only,
flags: 64 flags: 64,
}); });
} }
await interaction.reply({ await interaction.reply({
content: lang.commands.alert.cancelled, content: lang.commands.alert.cancelled,
flags: 64 flags: 64,
}); });
} },
}; };
+12 -7
View File
@@ -1,15 +1,20 @@
const { PermissionFlagsBits } = require("discord.js"); const { PermissionFlagsBits } = require('discord.js');
const { closeTicket } = require("../handlers/database"); const { closeTicket } = require('../handlers/database');
const { config, lang } = require("../handlers/configLoader"); const { config, lang } = require('../handlers/configLoader');
module.exports = { module.exports = {
id: "closeTicket", id: 'closeTicket',
async execute(interaction) { async execute(interaction) {
const member = interaction.member; const member = interaction.member;
const isStaff = member.roles.cache.some(role => config.staffRoles.includes(role.id)); const isStaff = member.roles.cache.some((role) =>
config.staffRoles.includes(role.id)
);
if (!isStaff) { if (!isStaff) {
return interaction.reply({ content: lang.permissions.staff_only, flags: 64 }); return interaction.reply({
content: lang.permissions.staff_only,
flags: 64,
});
} }
const channel = interaction.channel; const channel = interaction.channel;
@@ -20,5 +25,5 @@ module.exports = {
closeTicket(channel.id); closeTicket(channel.id);
await channel.delete().catch(() => {}); await channel.delete().catch(() => {});
}, 5000); }, 5000);
} },
}; };
+30 -24
View File
@@ -4,26 +4,28 @@ const {
TextInputStyle, TextInputStyle,
ActionRowBuilder, ActionRowBuilder,
PermissionFlagsBits, PermissionFlagsBits,
EmbedBuilder EmbedBuilder,
} = require("discord.js"); } = require('discord.js');
const { getModal } = require("../handlers/modalHandler"); const { getModal } = require('../handlers/modalHandler');
const { createTicket } = require("../handlers/database"); const { createTicket } = require('../handlers/database');
const { config } = require("../handlers/configLoader"); const { config } = require('../handlers/configLoader');
module.exports = { module.exports = {
id: /^ticket_.+$/, id: /^ticket_.+$/,
async execute(interaction, client) { async execute(interaction, client) {
const modalConfig = getModal(interaction.customId); const modalConfig = getModal(interaction.customId);
const staffRoles = (Array.isArray(config.staffRoles) ? config.staffRoles : [config.staffRoles]) const staffRoles = (
.filter(r => r && r.trim() !== ""); Array.isArray(config.staffRoles) ? config.staffRoles : [config.staffRoles]
).filter((r) => r && r.trim() !== '');
if (!modalConfig || modalConfig.Enabled === false) { if (!modalConfig || modalConfig.Enabled === false) {
const guild = interaction.guild; const guild = interaction.guild;
const member = interaction.member; const member = interaction.member;
const categories = config.TicketPanel.Panel.Categories; const categories = config.TicketPanel.Panel.Categories;
const parentCategory = categories && categories.length > 0 ? categories[0] : null; const parentCategory =
categories && categories.length > 0 ? categories[0] : null;
const overwrites = [ const overwrites = [
{ id: guild.id, deny: [PermissionFlagsBits.ViewChannel] }, { id: guild.id, deny: [PermissionFlagsBits.ViewChannel] },
@@ -32,9 +34,9 @@ module.exports = {
allow: [ allow: [
PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ViewChannel,
PermissionFlagsBits.SendMessages, PermissionFlagsBits.SendMessages,
PermissionFlagsBits.ReadMessageHistory PermissionFlagsBits.ReadMessageHistory,
] ],
} },
]; ];
for (const roleId of staffRoles) { for (const roleId of staffRoles) {
@@ -43,8 +45,8 @@ module.exports = {
allow: [ allow: [
PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ViewChannel,
PermissionFlagsBits.SendMessages, PermissionFlagsBits.SendMessages,
PermissionFlagsBits.ReadMessageHistory PermissionFlagsBits.ReadMessageHistory,
] ],
}); });
} }
@@ -52,25 +54,29 @@ module.exports = {
name: `ticket-${member.user.username}`.toLowerCase(), name: `ticket-${member.user.username}`.toLowerCase(),
type: 0, type: 0,
parent: parentCategory || undefined, parent: parentCategory || undefined,
permissionOverwrites: overwrites permissionOverwrites: overwrites,
}); });
createTicket(member.id, channel.id); createTicket(member.id, channel.id);
await interaction.reply({ await interaction.reply({
content: `✅ Ton ticket a été créé : ${channel}`, content: `✅ Ton ticket a été créé : ${channel}`,
flags: 64 flags: 64,
}); });
await channel.send(`🎟️ Bonjour ${member}, un membre du staff va bientôt te répondre.`); await channel.send(
`🎟️ Bonjour ${member}, un membre du staff va bientôt te répondre.`
);
const logChannel = await client.channels.fetch(config.logsChannel).catch(() => null); const logChannel = await client.channels
.fetch(config.logsChannel)
.catch(() => null);
if (logChannel) { if (logChannel) {
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
.setTitle("🎟️ Nouveau ticket (sans formulaire)") .setTitle('🎟️ Nouveau ticket (sans formulaire)')
.addFields( .addFields(
{ name: "Utilisateur", value: `${member.user.tag} (${member.id})` }, { name: 'Utilisateur', value: `${member.user.tag} (${member.id})` },
{ name: "Salon", value: `${channel}` } { name: 'Salon', value: `${channel}` }
) )
.setColor(0x2ecc71) .setColor(0x2ecc71)
.setTimestamp(); .setTimestamp();
@@ -83,9 +89,9 @@ module.exports = {
const modal = new ModalBuilder() const modal = new ModalBuilder()
.setCustomId(`ticket_modal_${interaction.customId}`) .setCustomId(`ticket_modal_${interaction.customId}`)
.setTitle(modalConfig.Title || "Création de ticket"); .setTitle(modalConfig.Title || 'Création de ticket');
modalConfig.Inputs.forEach(input => { modalConfig.Inputs.forEach((input) => {
const textInput = new TextInputBuilder() const textInput = new TextInputBuilder()
.setCustomId(input.CustomId) .setCustomId(input.CustomId)
.setLabel(input.Label) .setLabel(input.Label)
@@ -96,5 +102,5 @@ module.exports = {
}); });
await interaction.showModal(modal); await interaction.showModal(modal);
} },
}; };
+36 -24
View File
@@ -1,10 +1,17 @@
const { ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder, PermissionFlagsBits, EmbedBuilder } = require("discord.js"); const {
const { getModal } = require("../handlers/modalHandler"); ModalBuilder,
const { createTicket } = require("../handlers/database"); TextInputBuilder,
const { config } = require("../handlers/configLoader"); TextInputStyle,
ActionRowBuilder,
PermissionFlagsBits,
EmbedBuilder,
} = require('discord.js');
const { getModal } = require('../handlers/modalHandler');
const { createTicket } = require('../handlers/database');
const { config } = require('../handlers/configLoader');
module.exports = { module.exports = {
id: "ticket_select", id: 'ticket_select',
async execute(interaction, client) { async execute(interaction, client) {
const selected = interaction.values[0]; const selected = interaction.values[0];
const modalConfig = getModal(selected); const modalConfig = getModal(selected);
@@ -14,7 +21,8 @@ module.exports = {
const member = interaction.member; const member = interaction.member;
const categories = config.TicketPanel.Panel.Categories; const categories = config.TicketPanel.Panel.Categories;
const parentCategory = categories && categories.length > 0 ? categories[0] : null; const parentCategory =
categories && categories.length > 0 ? categories[0] : null;
const channel = await guild.channels.create({ const channel = await guild.channels.create({
name: `ticket-${member.user.username}`.toLowerCase(), name: `ticket-${member.user.username}`.toLowerCase(),
@@ -27,37 +35,41 @@ module.exports = {
allow: [ allow: [
PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ViewChannel,
PermissionFlagsBits.SendMessages, PermissionFlagsBits.SendMessages,
PermissionFlagsBits.ReadMessageHistory PermissionFlagsBits.ReadMessageHistory,
] ],
}, },
...config.staffRoles.map(roleId => ({ ...config.staffRoles.map((roleId) => ({
id: roleId, id: roleId,
allow: [ allow: [
PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ViewChannel,
PermissionFlagsBits.SendMessages, PermissionFlagsBits.SendMessages,
PermissionFlagsBits.ReadMessageHistory PermissionFlagsBits.ReadMessageHistory,
] ],
})) })),
] ],
}); });
createTicket(member.id, channel.id); createTicket(member.id, channel.id);
await interaction.reply({ await interaction.reply({
content: `✅ Ton ticket a été créé : ${channel}`, content: `✅ Ton ticket a été créé : ${channel}`,
flags: 64 flags: 64,
}); });
await channel.send(`🎟️ Bonjour ${member}, un membre du staff va bientôt te répondre.`); await channel.send(
`🎟️ Bonjour ${member}, un membre du staff va bientôt te répondre.`
);
const logChannel = await client.channels.fetch(config.logsChannel).catch(() => null); const logChannel = await client.channels
.fetch(config.logsChannel)
.catch(() => null);
if (logChannel) { if (logChannel) {
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
.setTitle("🎟️ Nouveau ticket (sans formulaire - via SelectMenu)") .setTitle('🎟️ Nouveau ticket (sans formulaire - via SelectMenu)')
.addFields( .addFields(
{ name: "Utilisateur", value: `${member.user.tag} (${member.id})` }, { name: 'Utilisateur', value: `${member.user.tag} (${member.id})` },
{ name: "Salon", value: `${channel}` }, { name: 'Salon', value: `${channel}` },
{ name: "Type de ticket", value: selected } { name: 'Type de ticket', value: selected }
) )
.setColor(0x2ecc71) .setColor(0x2ecc71)
.setTimestamp(); .setTimestamp();
@@ -70,9 +82,9 @@ module.exports = {
const modal = new ModalBuilder() const modal = new ModalBuilder()
.setCustomId(`ticket_modal_${selected}`) .setCustomId(`ticket_modal_${selected}`)
.setTitle(modalConfig.Title || "Création de ticket"); .setTitle(modalConfig.Title || 'Création de ticket');
modalConfig.Inputs.forEach(input => { modalConfig.Inputs.forEach((input) => {
const textInput = new TextInputBuilder() const textInput = new TextInputBuilder()
.setCustomId(input.CustomId) .setCustomId(input.CustomId)
.setLabel(input.Label) .setLabel(input.Label)
@@ -83,5 +95,5 @@ module.exports = {
}); });
await interaction.showModal(modal); await interaction.showModal(modal);
} },
}; };
+32 -28
View File
@@ -1,17 +1,17 @@
const { EmbedBuilder, PermissionFlagsBits } = require("discord.js"); const { EmbedBuilder, PermissionFlagsBits } = require('discord.js');
const { createTicket } = require("../handlers/database"); const { createTicket } = require('../handlers/database');
const { config } = require("../handlers/configLoader"); const { config } = require('../handlers/configLoader');
module.exports = { module.exports = {
id: /^ticket_modal_.+$/, id: /^ticket_modal_.+$/,
async execute(interaction, client) { async execute(interaction, client) {
const originalId = interaction.customId.replace("ticket_modal_", ""); const originalId = interaction.customId.replace('ticket_modal_', '');
const modalConfig = config.TicketPanel?.Modals?.[originalId]; const modalConfig = config.TicketPanel?.Modals?.[originalId];
if (!modalConfig) { if (!modalConfig) {
return interaction.reply({ return interaction.reply({
content: "❌ Aucun formulaire configuré pour ce ticket.", content: '❌ Aucun formulaire configuré pour ce ticket.',
flags: 64 flags: 64,
}); });
} }
@@ -19,10 +19,12 @@ module.exports = {
const guild = interaction.guild; const guild = interaction.guild;
const categories = config.TicketPanel.Panel.Categories; const categories = config.TicketPanel.Panel.Categories;
const parentCategory = categories && categories.length > 0 ? categories[0] : null; const parentCategory =
categories && categories.length > 0 ? categories[0] : null;
const staffRoles = (Array.isArray(config.staffRoles) ? config.staffRoles : [config.staffRoles]) const staffRoles = (
.filter(r => r && r.trim() !== ""); Array.isArray(config.staffRoles) ? config.staffRoles : [config.staffRoles]
).filter((r) => r && r.trim() !== '');
const overwrites = [ const overwrites = [
{ id: guild.id, deny: [PermissionFlagsBits.ViewChannel] }, { id: guild.id, deny: [PermissionFlagsBits.ViewChannel] },
@@ -31,9 +33,9 @@ module.exports = {
allow: [ allow: [
PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ViewChannel,
PermissionFlagsBits.SendMessages, PermissionFlagsBits.SendMessages,
PermissionFlagsBits.ReadMessageHistory PermissionFlagsBits.ReadMessageHistory,
] ],
} },
]; ];
for (const roleId of staffRoles) { for (const roleId of staffRoles) {
@@ -42,8 +44,8 @@ module.exports = {
allow: [ allow: [
PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ViewChannel,
PermissionFlagsBits.SendMessages, PermissionFlagsBits.SendMessages,
PermissionFlagsBits.ReadMessageHistory PermissionFlagsBits.ReadMessageHistory,
] ],
}); });
} }
@@ -51,46 +53,48 @@ module.exports = {
name: `ticket-${member.user.username}`.toLowerCase(), name: `ticket-${member.user.username}`.toLowerCase(),
type: 0, type: 0,
parent: parentCategory || undefined, parent: parentCategory || undefined,
permissionOverwrites: overwrites permissionOverwrites: overwrites,
}); });
createTicket(member.id, channel.id); createTicket(member.id, channel.id);
const fieldsOutput = modalConfig.Inputs.map(input => { const fieldsOutput = modalConfig.Inputs.map((input) => {
const value = interaction.fields.getTextInputValue(input.CustomId); const value = interaction.fields.getTextInputValue(input.CustomId);
return `**${input.Label}** : ${value}`; return `**${input.Label}** : ${value}`;
}).join("\n"); }).join('\n');
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
.setTitle(`🎟️ ${modalConfig.Title || "Nouveau ticket"}`) .setTitle(`🎟️ ${modalConfig.Title || 'Nouveau ticket'}`)
.setDescription(`👤 Ouvert par: ${member}\n\n${fieldsOutput}`) .setDescription(`👤 Ouvert par: ${member}\n\n${fieldsOutput}`)
.setColor(0x5e99ff) .setColor(0x5e99ff)
.setTimestamp(); .setTimestamp();
await channel.send({ await channel.send({
content: staffRoles.map(r => `<@&${r}>`).join(" "), content: staffRoles.map((r) => `<@&${r}>`).join(' '),
embeds: [embed] embeds: [embed],
}); });
await interaction.reply({ await interaction.reply({
content: `✅ Ton ticket a été créé : ${channel}`, content: `✅ Ton ticket a été créé : ${channel}`,
flags: 64 flags: 64,
}); });
const logChannel = await client.channels.fetch(config.logsChannel).catch(() => null); const logChannel = await client.channels
.fetch(config.logsChannel)
.catch(() => null);
if (logChannel) { if (logChannel) {
const logEmbed = new EmbedBuilder() const logEmbed = new EmbedBuilder()
.setTitle("🎟️ Nouveau ticket") .setTitle('🎟️ Nouveau ticket')
.setDescription(`Formulaire utilisé: \`${originalId}\``) .setDescription(`Formulaire utilisé: \`${originalId}\``)
.addFields( .addFields(
{ name: "Utilisateur", value: `${member.user.tag} (${member.id})` }, { name: 'Utilisateur', value: `${member.user.tag} (${member.id})` },
{ name: "Salon", value: `${channel}` }, { name: 'Salon', value: `${channel}` },
{ name: "Réponses", value: fieldsOutput } { name: 'Réponses', value: fieldsOutput }
) )
.setColor(0x2ecc71) .setColor(0x2ecc71)
.setTimestamp(); .setTimestamp();
await logChannel.send({ embeds: [logEmbed] }); await logChannel.send({ embeds: [logEmbed] });
} }
} },
}; };
+11 -2
View File
@@ -5,7 +5,10 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "node index.js", "start": "node index.js",
"dev": "nodemon index.js" "dev": "nodemon index.js",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write ."
}, },
"keywords": [], "keywords": [],
"author": "UltraLion - https://ultralion.xyz", "author": "UltraLion - https://ultralion.xyz",
@@ -20,6 +23,12 @@
"yaml": "^2.8.1" "yaml": "^2.8.1"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.1.10" "@eslint/js": "^9.34.0",
"eslint": "^9.34.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"globals": "^16.3.0",
"nodemon": "^3.1.10",
"prettier": "^3.6.2"
} }
} }