#Cannot send ActionRowBuilder due to type error in djs 14

116 messages · Page 1 of 1 (latest)

strong pulsar
#

I'm trying to send a button component with a message but i get the following errors:
Type 'ActionRowBuilder<AnyComponentBuilder>' is not assignable to type 'APIActionRowComponent<APIMessageActionRowComponent> | JSONEncodable<APIActionRowComponent<APIMessageActionRowComponent>> | ActionRowData<...>'.

Property 'type' is missing in type 'ActionRowBuilder<AnyComponentBuilder>' but required in type 'ActionRowData<MessageActionRowComponentBuilder | MessageActionRowComponentData>'.

const button = new ButtonBuilder()
    .setCustomId("qac_sr")
    .setLabel("Request")
    .setStyle(ButtonStyle.Success);

    const row = new ActionRowBuilder()
    .addComponents(button)

    client.guilds.fetch("id").then((guild) => {
        (guild.channels.fetch("id") as Promise<TextChannel>).then((channel) => {
            channel.send({
                content: "Click the button below to request a test",
                components: [row] // Errors here
            })
        })
    })
wicked moonBOT
#

In TypeScript the ActionRowBuilder class has a generic type parameter that specifies the type of component the action row holds:

const row = new ActionRowBuilder<ButtonBuilder>().addComponents(button)
const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectMenu)
const row = new ActionRowBuilder<TextInputBuilder>().addComponents(textInput)
exotic mirage
#

#986520997006032896 would’ve been a better fit for this question, but it’s alright

strong pulsar
#

anyway it worked thanks

exotic mirage
#

yeah it’s for both ts and js there, but i’m glad it’s fixed

wispy sandal
#

const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(confirm);

mine is specified but it still returns

In TypeScript the ActionRowBuilder class has a generic type parameter that specifies the type of component the action row holds:
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(button)
const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectMenu)
const row = new ActionRowBuilder<TextInputBuilder>().addComponents(textInput)

plucky crystal
wispy sandal
#

in the editor it all looks fine, when i run the slash command it all works fine no errors but as soon as i try to remove it by setting it to [] it gives me the above error

exotic mirage
#

can you show the error you get from your console

wispy sandal
#
.setCustomId('confirm')
        .setLabel('Complete (Make sure auth. is saved in app)')
        .setStyle(ButtonStyle.Primary);

      const row = new ActionRowBuilder<ButtonBuilder>()
        .addComponents(confirm);

      const embed = new EmbedBuilder()
        .setColor(0x0099FF)
        .setTitle('Scan qr with Google Authenticator')
        .setImage(attachmentUrl)
        .setFooter({ text: 'Risk Mitigation unit - [RU] Mangement', iconURL: 'link.png' });

      const inmess = await msgInt?.reply({
        content: '',
        ephemeral: true,
        components: [row],
        embeds: [embed],
        files: [attachment],
      });
    } catch (error) {
      console.log('Error with QR:', error);
    }

    const collector = channel?.createMessageComponentCollector({
      max: 1,
      componentType: ComponentType.Button,
      time: 1000 * 5 * 60,
    });
    collector?.on('collect', async (collected: Collection<string, ButtonInteraction>) => {
      if (collected.first()?.customId === 'confirm') {
        await msgInt?.editReply({
          content: 'Sucesfully configured 2fa',
          components: [],
          embeds: [],
          files: [],
        })
      }
    });
  },
} as CommandObject;
#

code ^

#

error

exotic mirage
#

the collect event in your code doesn't return a collection so im not too sure why you set it to one

#

collected would return a ButtonInteraction, which you can access .customId from

#

but regarding that error, make sure your files are saved

wispy sandal
#

honestly just straight up copied the collection from wok documentation, ill change that

#

seemed fine

exotic mirage
#

im sure it works fine, but it's really not needed

also could be TS not recognizing the type after placing it for that row. try restarting your TS server & your IDe

wispy sandal
#

interaction is now failing no errors

exotic mirage
#

i would also suggest making the collector on the message instead of the channel

wispy sandal
#

on msgInt?

plucky crystal
#

I'm also seeing an editReply after a reply.
Which won't work because you've already replied to the interaction.
You can either reply to the button interaction or do an update.
Or a followUp on your main message

exotic mirage
#

wot

#

you can call editReply after a reply

wispy sandal
#

im editing a reply?

#

i dont want to send a new message

plucky crystal
#

eh.... I thought it was meant to be used in deferred responses. mb then

exotic mirage
#

editReply is exactly what it sounds like. edits the inital reply

wispy sandal
plucky crystal
#

Makes sense. Thanks for the correction.

plucky crystal
# wispy sandal on msgInt?

You can create a collector on the message you send yes.
Rather than scoping the entire channel where the message is being sent

wispy sandal
#

it shows: Property 'createMessageComponentCollector' does not exist on type

exotic mirage
#

on type what

wispy sandal
#

Property 'createMessageComponentCollector' does not exist on type 'ChatInputCommandInteraction<CacheType>'

#

thats what i said before

exotic mirage
#

well yes because its not a message

wispy sandal
#

i cant use msgint

#

nor inmess

wispy sandal
exotic mirage
#

please show your entire code

wispy sandal
#

