Interactions
Interactions de Composants
Chaque clic de bouton ou sélection de menu sur un composant envoyé par votre bot déclenche une interaction, déclenchant l'événement Client#interactionCreate. La façon dont vous décidez de gérer ceci dépendra probablement du but des composants. Les options incluent :
- Attendre une seule interaction via
awaitMessageComponent()sur un canal ou un message. - Écouter plusieurs interactions sur une période de temps en utilisant un
InteractionCollector. - Créer un gestionnaire de composants permanent dans l'événement
Client#interactionCreate.
Cette page est un suivi de la section commandes slash et suppose que vous avez créé soit des boutons soit des menus de sélection comme détaillé dans ce guide. Veuillez lire attentivement ces pages d'abord pour que vous puissiez comprendre les méthodes utilisées ici.
Répondre aux interactions de composants
Comme avec toutes les autres interactions, les interactions de composants de messages nécessitent une réponse dans les 3 secondes, sinon Discord les traitera comme échouées.
Comme les commandes slash, tous les types d'interactions de composants de messages supportent les méthodes reply(), deferReply(), editReply() et followUp(), avec la possibilité que ces réponses soient éphémères. Ces fonctions fonctionnent de manière identique à celle des commandes slash, donc consultez la page sur les méthodes de réponse des commandes slash pour plus d'informations.
Les interactions de composants supportent également deux méthodes de réponse supplémentaires, détaillées ci-dessous et démontrées dans des exemples plus loin dans la page.
Mises à jour
Répondre à une interaction de composant via la méthode update() reconnaît l'interaction en modifiant le message auquel le composant était attaché. Cette méthode devrait être préférée à l'appel de editReply() sur l'interaction d'origine qui a envoyé les composants. Comme editReply(), update() ne peut pas être utilisé pour modifier l'état éphémère d'un message.
Une fois update() appelé, les messages futurs peuvent être envoyés en appelant followUp() ou les modifications peuvent être apportées en appelant editReply() sur l'interaction de composant.
Mises à jour reportées
Répondre à une interaction de composant via la méthode deferUpdate() reconnaît l'interaction et réinitialise l'état du message. Cette méthode peut être utilisée pour supprimer le besoin de réponses supplémentaires, cependant il est encouragé de fournir un retour significatif aux utilisateurs via au moins une update() ou une reply() éphémère.
Une fois deferUpdate() appelé, les messages futurs peuvent être envoyés en appelant followUp() ou les modifications peuvent être apportées en appelant editReply() sur l'interaction de composant.
Attendre des composants
Si vous avez suivi notre guide sur les boutons, le flux de travail de confirmation pour la commande ban est un bon exemple d'une situation où votre bot s'attend à recevoir une seule réponse, soit du bouton Confirmer, soit du bouton Annuler.
Commencez par ajouter withResponse aux options, puis appelez Message#awaitMessageComponent sur le message. Cette méthode retourne une Promise qui se résout lorsqu'une interaction passe son filtre (si l'un est fourni), ou lève une erreur si aucune n'est reçue avant l'expiration du délai. Si cela se produit, supprimez les composants et notifiez l'utilisateur.
const response = await interaction.reply({
content: `Êtes-vous sûr de vouloir bannir ${target.username} pour la raison : ${reason} ?`,
components: [row],
withResponse: true,
});
const collectorFilter = (i) => i.user.id === interaction.user.id;
try {
const confirmation = await response.resource.message.awaitMessageComponent({ filter: collectorFilter, time: 60_000 });
} catch {
await interaction.editReply({ content: 'Confirmation non reçue dans 1 minute, annulation', components: [] });
}Le filtre appliqué ici assure que seul l'utilisateur qui a déclenché l'interaction d'origine peut utiliser les boutons.
Avec la confirmation collectée, vérifiez quel bouton a été cliqué et effectuez l'action appropriée.
const response = await interaction.reply({
content: `Êtes-vous sûr de vouloir bannir ${target.username} pour la raison : ${reason} ?`,
components: [row],
withResponse: true,
});
const collectorFilter = (i) => i.user.id === interaction.user.id;
try {
const confirmation = await response.resource.message.awaitMessageComponent({ filter: collectorFilter, time: 60_000 });
if (confirmation.customId === 'confirm') {
await interaction.guild.members.ban(target);
await confirmation.update({ content: `${target.username} a été banni pour la raison : ${reason}`, components: [] });
} else if (confirmation.customId === 'cancel') {
await confirmation.update({ content: 'Action annulée', components: [] });
}
} catch {
await interaction.editReply({ content: 'Confirmation non reçue dans 1 minute, annulation', components: [] });
}Collecteurs de composants
Pour les situations où vous souhaitez collecter plusieurs interactions, l'approche Collector est mieux adaptée que d'attendre les interactions singulières. En continuant le guide des menus de sélection, vous allez étendre cet exemple pour utiliser un InteractionCollector pour écouter plusieurs StringSelectMenuInteraction.
Commencez par ajouter withResponse aux options, puis appelez Message#createMessageComponentCollector sur cette instance. Cette méthode retourne un InteractionCollector qui déclenchera son événement InteractionCollector#collect chaque fois qu'une interaction passe son filtre (si l'un est fourni).
Dans l'événement collect, chaque interaction est une StringSelectMenuInteraction grâce à l'option componentType: ComponentType.StringSelect fournie au collecteur (et parce que c'était le seul type de composant dans le message). La ou les valeur(s) sélectionnée(s) sont disponibles via la propriété StringSelectMenuInteraction#values.
const response = await interaction.reply({
content: 'Choisissez votre starter !',
components: [row],
withResponse: true,
});
const collector = response.resource.message.createMessageComponentCollector({
componentType: ComponentType.StringSelect,
time: 3_600_000, // 1 heure
});
collector.on('collect', async (i) => {
const selection = i.values[0];
await i.reply(`${i.user} a sélectionné ${selection} !`);
});L'événement Client#interactionCreate
Troisièmement et enfin, vous voudrez peut-être avoir un écouteur configuré pour répondre aux fonctionnalités permanentes de bouton ou de menu de sélection de votre guilde. Pour cela, revenir à l'événement Client#interactionCreate est la meilleure approche.
Si votre gestion d'événements a été configurée dans plusieurs fichiers selon notre guide de gestion des événements, vous devez déjà avoir un fichier events/interactionCreate.js qui ressemble à quelque chose comme ceci.
const { Events } = require('discord.js');
module.exports = {
name: Events.InteractionCreate,
async execute(interaction) {
if (!interaction.isChatInputCommand()) return;
const command = interaction.client.commands.get(interaction.commandName);
if (!command) {
console.error(`Aucune commande correspondant à ${interaction.commandName} n'a été trouvée.`);
return;
}
try {
await command.execute(interaction);
} catch (error) {
console.error(`Erreur lors de l'exécution de ${interaction.commandName}`);
console.error(error);
}
},
};La façon dont cela a été configuré précédemment retourne de la fonction execute chaque fois qu'elle rencontre une interaction qui n'est pas une ChatInputCommandInteraction, comme montré sur la ligne mise en évidence ci-dessus. Le premier changement qui doit être fait est d'inverser cette logique, sans changer la fonctionnalité.
const { Events } = require('discord.js');
module.exports = {
name: Events.InteractionCreate,
async execute(interaction) {
if (!interaction.isChatInputCommand()) return;
if (interaction.isChatInputCommand()) {
const command = interaction.client.commands.get(interaction.commandName);
if (!command) {
console.error(`Aucune commande correspondant à ${interaction.commandName} n'a été trouvée.`);
return;
}
try {
await command.execute(interaction);
} catch (error) {
console.error(`Erreur lors de l'exécution de ${interaction.commandName}`);
console.error(error);
}
}
},
};Maintenant que la logique est configurée pour exécuter le code lorsque quelque chose est une ChatInputCommandInteraction, plutôt que de s'arrêter et de sortir quand ce n'est pas le cas, vous pouvez ajouter la gestion pour les types d'interaction supplémentaires via une simple logique if...else.
const { Events } = require('discord.js');
module.exports = {
name: Events.InteractionCreate,
async execute(interaction) {
if (interaction.isChatInputCommand()) {
const command = interaction.client.commands.get(interaction.commandName);
if (!command) {
console.error(`Aucune commande correspondant à ${interaction.commandName} n'a été trouvée.`);
return;
}
try {
await command.execute(interaction);
} catch (error) {
console.error(`Erreur lors de l'exécution de ${interaction.commandName}`);
console.error(error);
}
} else if (interaction.isButton()) {
// répondre au bouton
} else if (interaction.isStringSelectMenu()) {
// répondre au menu de sélection
}
},
};Menus de Sélection
Les menus de sélection sont l'une des classes `MessageComponent`, qui peuvent être envoyées via des messages ou des réponses d'interaction.
Composants d'Affichage
Bien que vous puissiez être familier avec les [embeds](./embeds) dans Discord, il existe d'autres façons de styliser et de formater les messages de votre...