how to set up action row such that each user can interact with a button only once?

I'm trying to set up an action row with multiple buttons (for example A, B, C), and I want each user in my server to be able to interact with these buttons, however each user gets a max of only one interaction. The reason for this is a polling system; I want each user to vote only once. How can I achieve this?
20 Replies
d.js toolkit
d.js toolkit3mo ago
- What's your exact discord.js npm list discord.js and node node -v version? - Not a discord.js issue? Check out #other-js-ts. - Consider reading #how-to-get-help to improve your question! - Explain what exactly your issue is. - Post the full error stack trace, not just the top part! - Show your code! - Issue solved? Press the button! - Marked as resolved by OP
monbrey
monbrey3mo ago
Discord doesn't support a per-user display for Buttons. If you disable one, they're disabled for everyone It's up to you to track that internally and respond "You already submitted" or something like that
Penitent
Penitent3mo ago
ahh thats what I thought too, any ideas how I can track a "you already submitted"? my initial thought is to have a set with user id but idk how to get the user id of each person who interacts once i figure that out i could prob just send an ephemeral "you already submitted" and then we're good to go
monbrey
monbrey3mo ago
Yep, thats pretty much how I'd do it. interaction.user.id will be available on the button interaction
Penitent
Penitent3mo ago
okay, ill try that out! thanks for the help:) hopefully I can get it to work with multiple interactions without much of a headache
monbrey
monbrey3mo ago
Just gotta maintain that set in the right scope, so it's not a new Set() on every interaction Depends how you're listening for buttons
Penitent
Penitent3mo ago
yeah i cant even get the button interactions to work at the moment unfortunately im trying to follow the tutorial on the website but for some reason it just consistently fails
Penitent
Penitent3mo ago
const response = await modalSubmission.reply({ embeds: [pollEmbed], components: [row] });


const collectorFilter = i => i.user.id === interaction.user.id;

try {
const confirmation = await response.awaitMessageComponent({ filter: collectorFilter, time: 60_000 });
} catch (e) {
await interaction.editReply({ content: 'Confirmation not received within 1 minute, cancelling', components: [] });
}
const response = await modalSubmission.reply({ embeds: [pollEmbed], components: [row] });


const collectorFilter = i => i.user.id === interaction.user.id;

try {
const confirmation = await response.awaitMessageComponent({ filter: collectorFilter, time: 60_000 });
} catch (e) {
await interaction.editReply({ content: 'Confirmation not received within 1 minute, cancelling', components: [] });
}
No description
Penitent
Penitent3mo ago
i copied the code straight from the tutorial to see if itll work but nope
monbrey
monbrey3mo ago
That error suggests its trying to respond to it like a command though It might not be reaching these buttons
Penitent
Penitent3mo ago
maybe but the error only comes up after i interact with a button thats why im not too sure
monbrey
monbrey3mo ago
If your command handler is rejecting it first, that would cause this issue If you want to collect multiple button interactions a collector might be better than await
d.js docs
d.js docs3mo ago
:guide: Message Components: Component interactions - Component collectors Begin by storing the InteractionResponseopen in new window as a variable, and calling InteractionResponse#createMessageComponentCollector()open in new window on this instance. This method returns an InteractionCollector that will fire its InteractionCollector#event:collectopen in new window event... read more
Penitent
Penitent3mo ago
hmmm im gonna try that and see what happens im hoping its not a command handler issue
monbrey
monbrey3mo ago
It seems like your command handler might not have a line to ignore anything thats not a command if(!interaction.isChatInputCommand()) return;
Penitent
Penitent3mo ago
i do have that actually
const { ActionRowBuilder, Events, ModalBuilder, TextInputBuilder, TextInputStyle } = 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(`No command matching ${interaction.commandName}`);
}

try {
await command.execute(interaction);
} catch (error) {
console.error(error);
if (interaction.replied || interaction.deferred) {
await interaction.followUp({ content: 'There was an error while executing this command!', ephemeral: true});
} else {
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true});
}
}

},
};
const { ActionRowBuilder, Events, ModalBuilder, TextInputBuilder, TextInputStyle } = 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(`No command matching ${interaction.commandName}`);
}

try {
await command.execute(interaction);
} catch (error) {
console.error(error);
if (interaction.replied || interaction.deferred) {
await interaction.followUp({ content: 'There was an error while executing this command!', ephemeral: true});
} else {
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true});
}
}

},
};
this is my command handler though i guess it is coming from here ahh wait i figured it out, its cause i had copied from the tutorial but i didnt follow their ban command tutorial i still get an error but at least this time i know its not from the command handler
Penitent
Penitent3mo ago
No description
Penitent
Penitent3mo ago
const response = await modalSubmission.reply({ embeds: [pollEmbed], components: [row] });


const confirmation = await response.awaitMessageComponent();
console.log(confirmation)

if (confirmation.customId == 'firstChoiceButton') {
await confirmation.update({ content: 'Successful interaction! ', components: []})
}
const response = await modalSubmission.reply({ embeds: [pollEmbed], components: [row] });


const confirmation = await response.awaitMessageComponent();
console.log(confirmation)

if (confirmation.customId == 'firstChoiceButton') {
await confirmation.update({ content: 'Successful interaction! ', components: []})
}
const response = await modalSubmission.reply({ embeds: [pollEmbed], components: [row] });


const collector = response.createMessageComponentCollector();

collector.on('collect', async i => {
console.log(i)
await i.reply(`Hello WOrld!`);
});
const response = await modalSubmission.reply({ embeds: [pollEmbed], components: [row] });


const collector = response.createMessageComponentCollector();

collector.on('collect', async i => {
console.log(i)
await i.reply(`Hello WOrld!`);
});
continues to give me "This interaction failed" when i click on a button even if i set the ComponentType to Button @ʎǝɹquoɯ is it at all possible that the reason there's issues is because it's a modalsubmission reply instead of an interaction reply?
monbrey
monbrey3mo ago
no that shouldnt matter sorry, Im busy with work stuff, cant give this the level of answer it needs right now
Penitent
Penitent3mo ago
no worries! take your time ill figure it out eventually 😅