EdJoPaTo / grammy-inline-menu

Inline Menus for Telegram made simple. Successor of telegraf-inline-menu.
MIT License
357 stars 44 forks source link

ctx.match with replyMenuToContext #158

Closed kirosc closed 3 years ago

kirosc commented 3 years ago

I notice the ctx.match is missing when sending a menu with replyMenuToContext.

I don't want to rely on storing the information in session. Is it possible to send a submenu to user directly and providing the action in the path? Like this,

replyMenuToContext(menuB, ctx, '/a:choiceA/b');

Thank you!

EdJoPaTo commented 3 years ago

The context is simply passed through so if you provide a ctx without match, it wont appear somewhere in between. For example when using a interact button its fairly simple to get the choice from the path:

menuB.interact('Text', 'unique', {
  do: async (ctx, path) => {
    let match = /\/a:([^/]+)\//.exec(path);
    if (!match) {
      throw new Error('something is fishy');
    }
    console.log('You are in submenu choice', match[1]);
    await ctx.answerCbQuery('Hi there!');
    return false;
  }
}

I hope it helps.

kirosc commented 3 years ago
bot.command('menuB', (ctx) => replyMenuToContext(menuB, ctx, '/a:choiceA/b'));

const buildChoices = (ctx) => {
  const [,match] = ctx.match!; // ctx.match is undefined
  // fall back to retrieve the choice from ctx.session

  if (match === 'choiceA' {
    return ['A1', 'A2'];
  } else {
    // return other choices
  }
};

menuB.choose('b', buildChoices, {
  do: (ctx, path) => {
    console.log(`You choose ${path}`);
    return false;
  }
});

Thanks for the quick reply!

Actually, I want to build the menuB keyboard based on the user answer in menuA. But at same time, I want to show menuB to some users directly by assuming their answer in menuA. I guess I must use session here to build the keyboard? No other ways to do this using the library>

EdJoPaTo commented 3 years ago

This library simply displays the data wherever it comes from. You provide the function which gives the data to the library.

You can use the session to store this data but you can also build your own function based on ctx.from.id for example. Also using a fallback if the user has nothing stored currently is possible there.

Also something small I noticed: Its probably simpler to use menuMiddleware.replyToContext in the first line:

bot.command('menuB', ctx => menuMiddleware.replyToContext(ctx, '/a:choiceA/b'))

The menu is then picked by the middleware on its own → less stuff needed to supply to the method.

kirosc commented 3 years ago

Thanks for the help!