how would i make the collector on the msg instead of channel

exotic mirage
#

should really be in #986520997006032896 since this isn't the best channel, but this time its fine

wispy sandal
#
const user = '[RU] Authorization';
const service = '[RU] | Russian Federation';

export default {
  description: "generates TOTP TOKEN - ONE TIME USE",
  type: CommandType.SLASH,
  testOnly: true,
  callback: async ({ interaction: msgInt, channel }) => {
    const userId = msgInt?.user?.id;
    console.log(userId)
    const secret = userId ? userId + "" : '';
    const otpauth = authenticator.keyuri(user, service, secret);

    try {
      const imageDataUrl = await qrcode.toDataURL(otpauth);
      const buffer = Buffer.from(imageDataUrl.split(',')[1], 'base64');
      const attachment = new AttachmentBuilder(buffer, { name: 'qrcode.png' });
      const attachmentUrl = `attachment://${attachment.name}`;

      const confirm = new ButtonBuilder()
        .setCustomId('confirm')
        .setLabel('Complete (Make sure auth. is saved in app)')
        .setStyle(ButtonStyle.Primary);

      const row = new ActionRowBuilder<ButtonBuilder>()
        .addComponents(confirm);

      const embed = new EmbedBuilder()
        .setColor(0x0099FF)
        .setTitle('Scan qr with Google Authenticator')
        .setImage(attachmentUrl)
        .setFooter({ text: 'Risk Mitigation unit - [RU] Mangement', iconURL: ' });

      const inmess = await msgInt?.reply({
        content: '',
        ephemeral: true,
        components: [row],
        embeds: [embed],
        files: [attachment],
      });
    } catch (error) {
      console.log('Error with QR:', error);
    }

    const collector = msgInt?.createMessageComponentCollector({
      max: 1,
      componentType: ComponentType.Button,
      time: 1000 * 5 * 60,
    });
    collector?.on('collected', async (collected: Collection<string, ButtonInteraction>) => {
      if (collected.first()?.customId === 'confirm') {
        await msgInt?.editReply({
          content: 'Sucesfully configured 2fa',
          components: [],
          embeds: [],
          files: [],
        })
      }
    });
  },
} as CommandObject;```
exotic mirage
#

add fetchReply: true inside the options for inmess and i would move the catch statement lower in your code

#

then you can call inmess.createMessageComponentCollector(...

exotic mirage
#

i would move the catch statement lower in your code

wispy sandal
#

oops

exotic mirage
#

because inmess is inside the try...catch so it's not in the correct scope

wispy sandal
#

testing rn..

#

no error

exotic mirage
#

in that case i would do collected.update, but since you set it to a collection, you need to access a collection value first

or... use ButtonInteraction instead

wicked moonBOT
wispy sandal
exotic mirage
#

?

wispy sandal
#

collector does not respond at all?

#

i put in a console.log

#

and when i press btn nothing gets outputted

exotic mirage
#

the event is collect, not collected

#

before i was referring to your collected callback param

wispy sandal
exotic mirage
wispy sandal
#

how do i refer to collection

#

huh

exotic mirage
#

please look at your code to see what you named your variables

wispy sandal
#

magically changed lol

exotic mirage
#

its collected, not collection

wispy sandal
#

sorry

exotic mirage
#

it's alright, just be aware of the names

#

to make it easier, you could call the callback param button as an example

wispy sandal
#

i cant use collected.first now

#

so how do i check for the buttonid

exotic mirage
#

im still not sure why you set it to a Collection anyway

wispy sandal
#

no i mean i used .first() before

#

but i cant do that if i change to collect

exotic mirage
#

change what exactly?

wispy sandal
#

how do i check if custom id == 'confirm'

exotic mirage
#

you're doing that already

wispy sandal
wispy sandal
#

TypeError: collected.first is not a function
at C:\Users\sisar\Desktop\RiskMittigation\commands\setup.ts:55:21

exotic mirage
#

collect is the collector event name
collector is the name of your InteractionCollector
collected is the param for your InteractionCollector in the collect event

#

still not sure why you make it a collection since a InteractionCollector does not return that in the collect event

wispy sandal
wispy sandal
exotic mirage
#

change the collected type to ButtonInteraction

#

and then collected.customId

exotic mirage
wispy sandal
#

i mean they wrote the handler

#

but it indeed wasnt

wispy sandal
exotic mirage
#

it's a collection with a ButtonInteraction as the value

#

so it's not only a ButtonInteraction

wispy sandal
exotic mirage
#

you dont seem to understand what im saying

wispy sandal
#

my brain isnt working its late what do i do diffrent

#

yes im sorry ive been debugging this stupid program for the past 3 hours

exotic mirage
#
collector?.on('collect', async (collected: ButtonInteraction) => {
#

and then collected.customId

wispy sandal
#

omg

#

thank you so much!!!!!!

#

YES

#

FINALLY

#

OMG

#

how can i thank you

exotic mirage
#

the discord.js guide has great sections for making your own event & command handler if you don't want to rely on what a separate package does since it may not all be 100% correct, but this is just my suggestion

#

im so glad its working!

wispy sandal
#

thank you so much!!

#

i really apreciate you sticking around for so long!!

#

im gonna go to sleep now