Skip to content

Commit

Permalink
feat: implement /setinfo and /start commands
Browse files Browse the repository at this point in the history
  • Loading branch information
roziscoding committed Aug 21, 2022
1 parent 015ccdc commit c99422e
Show file tree
Hide file tree
Showing 15 changed files with 202 additions and 290 deletions.
52 changes: 52 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@commitlint/config-conventional": "^12.1.1",
"@semantic-release/changelog": "^5.0.1",
"@semantic-release/git": "^9.0.1",
"@types/common-tags": "^1.8.1",
"@types/mongodb": "^3.6.20",
"@types/node": "^15.0.1",
"@types/qrcode": "^1.4.0",
Expand Down Expand Up @@ -57,8 +58,10 @@
}
},
"dependencies": {
"@grammyjs/conversations": "^1.0.2",
"@grammyjs/router": "^2.0.0",
"axios": "^0.21.1",
"common-tags": "^1.8.2",
"dotenv": "^16.0.1",
"grammy": "^1.10.1",
"jimp": "^0.16.1",
Expand Down Expand Up @@ -92,4 +95,4 @@
"@semantic-release/git"
]
}
}
}
20 changes: 14 additions & 6 deletions src/bot.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { ConversationFlavor, conversations as grammyConversations } from '@grammyjs/conversations'
import { Bot, Context, session, SessionFlavor } from 'grammy'
import { start } from './commands'
import { cancel } from './commands/cancel'
import { cancel, setInfo, start } from './commands'
import { AppConfig } from './config'
import { WizardFlavor, wizards } from './util/wizard'
import setInfo from './wizards/set-info'
import * as conversations from './conversations'

export type AppSession = {
pixKey: string
Expand All @@ -12,7 +11,7 @@ export type AppSession = {
query?: string
}

export type AppContext = Context & SessionFlavor<AppSession> & WizardFlavor
export type AppContext = Context & SessionFlavor<AppSession> & ConversationFlavor

export async function getBot(config: AppConfig) {
const bot = new Bot<AppContext>(config.telegram.token)
Expand All @@ -28,10 +27,19 @@ export async function getBot(config: AppConfig) {
})
)

bot.use(...wizards([setInfo]))
bot.use(grammyConversations())

/** Cancel Command */
bot.command(cancel.name, cancel.fn)

/** Conversations */
bot.use(conversations.setInfo)

/** Regular commands */
bot.command(start.name, start.fn)
bot.command(setInfo.name, setInfo.fn)

bot.catch(console.error)

