grammyjs/conversations

question: how can I wait for menu option click in conversation?

avmax opened this issue · 4 comments

avmax commented

Hello!

There is a wonderful thing in grammy - conversation.wait().
However, it waits for messages. And I need to wait until user chooses an option in menu.

I am using '@grammyjs/menu';

In my code I want to achieve something like this:

const menu = new Menu("my-menu-identifier")
  .text("A", (ctx) => ctx.reply("You pressed A!")).row()
  .text("B", (ctx) => ctx.reply("You pressed B!"));

await ctx.reply('Choose option bro', { reply_markup: menu };
await conversation.waitFor(':menuClick'); // thats a fake code just to show the idea
console.log('blabla) // this line executes only after user chooses any option in menu

How can I wait in a conversation until user chooses an option in menu?

Thanks in advance for help.
And very very big thank you for grammy! Awesome framework.
Have not been coding for 2 years, and when started looking for frameworks - was shocked how telegraf being so popular has such bad docs and so not easy to use. Grammy is awesome at use, and super awesome at docs. Thank u!

PPS: I tried conversation.wait() - looks like that it is waiting only for messages, not for menu clicks

This is also my question, conversation.wait() just wait for the user to trigger message

Heya. I have the same issue. I was reading through conversations types and I found out that it has such methods: wait, waitUnless, waitFor, waitUntil, waitFrom. I haven't tried to use these yet. But it looks like some of them may be used to solve the issue. Some comments from contributors would be appreciated though

I am not sure if there is a good way to use the menu plugin and the conversations plugin together. This is because the menu handles the button clicks already, so it is not clear how the conversation would wait for button clicks also.

Instead, I would probably use the built-in inline keyboard plugin of grammY.

async function menu(conversation: MyConversation, ctx: MyContext) {
    const keyboard = new InlineKeyboard()
        .text("Click me!", "click");
    await ctx.reply("Keyboard:", { reply_markup: keyboard });
    ctx = await conversation.waitFor("callback_query:data");
    await ctx.editMessageText("Done!");
}

However, note that there are a few things that work very differently in comparison to regular menus. We only wait for the callback query ONCE, so as soon as the user clicks the button, the conversation moves on and other things are happening. Subsequent button clicks are not being handled. In the above example, the conversation has already completed. If you want to handle the button more times, you can either loop, or wait for #42 to be implemented. But honestly, it's probably easier to remove the button as soon as it was pressed (which is what the code above does).

It would be cool to have a way to use menus inside conversations, and I am confident that #44 is not too hard to implement. It could provide a way to do this.

Contributions are always welcome! This not only includes code, but if you find a way to make conversations and menus work well together, please share it :)

Please review #47 so that we can get #52 done. I have tested the changes locally and it seems to work pretty well with the following code.

async function greeting(conversation: MyConversation, ctx: MyContext) {
  const main = new Menu("root-menu")
    .text("Welcome", (ctx) => ctx.reply("Hi!")).row()
    .submenu("Credits", "credits-menu");
  const settings = new Menu("credits-menu")
    .text("Show Credits", (ctx) => ctx.reply("Powered by grammY"))
    .back("Go Back");
  main.register(settings);
  await conversation.run(main);

  const msg = await ctx.reply("Here is your menu. Send /exit to leave!", {
    reply_markup: main,
  });

  await ctx.reply("What is your first name?");
  const text = await conversation.form.text();
  await ctx.reply("Your name is " + text);
}

The menu can be used at the same time as the conversation is running, and one can even interact with the menu message (edit it, delete it, etc) from a later point in the conversation.