r_Ioaded
r_Ioaded

Reputation: 29

How to make a custom embed based on input gathered from user input through a prompt - Discord.js

I'm attempting to make a suggestions command, where if the user types =suggest in the server, it would create a prompt in their DM's, asking for different specifications.

However, I am unsure how to obtain user input and use that input in an embed. How would I do this?

For example: The bot would ask in DM's "What would you like the title to be?", and then the user would respond with their desired title, and it would set that input as the title.

Upvotes: 1

Views: 978

Answers (1)

Zsolt Meszaros
Zsolt Meszaros

Reputation: 23189

You can use a message collector. I used channel.awaitMessages here:

const prefix = '!';

client.on('message', (message) => {
  if (message.author.bot || !message.content.startsWith(prefix)) return;
  const args = message.content.slice(prefix.length).split(/ +/);
  const command = args.shift().toLowerCase();

  if (command === 'suggest') {
    // send the question
    message.channel.send('What would you like the title to be?');

    // use a filter to only collect a response from the message author
    const filter = (response) => response.author.id === message.author.id;
    // only accept a maximum of one message, and error after one minute
    const options = { max: 1, time: 60000, errors: ['time'] };

    message.channel
      .awaitMessages(filter, options)
      .then((collected) => {
        // the first collected message's content will be the title
        const title = collected.first().content;
        const embed = new MessageEmbed()
          .setTitle(title)
          .setDescription('This embed has a custom title');

        message.channel.send(embed);
      })
      .catch((collected) =>
        console.log(`After a minute, only collected ${collected.size} messages.`),
      );
  }
});

enter image description here

I've just noticed that you wanted to send it in a DM. In that case, you can .send() the first message, wait for it to be resolved, so you can add a message collector in the channel using channel.createMessageCollector(). I've added some comments to explain it:

const prefix = '!';

client.on('message', async (message) => {
  if (message.author.bot || !message.content.startsWith(prefix)) return;

  const args = message.content.slice(prefix.length).split(/ +/);
  const command = args.shift().toLowerCase();
  const MINUTES = 5;

  if (command === 'suggest') {
    const questions = [
      { answer: null, field: 'title' },
      { answer: null, field: 'description' },
      { answer: null, field: 'author name' },
      { answer: null, field: 'colour' },
    ];
    let current = 0;

    // wait for the message to be sent and grab the returned message
    // so we can add the message collector
    const sent = await message.author.send(
      `**Question 1 of ${questions.length}:**\nWhat would you like the ${questions[current].field} be?`,
    );

    const filter = (response) => response.author.id === message.author.id;
    // send in the DM channel where the original question was sent
    const collector = sent.channel.createMessageCollector(filter, {
      max: questions.length,
      time: MINUTES * 60 * 1000,
    });

    // fires every time a message is collected
    collector.on('collect', (message) => {
      // add the answer and increase the current index
      questions[current++].answer = message.content;
      const hasMoreQuestions = current < questions.length;

      if (hasMoreQuestions) {
        message.author.send(
          `**Question ${current + 1} of ${questions.length}:**\nWhat would you like the ${questions[current].field} be?`,
        );
      }
    });

    // fires when either times out or when reached the limit
    collector.on('end', (collected, reason) => {
      if (reason === 'time') {
        return message.author.send(
          `I'm not saying you're slow but you only answered ${collected.size} questions out of ${questions.length} in ${MINUTES} minutes. I gave up.`,
        );
      }

      const embed = new MessageEmbed()
        .setTitle(questions[0].answer)
        .setDescription(questions[1].answer)
        .setAuthor(questions[2].answer)
        .setColor(questions[3].answer);

      message.author.send('Here is your embed:');
      message.author.send(embed);
      // send a message for confirmation
      message.author.send('Would you like it to be published? `y[es]/n[o]`');
      message.author.dmChannel
        .awaitMessages(
          // set up a filter to only accept y, yes, n, and no
          (m) => ['y', 'yes', 'n', 'no'].includes(m.content.toLowerCase()),
          { max: 1 },
        )
        .then((coll) => {
          let response = coll.first().content.toLowerCase();
          if (['y', 'yes'].includes(response)) {
            // publish embed, like send in a channel, etc
            // then let the member know that you've finished
            message.author.send('Great, the embed is published.');
          } else {
            // nothing else to do really, just let them know what happened
            message.author.send('Publishing the embed is cancelled.');
          }
        })
        .catch((coll) => console.log('handle error'));
    });
  }
});

enter image description here

PS: You can learn more about message collectors on DiscordJS.guide.

Upvotes: 3

Related Questions