Closed yakovenkodenis closed 4 years ago
Thanks for your interest! I think I understand your idea of doing it. The approach of the menu is a bit different: The menu structure itself tries to be static, not generated by code. Only the content is dynamic. I think in your situation the selectSubmenu
(version 5 calls it chooseIntoSubmenu
) is fitted quite well for your needs.
That way you will only have one submenu representing the amount selection:
const amountMenu = new TelegrafInlineMenu(ctx => {
return 'How many ' + ctx.match[1] + ' do you want to get?'
})
amountMenu.select('pickAmount', [0, 1, 2, 3, 4, 5], {
setParentMenuAfter: true, // When the user hits a button the parent menu is opened -> no need to hit the back button then
setFunc: (ctx, key) => {
const product = ctx.match[1]
// pick one of the following, they are the same
const amount = Number(ctx.match[2])
const amount = Number(key)
// do your logic of storing the information
}
})
This menu is now independent from the actual drink. It works based on the ctx.match
information.
Now you can create a drink selection menu which enters the submenus.
const drinkMenu = new TelegrafInlineMenu('Want a drink?')
drinkMenu.selectSubmenu('drink', ['applejuice', 'mate', 'Tschunk', 'whatever drinks you have…'], amountMenu, {…})
That way you basically have another menu with a dynamic list of buttons, in this case of the array of your drinks (or a function returning the array).
Back to the pagination:
You could use menu.pagination
but the pagination feature is already built into select
and selectSubmenu
:
drinkMenu.selectSubmenu('drink', ctx => drinksCurrentlyInStock(), amountMenu, {
getCurrentPage: ctx => ctx.session.page,
setPage: (ctx, page) => {
ctx.session.page = page
}
})
That way the menu calls the getCurrentPage
whenever it needs to display the buttons and will call setPage when the user hits a button to go to a different page.
Also another tip for you: Telegraf simplifies the usage of the context for you. You can simplify ctx.update.callback_query
to ctx.callbackQuery
or ctx.update.callback_query.from
to ctx.from
which is a lot shorter to write.
Also you should not use the username as not all users have one and they can change it anytime. I suggest using ctx.from.id
instead as it is unique to the user.
Hope it helps :)
@EdJoPaTo Yes, it totally helped me, thanks a lot for such a detailed answer! In fact, you've made my code three times shorter and have given me some very useful tips.
Your library is by far the best out there for making bots with inline menus!
I'm making a bot for ordering drinks in a coffeeshop. The expected sequence of user actions is the following:
/start
go back
back button and gets taken to the drinks listconfirm
button and the collected data gets sent to the server.The list of drinks is stored in an array. The list of orders from different users is also stored locally (in memory) as I'm not expecting many orders at the same time. For sessions I use the
telegraf-session-local
package.The structure of the
orders
object is the following:So I generate the menu for the list of drinks in
forEach
and create a submenu for each drink, and then attach a submenu for choosing the quantity to each drink submenu.Given that the list of drinks is quite long, I need pagination so that on each page the user could see not more than 10 items.
However, after reading the issues and the docs I still can't understand how to implement such functionality in my case.
My current code is below:
(
menuItems
is an array like this[{name: "Drink1", key: "d", price: "10"}, {...},...]
)Could you please help me to get the pagination right?
This is how the code works right now: