Skip to content

Instantly share code, notes, and snippets.

@waptik
Last active April 29, 2024 11:27
Show Gist options
  • Save waptik/1a57faa9a6aa89702c23ade43ad8a08f to your computer and use it in GitHub Desktop.
Save waptik/1a57faa9a6aa89702c23ade43ad8a08f to your computer and use it in GitHub Desktop.
An example on how to use grammY's Interactive Menus plugin
// I'm using deno
import "https://deno.land/std@0.178.0/dotenv/load.ts";
import { green } from "https://deno.land/std@0.178.0/fmt/colors.ts";
import { itemsMenu } from './menus/example.menu.ts';
const grammy = new Bot<GrammyContext>(Deno.env.get("BOT_TOKEN")||""); // replace `BOT_TOKEN` inside `.env` file with your own telegram bot's token
// attaching the menu to bot to get it to work if not we'll get the following errors inside the terminal
// `Error: Cannot send menu 'bot-items-menu'! Did you forget to use bot.use() for it?`
grammy.use(itemsMenu);
// setting up a command to bring the menu in action
grammy.command('items', async (ctx) => {
const text = `Here are the items we currently have:`;
return await ctx.replyWithHTML(text, {
reply_markup: itemsMenu,
});
});
grammy.start({
drop_pending_updates: false,
onStart: ({ username }) =>
console.log(`[bot] @${green(username)} is up and running 🦄`),
});
// Path: bot.ts
let pageIndex = 0;
/**
* A function that generates a paginated menu inspired by
* @see {@link https://github.com/ImOnlyFire/applications-bot/blob/main/bot/src/menus.ts#L41}
*
* @param index The index of the page to generate
* @returns A range of the menu
*/
function itemMenuRange(index: number, range: MenuRange<Context>) {
pageIndex = index;
// items is a dictionary of items such as a Macbook Pro or Air from 2016 to 2021 and an iPhone from 7 Plus to 12 Pro Max.
const items = {
mbp_2016: {
name: `Macbook Pro 13" 2016`,
message:
`An Apple Macbook Pro 13" 2016 with 16GB of RAM and 512GB of storage.`,
},
mbp_2017: {
name: `Macbook Pro 13" 2017`,
message:
`An Apple Macbook Pro 13" 2017 with 16GB of RAM and 512GB of storage.`,
},
mbp_2018: {
name: `Macbook Pro 13" 2018`,
message:
`An Apple Macbook Pro 13" 2018 with 16GB of RAM and 512GB of storage.`,
},
mbp_2019: {
name: `Macbook Pro 13" 2019`,
message:
`An Apple Macbook Pro 13" 2019 with 16GB of RAM and 512GB of storage.`,
},
mbp_2020: {
name: `Macbook Pro 13" 2020`,
message:
`An Apple Macbook Pro 13" 2020 with 16GB of RAM and 512GB of storage.`,
},
mbp_2021: {
name: `Macbook Pro 13" 2021`,
message:
`An Apple Macbook Pro 13" 2021 with 16GB of RAM and 512GB of storage.`,
},
iphone_7_plus: {
name: `iPhone 7 Plus`,
message:
`An Apple iPhone 7 Plus, black color with 256GB of storage.`,
},
iphone_8_plus: {
name: `iPhone 8 Plus`,
message:
`An Apple iPhone 8 Plus, black color with 256GB of storage.`,
},
iphone_x: {
name: `iPhone X`,
message:
`An Apple iPhone X, black color with 256GB of storage.`,
},
iphone_xr: {
name: `iPhone XR`,
message:
`An Apple iPhone XR, black color with 256GB of storage.`,
},
iphone_xs: {
name: `iPhone XS`,
message:
`An Apple iPhone XS, black color with 256GB of storage.`,
},
iphone_11: {
name: `iPhone 11`,
message:
`An Apple iPhone 11, black color with 256GB of storage.`,
},
iphone_11_pro: {
name: `iPhone 11 Pro`,
message:
`An Apple iPhone 11 Pro, black color with 256GB of storage.`,
},
iphone_11_pro_max: {
name: `iPhone 11 Pro Max`,
message:
`An Apple iPhone 11 Pro Max, black color with 256GB of storage.`,
},
iphone_12: {
name: `iPhone 12`,
message:
`An Apple iPhone 12, black color with 256GB of storage.`,
},
iphone_12_pro: {
name: `iPhone 12 Pro`,
message:
`An Apple iPhone 12 Pro, black color with 256GB of storage.`,
},
iphone_12_pro_max: {
name: `iPhone 12 Pro Max`,
message:
`An Apple iPhone 12 Pro Max, black color with 256GB of storage.`,
},
};
const itemsPerPage = 3;
const itemsKeys = Object.keys(items) as Array<
keyof typeof items
>;
const currentPagePersonasKeys = itemsKeys.slice(
pageIndex * itemsPerPage,
(pageIndex + 1) * itemsPerPage,
);
// Generate a part of the menu dynamically!
for (const itemKey of currentPagePersonasKeys) {
const item = items[itemKey];
range.text(item.name, async (ctx) => {
await ctx.editMessageText(item.message, {
parse_mode: 'HTML',
});
await ctx.menu.close();
}).row();
}
if (itemsKeys.length > itemsPerPage) {
const isFirstPage = pageIndex === 0;
const isLastPage = (pageIndex + 1) * itemsPerPage >= itemsKeys.length;
if (isFirstPage) {
range.submenu(
'👉',
`pagination-example-menu`,
() => {
pageIndex++;
},
);
} else if (isLastPage) {
range.submenu(
'👈',
`pagination-example-menu`,
() => {
pageIndex--;
},
);
} else {
range
.submenu(
'👈',
`pagination-example-menu`,
() => {
pageIndex--;
},
)
.submenu(
'👉',
`pagination-example-menu`,
() => {
pageIndex++;
},
);
}
}
return range;
}
export const itemsMenu = new Menu<Context>('bot-items-menu')
.dynamic((_, range) => itemMenuRange(0, range));
const paginationMenu = new Menu<Context>(
`pagination-example-menu`,
).dynamic((_, range) => itemMenuRange(pageIndex, range));
itemsMenu.register(paginationMenu);
// Path: menus/example.menu.ts
@waptik
Copy link
Author

waptik commented Apr 29, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment