// bot.js
import { Bot, defineBot, flow, isMainModule } from '@botmesh/core'
import { BaileysProvider } from '@botmesh/baileys'
const PRICES = { small: 8, medium: 10, large: 12 }
const createBot = defineBot((provider) => {
const bot = new Bot({ provider })
// A sub-flow with no trigger of its own: the main menu runs it
const order = flow([])
.choose('Which size?', { small: 'Small ($8)', medium: 'Medium ($10)', large: 'Large ($12)' }, 'size')
.choose('Which flavour?', { margherita: 'Margherita', pepperoni: 'Pepperoni', veggie: 'Veggie' }, 'flavour')
.say((_ctx, c) => `✅ One ${c.state.size} ${c.state.flavour}: $${PRICES[c.state.size]}. Ready in 20 minutes!`)
// Numbered menu: works everywhere, WhatsApp via Baileys included
bot.use(
flow('menu').choose('🍕 *Pizza Place*: what would you like?', {
order: { label: 'Order a pizza', then: order },
hours: { label: 'Opening hours', then: (_ctx, c) => c.say('🕘 Every day, 12:00 to 23:00.') },
}),
)
// Native buttons where the channel renders them (Telegram, WhatsApp Cloud API),
// the same question as a numbered menu everywhere else
bot.conversation('rate', async (c, ctx) => {
const options = { great: '😋 Great', ok: '🙂 OK', meh: '😕 Meh' }
let answer
if (ctx.capabilities?.buttons) {
await ctx.buttons('How was your pizza?', Object.entries(options).map(([id, title]) => ({ id, title })))
answer = (await c.waitAny()).body // a tap arrives as a message whose text is the button id
} else {
answer = await c.choose('How was your pizza?', options)
}
await ctx.reply(Object.hasOwn(options, answer) ? `Thanks for rating us ${options[answer]}!` : 'Thanks for your feedback!')
})
bot.onMessage((ctx) => ctx.reply('Send "menu" to order or "rate" to rate us.'))
return bot
})
export default createBot
// `node bot.js` connects to WhatsApp; `npx botmesh dev bot.js` skips this block
if (isMainModule(import.meta)) {
const bot = await createBot(new BaileysProvider({ session: 'menu-bot' }))
bot.on('ready', () => console.log('✅ Connected. Send "menu" from another phone.'))
await bot.start()
}