return bot
}
11 changes: 3 additions & 8 deletions src/commands/cancel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@ import { AppContext } from '../bot'
export const cancel = {
name: 'cancel',
helpText: 'Cancela a operação atual',
fn: (ctx: AppContext) => {
if (ctx.session.wizard?.id === 'setInfo') {
ctx.session.city = ''
ctx.session.name = ''
ctx.session.pixKey = ''
}
ctx.wizard.exit()
fn: async (ctx: AppContext) => {
delete ctx.session.query
return ctx.reply('Ok, deixa pra lá')
await ctx.reply('Tudo bem. Deixa pra lá :)', { reply_markup: { remove_keyboard: true } })
await ctx.conversation.exit()
}
}
2 changes: 2 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './cancel'
export * from './set-info'
export * from './start'
9 changes: 9 additions & 0 deletions src/commands/set-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { AppContext } from '../bot'

export const setInfo = {
name: 'setinfo',
helpText: 'Define suas informações',
fn: async (ctx: AppContext) => {
return ctx.conversation.enter('setInfo')
}
}
12 changes: 2 additions & 10 deletions src/commands/start.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { InlineKeyboard } from 'grammy'
import { evaluateQuery } from '../../old/handleInlineQuery'
import { AppContext } from '../bot'
import { User } from '../domain/User'
import { evaluateQuery } from '../old/handleInlineQuery'

const KNOWN_MESSAGE = (user: User) =>
`Opa, tudo certo? Eu já tenho seus dados do Pix aqui, olha só:
Expand All @@ -17,8 +17,6 @@ const KNOWN_MESSAGE_REQUESTED = (amount: string) => `
Para gerar um código de R$ ${amount} conforme solicitado, clique no botão abaixo.
`

const PRIVACY = `\n\n\\(Ao responder, você concorda com o armazenamento desses dados com o único propósito de gerar os códigos pix que você solicitar e de acordo com a [política de privacidade](https://github.com/roziscoding/amandapix-telegram-bot/blob/main/PRIVACY.md)\\)`

export const start = {
name: 'start',
helpText: 'Cria seu cadastro, caso ainda não exista',
Expand All @@ -40,12 +38,6 @@ export const start = {
}

if (query) ctx.session.query = query
ctx.wizard.enter('setInfo', { step: 1 })

const text = query
? `Opa, entendi que você quer gerar um código de ${query} mas, pra isso, primeiro me manda sua chave Pix:${PRIVACY}`
: `Opa, bora te cadastrar por aqui pra você poder gerar códigos Pix\\! Primeiro, me manda sua chave Pix:${PRIVACY}`

return ctx.reply(text, { disable_web_page_preview: true, parse_mode: 'MarkdownV2' })
return ctx.conversation.enter('setInfo')
}
}
1 change: 1 addition & 0 deletions src/conversations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as setInfo } from './set-info'
114 changes: 114 additions & 0 deletions src/conversations/set-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { Conversation, createConversation } from '@grammyjs/conversations'
import { oneLine, safeHtml, stripIndents } from 'common-tags'
import { InlineKeyboard, Keyboard } from 'grammy'
import { evaluateQuery } from '../../old/handleInlineQuery'
import { AppContext } from '../bot'

const PRIVACY_URL = 'https://github.com/roziscoding/amandapix-telegram-bot/blob/main/PRIVACY.md'

const confirm = new Keyboard().text('Sim').text('Não').oneTime()
const cancellable = (fn: (ctx: AppContext) => any) => (ctx: AppContext) => ctx.hasCommand('cancel') ?? fn(ctx)

const setInfo = async (conversation: Conversation<AppContext>, ctx: AppContext) => {
await ctx.reply(
oneLine`
Antes de começarmos, preciso que você leia minha [política de privacidade](${PRIVACY_URL})\\.
Você concorda com a política de privacidade? Você pode usar /cancel a qualquer momento pra encerrar a conversa\\.
`,
{ parse_mode: 'MarkdownV2', disable_web_page_preview: true, reply_markup: confirm }
)

const privacyPolicy = await conversation.form.select(
['Sim', 'Não'],
cancellable((ctx) => ctx.reply('Usa um dos botões pra me responder, por favor.'))
)

if (privacyPolicy === 'Não') {
await ctx.reply('Tudo bem. Deixa pra lá então.', { reply_markup: { remove_keyboard: true } })
return ctx.reply(
'Se quiser sugerir mudanças na minha política de privacidade, você pode abrir uma issue no meu repositório.',
{
reply_markup: new InlineKeyboard().url(
'Abrir issue',
'https://github.com/roziscoding/amandapix-telegram-bot/issues/new'
)
}
)
}

await ctx.reply('Boa! Agora sim, podemos começar!', { reply_markup: { remove_keyboard: true } })

await ctx.reply('Primeiro, me envia sua chave pix.')
const pixKey = await conversation.form.text(
cancellable((ctx) => ctx.reply('Me manda sua chave pix como texto, por favor!'))
)

await ctx.reply('Show. Agora me manda sua cidade, por favor')
const city = await conversation.form.text(
cancellable((ctx) => ctx.reply('Pra continuarmos, preciso que me mande sua cidade como texto'))
)

await ctx.reply('Boa. Por último, me diz seu nome')
const name = await conversation.form.text(
cancellable((ctx) => ctx.reply('Ainda não sei seu nome... Pode me mandar como texto, por favor?'))
)

await ctx.reply(
stripIndents(safeHtml)`
Boa! Então me confirma se tá tudo certo. Esses são os dados que eu anotei:
<b>Chave PIX</b>: ${pixKey}
<b>Cidade</b>: ${city}
<b>Nome</b>: ${name}
Tá correto?
`,
{ parse_mode: 'HTML', reply_markup: confirm.text('Cancelar Cadastro') }
)

const confirmation = await conversation.form.select(
['Sim', 'Não', 'Cancelar Cadastro'],
cancellable((ctx) => ctx.reply('Não entendi... Por favor, usa os botões pra me responder :)'))
)

if (confirmation === 'Cancelar Cadastro') {
return ctx.reply('OK. Deixa pra lá então. Espero poder ajudar numa próxima :)', {
reply_markup: { remove_keyboard: true }
})
}

if (confirmation === 'Não') {
await ctx.reply('Putz. Bora do começo então', { reply_markup: { remove_keyboard: true } })
return ctx.conversation.reenter('setInfo')
}

// ctx.session.pixKey = pixKey
// ctx.session.city = city
// ctx.session.name = name

await ctx.reply('Só mais um minuto...', { reply_markup: { remove_keyboard: true } })
await conversation.sleep(1000)

if (ctx.session.query) {
const amount = await evaluateQuery(ctx.session.query)
const keyboard = new InlineKeyboard().switchInline(`Gerar código Pix de R$ ${amount.toString()}`, ctx.session.query)
return ctx.reply(`Pronto! Agora tá tudo certo pra gerar o código Pix de ${amount} reais. É só clicar no botão:`, {
reply_markup: keyboard
})
}

const keyboard = new InlineKeyboard().switchInline(`Gerar código Pix`)
return ctx.reply(
stripIndents`
Pronto! Agora tá tudo certo pra gerar códigos Pix. Pra isso, é só clicar no botão aqui em baixo.
Você também pode digitar, em qualquer chat, <code>@amandapixbot 10</code>, trocando "10" pelo valor desejado, ou por uma operação matemática.
`,
{
parse_mode: 'HTML',
reply_markup: keyboard
}
)
}

export default createConversation<AppContext>(setInfo)
2 changes: 1 addition & 1 deletion src/util/pixCode.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { pix } from 'pix-me'
import { User } from '../old/domain/User'
import { User } from '../../old/domain/User'

export function getPixCodeForUser(user: User, value: string | number) {
return pix({
Expand Down
27 changes: 0 additions & 27 deletions src/util/telegram/sendMessage.ts

This file was deleted.

Loading

0 comments on commit c99422e

Please sign in to comment.