mirror of
https://github.com/arthur-pbty/LazyBot.git
synced 2026-06-03 15:07:29 +02:00
383 lines
13 KiB
JavaScript
383 lines
13 KiB
JavaScript
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType } = require('discord.js');
|
||
const addCommand = require('../../fonctions/addCommand');
|
||
const db = require('../../db');
|
||
|
||
const buttonStyles = {
|
||
'primary': ButtonStyle.Primary,
|
||
'secondary': ButtonStyle.Secondary,
|
||
'success': ButtonStyle.Success,
|
||
'danger': ButtonStyle.Danger
|
||
};
|
||
|
||
// Fonction pour créer/mettre à jour le message du panel
|
||
async function updatePanelMessage(client, panel, buttons) {
|
||
try {
|
||
const guild = client.guilds.cache.get(panel.guild_id);
|
||
if (!guild) return null;
|
||
|
||
const channel = guild.channels.cache.get(panel.channel_id);
|
||
if (!channel) return null;
|
||
|
||
// Créer l'embed
|
||
const embed = new EmbedBuilder()
|
||
.setColor(panel.color || '#5865F2')
|
||
.setTitle(panel.title || '🎭 Choisissez vos rôles')
|
||
.setDescription(panel.description || 'Cliquez sur les boutons ci-dessous pour obtenir ou retirer des rôles.');
|
||
|
||
if (panel.image_url) embed.setImage(panel.image_url);
|
||
if (panel.thumbnail_url) embed.setThumbnail(panel.thumbnail_url);
|
||
|
||
// Infos sur le mode
|
||
const modeText = panel.exclusive
|
||
? '⚠️ *Un seul rôle possible à la fois*'
|
||
: (panel.mode === 'toggle' ? '💡 *Cliquez à nouveau pour retirer un rôle*' : '');
|
||
|
||
if (modeText) {
|
||
embed.setFooter({ text: modeText });
|
||
}
|
||
|
||
// Créer les boutons (max 5 par ligne, max 5 lignes)
|
||
const rows = [];
|
||
const enabledButtons = buttons.filter(b => b.enabled).sort((a, b) => a.position - b.position);
|
||
|
||
for (let i = 0; i < enabledButtons.length && rows.length < 5; i += 5) {
|
||
const row = new ActionRowBuilder();
|
||
const rowButtons = enabledButtons.slice(i, i + 5);
|
||
|
||
for (const btn of rowButtons) {
|
||
const button = new ButtonBuilder()
|
||
.setCustomId(`role_panel_${btn.id}`)
|
||
.setLabel(btn.label)
|
||
.setStyle(buttonStyles[btn.style] || ButtonStyle.Primary);
|
||
|
||
if (btn.emoji) {
|
||
// Vérifier si c'est un emoji custom ou unicode
|
||
if (btn.emoji.match(/^\d+$/)) {
|
||
button.setEmoji({ id: btn.emoji });
|
||
} else {
|
||
button.setEmoji(btn.emoji);
|
||
}
|
||
}
|
||
|
||
row.addComponents(button);
|
||
}
|
||
|
||
if (row.components.length > 0) {
|
||
rows.push(row);
|
||
}
|
||
}
|
||
|
||
// Mettre à jour ou créer le message
|
||
if (panel.message_id) {
|
||
try {
|
||
const message = await channel.messages.fetch(panel.message_id);
|
||
await message.edit({ embeds: [embed], components: rows });
|
||
return panel.message_id;
|
||
} catch {
|
||
// Message introuvable, en créer un nouveau
|
||
}
|
||
}
|
||
|
||
const message = await channel.send({ embeds: [embed], components: rows });
|
||
|
||
// Sauvegarder l'ID du message
|
||
await new Promise((resolve, reject) => {
|
||
db.run("UPDATE role_panels SET message_id = ? WHERE id = ?", [message.id, panel.id], (err) => {
|
||
if (err) reject(err);
|
||
else resolve();
|
||
});
|
||
});
|
||
|
||
return message.id;
|
||
|
||
} catch (err) {
|
||
console.error('Erreur mise à jour panel:', err);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
module.exports = addCommand({
|
||
name: 'rolepanel',
|
||
description: 'Créer un panneau de rôles interactif',
|
||
aliases: ['rp', 'rolebuttons', 'reactionroles'],
|
||
permissions: ['ManageRoles', 'ManageMessages'],
|
||
botOwnerOnly: false,
|
||
dm: false,
|
||
scope: 'global',
|
||
slashOptions: [
|
||
{ type: 'STRING', name: 'action', description: 'Action à effectuer', required: true, choices: [
|
||
{ name: 'Créer un panel', value: 'create' },
|
||
{ name: 'Ajouter un bouton', value: 'addbutton' },
|
||
{ name: 'Supprimer un panel', value: 'delete' },
|
||
{ name: 'Liste des panels', value: 'list' },
|
||
{ name: 'Actualiser un panel', value: 'refresh' }
|
||
]},
|
||
{ type: 'STRING', name: 'nom', description: 'Nom du panel', required: false },
|
||
{ type: 'CHANNEL', name: 'salon', description: 'Salon où envoyer le panel', required: false },
|
||
{ type: 'ROLE', name: 'role', description: 'Rôle à associer (pour addbutton)', required: false },
|
||
{ type: 'STRING', name: 'label', description: 'Texte du bouton', required: false },
|
||
{ type: 'STRING', name: 'emoji', description: 'Emoji du bouton', required: false }
|
||
],
|
||
|
||
executeSlash: async (client, interaction) => {
|
||
const action = interaction.options.getString('action');
|
||
const guildId = interaction.guild.id;
|
||
|
||
switch (action) {
|
||
case 'create': {
|
||
const name = interaction.options.getString('nom');
|
||
const channel = interaction.options.getChannel('salon');
|
||
|
||
if (!name || !channel) {
|
||
return interaction.reply({
|
||
content: '❌ Vous devez spécifier un nom et un salon.\nUsage: `/rolepanel create nom:MonPanel salon:#roles`',
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
if (channel.type !== ChannelType.GuildText) {
|
||
return interaction.reply({
|
||
content: '❌ Le salon doit être un salon textuel.',
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
// Vérifier si un panel avec ce nom existe déjà
|
||
const existing = await db.getAsync(
|
||
"SELECT id FROM role_panels WHERE guild_id = ? AND name = ?",
|
||
[guildId, name]
|
||
);
|
||
|
||
if (existing) {
|
||
return interaction.reply({
|
||
content: '❌ Un panel avec ce nom existe déjà.',
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
// Créer le panel
|
||
const panelId = await new Promise((resolve, reject) => {
|
||
db.run(
|
||
"INSERT INTO role_panels (guild_id, channel_id, name, title, description) VALUES (?, ?, ?, ?, ?)",
|
||
[guildId, channel.id, name, `🎭 ${name}`, 'Cliquez sur les boutons ci-dessous pour obtenir vos rôles.'],
|
||
function(err) {
|
||
if (err) reject(err);
|
||
else resolve(this.lastID);
|
||
}
|
||
);
|
||
});
|
||
|
||
const embed = new EmbedBuilder()
|
||
.setColor(0x57F287)
|
||
.setTitle('✅ Panel créé')
|
||
.setDescription(`Le panel **${name}** a été créé.`)
|
||
.addFields(
|
||
{ name: '📁 Salon', value: `${channel}`, inline: true },
|
||
{ name: '🆔 ID', value: `${panelId}`, inline: true }
|
||
)
|
||
.setFooter({ text: 'Ajoutez des boutons avec /rolepanel addbutton' });
|
||
|
||
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||
}
|
||
|
||
case 'addbutton': {
|
||
const name = interaction.options.getString('nom');
|
||
const role = interaction.options.getRole('role');
|
||
const label = interaction.options.getString('label');
|
||
const emoji = interaction.options.getString('emoji');
|
||
|
||
if (!name || !role) {
|
||
return interaction.reply({
|
||
content: '❌ Vous devez spécifier le nom du panel et un rôle.\nUsage: `/rolepanel addbutton nom:MonPanel role:@MonRole label:Mon Rôle emoji:🎮`',
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
// Trouver le panel
|
||
const panel = await db.getAsync(
|
||
"SELECT * FROM role_panels WHERE guild_id = ? AND name = ?",
|
||
[guildId, name]
|
||
);
|
||
|
||
if (!panel) {
|
||
return interaction.reply({
|
||
content: `❌ Panel "${name}" non trouvé. Utilisez \`/rolepanel list\` pour voir les panels existants.`,
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
// Vérifier le nombre de boutons (max 25)
|
||
const buttonCount = await db.getAsync(
|
||
"SELECT COUNT(*) as count FROM role_panel_buttons WHERE panel_id = ?",
|
||
[panel.id]
|
||
);
|
||
|
||
if (buttonCount.count >= 25) {
|
||
return interaction.reply({
|
||
content: '❌ Ce panel a atteint la limite de 25 boutons.',
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
// Ajouter le bouton
|
||
await new Promise((resolve, reject) => {
|
||
db.run(
|
||
"INSERT INTO role_panel_buttons (panel_id, role_id, label, emoji, position) VALUES (?, ?, ?, ?, ?)",
|
||
[panel.id, role.id, label || role.name, emoji || null, buttonCount.count],
|
||
(err) => {
|
||
if (err) reject(err);
|
||
else resolve();
|
||
}
|
||
);
|
||
});
|
||
|
||
// Mettre à jour le message
|
||
const buttons = await db.allAsync(
|
||
"SELECT * FROM role_panel_buttons WHERE panel_id = ?",
|
||
[panel.id]
|
||
);
|
||
|
||
await updatePanelMessage(client, panel, buttons);
|
||
|
||
const embed = new EmbedBuilder()
|
||
.setColor(0x57F287)
|
||
.setTitle('✅ Bouton ajouté')
|
||
.addFields(
|
||
{ name: '📋 Panel', value: name, inline: true },
|
||
{ name: '🎭 Rôle', value: `${role}`, inline: true },
|
||
{ name: '🏷️ Label', value: label || role.name, inline: true }
|
||
);
|
||
|
||
if (emoji) embed.addFields({ name: '😀 Emoji', value: emoji, inline: true });
|
||
|
||
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||
}
|
||
|
||
case 'delete': {
|
||
const name = interaction.options.getString('nom');
|
||
|
||
if (!name) {
|
||
return interaction.reply({
|
||
content: '❌ Vous devez spécifier le nom du panel à supprimer.',
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
const panel = await db.getAsync(
|
||
"SELECT * FROM role_panels WHERE guild_id = ? AND name = ?",
|
||
[guildId, name]
|
||
);
|
||
|
||
if (!panel) {
|
||
return interaction.reply({
|
||
content: `❌ Panel "${name}" non trouvé.`,
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
// Supprimer le message
|
||
try {
|
||
const channel = interaction.guild.channels.cache.get(panel.channel_id);
|
||
if (channel && panel.message_id) {
|
||
const message = await channel.messages.fetch(panel.message_id).catch(() => null);
|
||
if (message) await message.delete();
|
||
}
|
||
} catch {}
|
||
|
||
// Supprimer de la DB
|
||
await new Promise((resolve, reject) => {
|
||
db.run("DELETE FROM role_panel_buttons WHERE panel_id = ?", [panel.id], (err) => {
|
||
if (err) reject(err);
|
||
else resolve();
|
||
});
|
||
});
|
||
|
||
await new Promise((resolve, reject) => {
|
||
db.run("DELETE FROM role_panels WHERE id = ?", [panel.id], (err) => {
|
||
if (err) reject(err);
|
||
else resolve();
|
||
});
|
||
});
|
||
|
||
return interaction.reply({
|
||
content: `✅ Panel **${name}** supprimé avec succès.`,
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
case 'list': {
|
||
const panels = await db.allAsync(
|
||
"SELECT rp.*, COUNT(rpb.id) as button_count FROM role_panels rp LEFT JOIN role_panel_buttons rpb ON rp.id = rpb.panel_id WHERE rp.guild_id = ? GROUP BY rp.id",
|
||
[guildId]
|
||
);
|
||
|
||
if (!panels || panels.length === 0) {
|
||
return interaction.reply({
|
||
content: 'ℹ️ Aucun panel de rôles configuré. Créez-en un avec `/rolepanel create`.',
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
const embed = new EmbedBuilder()
|
||
.setColor(0x5865F2)
|
||
.setTitle('📋 Panels de rôles')
|
||
.setDescription(panels.map(p => {
|
||
const status = p.enabled ? '🟢' : '🔴';
|
||
return `${status} **${p.name}** - ${p.button_count} boutons - <#${p.channel_id}>`;
|
||
}).join('\n'));
|
||
|
||
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||
}
|
||
|
||
case 'refresh': {
|
||
const name = interaction.options.getString('nom');
|
||
|
||
if (!name) {
|
||
return interaction.reply({
|
||
content: '❌ Vous devez spécifier le nom du panel à actualiser.',
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
const panel = await db.getAsync(
|
||
"SELECT * FROM role_panels WHERE guild_id = ? AND name = ?",
|
||
[guildId, name]
|
||
);
|
||
|
||
if (!panel) {
|
||
return interaction.reply({
|
||
content: `❌ Panel "${name}" non trouvé.`,
|
||
ephemeral: true
|
||
});
|
||
}
|
||
|
||
const buttons = await db.allAsync(
|
||
"SELECT * FROM role_panel_buttons WHERE panel_id = ?",
|
||
[panel.id]
|
||
);
|
||
|
||
const messageId = await updatePanelMessage(client, panel, buttons);
|
||
|
||
if (messageId) {
|
||
return interaction.reply({
|
||
content: `✅ Panel **${name}** actualisé !`,
|
||
ephemeral: true
|
||
});
|
||
} else {
|
||
return interaction.reply({
|
||
content: '❌ Erreur lors de l\'actualisation du panel.',
|
||
ephemeral: true
|
||
});
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
executePrefix: async (client, message, args) => {
|
||
return message.reply('❌ Cette commande est disponible uniquement en slash command. Utilisez `/rolepanel`.');
|
||
}
|
||
});
|
||
|
||
// Exporter la fonction de mise à jour pour l'API
|
||
module.exports.updatePanelMessage = updatePanelMessage;
|