Skip to content
Advertisement

Faster and cleaner way to update Discord Message Embed with a MessageComponentInteraction collector

I’m trying to make a horse race command for my discord bot (TypeScript). The code itself works fine, but I have to update an embed which contains the race and the participants. The thing is that for it to properly update, I have to set its description every time that collector.on("collect") fires. I want to ask if there’s a better, more efficient and cleaner way to update it. Thank you!
code:

    const bet = interaction.options.get("bet").value;

    class Horse {
      name: string;
      owner: User;
      speed: number;
      position: Array<string>;
      constructor(name: string) {
        this.name = name;
        this.owner = null;
        this.speed = 0;
        this.position = ["🐴"];
      }
    }

    const horses = [
      new Horse(aimless.pick(names, { remove: true })),
      new Horse(aimless.pick(names, { remove: true })),
      new Horse(aimless.pick(names, { remove: true })),
      new Horse(aimless.pick(names, { remove: false })),
    ];
    const hasJoined: Array<Horse["owner"]> = [];

    const row = new MessageActionRow();
    for (const horse of horses) {
      row.addComponents(
        new MessageButton()
          .setCustomId(horse.name)
          .setLabel(horse.name)
          .setStyle("SECONDARY")
      );
    }
    const embed = new MessageEmbed()
      .setTitle("Place your bets!")
      .setDescription(
        `**${horses[0].name} - ${
          horses[0].owner !== null ? horses[0].owner.username : "Nobody"
        } 
        ${horses[0].position}
        
        ${horses[1].name} - ${
          horses[1].owner !== null ? horses[1].owner.username : "Nobody"
        }
        ${horses[1].position}
        
        ${horses[2].name} - ${
          horses[2].owner !== null ? horses[2].owner.username : "Nobody"
        }
        ${horses[2].position} 
        
        ${horses[3].name} - ${
          horses[3].owner !== null ? horses[3].owner.username : "Nobody"
        }
        ${horses[3].position}**`
      );
    await interaction.editReply({
      embeds: ,
      components: [row],
    });
    const filter = async (i: MessageComponentInteraction) => {
      let profile: any;
      try {
        profile = await profileModel.findOne({ userID: i.user.id });
        if (!profile) {
          await profileModel.create({
            userID: i.user.id,
            serverID: i.guild?.id,
            username: i.user.username,
            bananas: 100,
            deposit: 0,
          });
          profile.save();
        }
      } catch (e) {
        await i.editReply("Something went wrong! :( Please retry.");
      } finally {
        if (hasJoined.includes(i.user)) {
          return false;
        }
        if (profile.bananas < bet) {
          interaction.editReply(`${i.user} you don't have enough bananas!`);
        }
        return profile.bananas >= bet;
      }
    };
    const collector = interaction.channel.createMessageComponentCollector({
      filter,
      time: 60000,
    });
    collector.on("collect", async (int) => {
      await int.deferUpdate();
      for (const btn of row.components) {
        if (btn.customId === (int.component as MessageButton).customId) {
          (btn as MessageButton).setDisabled(true).setStyle("SUCCESS");
          hasJoined.push(int.user);
          horses.find((h) => h.name === btn.customId).owner = int.user;
          console.log(horses);
        }
      }

      embed.setDescription(
        `**${horses[0].name} - ${
          horses[0].owner !== null ? horses[0].owner.username : "Nobody"
        } 
        ${horses[0].position}
        
        ${horses[1].name} - ${
          horses[1].owner !== null ? horses[1].owner.username : "Nobody"
        }
        ${horses[1].position}
        
        ${horses[2].name} - ${
          horses[2].owner !== null ? horses[2].owner.username : "Nobody"
        }
        ${horses[2].position} 
        
        ${horses[3].name} - ${
          horses[3].owner !== null ? horses[3].owner.username : "Nobody"
        }
        ${horses[3].position}**`
      );

      await int.editReply({
        embeds: ,
        components: [row],
      });
    });
  },
});`

Advertisement

Answer

You could make it into a function:

const displayHorses = (horses: Array<Horse>) => {
  return `**${horses[0].name} - ${
    horses[0].owner !== null ? horses[0].owner.username : "Nobody"
  } 
        ${horses[0].position}
        
        ${horses[1].name} - ${
    horses[1].owner !== null ? horses[1].owner.username : "Nobody"
  }
        ${horses[1].position}
        
        ${horses[2].name} - ${
    horses[2].owner !== null ? horses[2].owner.username : "Nobody"
  }
        ${horses[2].position} 
        
        ${horses[3].name} - ${
    horses[3].owner !== null ? horses[3].owner.username : "Nobody"
  }
        ${horses[3].position}**`;
};

And then every time:

embed.setDescription(displayHorses(horses));

If you want to compact it even further, you could map the horse array.

const displayHorses = (horses: Array<Horse>) => {
  return horses.map(
    ({ name, owner, position }) =>
      `**${name}** - ${owner !== null ? owner.username : "Nobody"}
     ${position}`
  );
};

Lastly, as a tip, if you’re using 14+, you could compact it even further to:

const displayHorses = (horses: Array<Horse>) => {
  return horses.map(
    ({ name, owner, position }) =>
    `**${name}** - ${owner?.username ?? "Nobody"}
     ${position}`
  );
};
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement