Skip to content

Commit

Permalink
feat: update phrases, update /start command, add /menu command
Browse files Browse the repository at this point in the history
  • Loading branch information
evermake committed Apr 7, 2024
1 parent cab2d55 commit f588326
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 47 deletions.
6 changes: 3 additions & 3 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
"@grammyjs/auto-retry": "^1.1.1",
"@grammyjs/runner": "^2.0.3",
"@prisma/client": "5.11.0",
"@telegum/grammy-buttons": "^0.4.0",
"@telegum/grammy-messages": "^0.4.0",
"@telegum/tgx": "^0.1.1",
"@telegum/grammy-buttons": "^0.5.1",
"@telegum/grammy-messages": "^0.5.1",
"@telegum/tgx": "^0.2.1",
"axios": "^1.6.8",
"dotenv": "^16.4.5",
"grammy": "^1.22.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import views from '~/bot/handlers/views'

export default handler((composer) => {
composer
.command('start')
.command('menu')
.filter(filters.pm)
.use(async (ctx) => {
await ctx
Expand Down
49 changes: 49 additions & 0 deletions backend/src/bot/handlers/commands/start.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import views from '~/bot/handlers/views'
import { handler } from '~/bot/handlers'
import filters from '~/bot/filters'
import { TelegramNotLinkedToInnohassleAccountError } from '~/domain/errors'
import { InnohassleLoginButton } from '~/bot/login-button'

export default handler((composer) => {
composer
.command('start')
.filter(filters.pm)
.use(async (ctx) => {
let authorized
try {
authorized = await ctx.domain.isUserAuthorized(ctx.from.id)
} catch (error) {
authorized = false
if (error instanceof TelegramNotLinkedToInnohassleAccountError) {
// ignore
} else {
ctx.logger.error({
msg: 'failed to check whether user is authorized',
error: error,
})
}
}

let content
if (authorized) {
content = await views.main.render(ctx, {})
} else {
content = (
<>
{ctx.t['WelcomeMessage.Unauthorized']}
<keyboard>
<InnohassleLoginButton
loginUrl={ctx.config.innohassle.telegramLoginUrl}
loginBotUsername={ctx.config.innohassle.telegramBotUsername}
returnBotUsername={ctx.me.username}
>
{ctx.t['Buttons.LoginWithInnohassle']}
</InnohassleLoginButton>
</keyboard>
</>
)
}

await ctx.send(content).to(ctx.chat.id)
})
})
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
import { InlineKeyboard } from 'grammy'
import commands from './commands'
import views from './views'
import { handler } from '.'
import { TelegramNotLinkedToInnohassleAccountError } from '~/domain/errors'
import { InnohassleLoginButton } from '~/bot/login-button'

export default handler((composer) => {
composer = composer.errorBoundary(async (err) => {
if (err.error instanceof TelegramNotLinkedToInnohassleAccountError) {
const ctx = err.ctx
const loginUrl = new URL(ctx.config.innohassle.telegramLoginUrl)
loginUrl.searchParams.set('bot', `${ctx.me.username}?start=_`)
await ctx.reply(ctx.t['InNoHassle.LinkAccountsRequest.Message'], {
reply_markup: new InlineKeyboard([[
{
text: ctx.t['InNoHassle.LinkAccountsRequest.Button'],
login_url: {
url: loginUrl.toString(),
bot_username: ctx.config.innohassle.telegramBotUsername,
forward_text: ctx.t['InNoHassle.LinkAccountsRequest.ForwardText'],
},
},
]]),
})
await ctx
.send(
<InnohassleLoginButton
loginUrl={ctx.config.innohassle.telegramLoginUrl}
loginBotUsername={ctx.config.innohassle.telegramBotUsername}
returnBotUsername={ctx.me.username}
>
{ctx.t['Buttons.LoginWithInnohassle']}
</InnohassleLoginButton>,
)
.to(ctx.chat!.id)
} else {
throw err.error
}
Expand Down
24 changes: 24 additions & 0 deletions backend/src/bot/login-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export function InnohassleLoginButton({
loginUrl: loginUrlStr,
loginBotUsername,
returnBotUsername,
children,
}: {
loginUrl: string
loginBotUsername: string
returnBotUsername: string
children: string
}) {
const loginUrl = new URL(loginUrlStr)
loginUrl.searchParams.set('bot', `${returnBotUsername}?start=_`)
return (
<button
loginUrl={{
url: loginUrl.toString(),
bot_username: loginBotUsername,
}}
>
{children}
</button>
)
}
4 changes: 4 additions & 0 deletions backend/src/domain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ export class Domain {
})
}

public async isUserAuthorized(telegramId: number): Promise<boolean> {
return !!(await this.getUserSportData(telegramId))
}

private async requestSport<M extends keyof SportClient>(
telegramId: number,
method: M,
Expand Down
34 changes: 22 additions & 12 deletions backend/src/translations/_en.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,26 @@ import { tgxFromHtml } from '~/utils/tgx-from-html'
function dateLong(date: Date): string {
const day = date.toLocaleDateString('en-US', { weekday: 'long', timeZone: TIMEZONE })
const month = date.toLocaleDateString('en-US', { month: 'long', timeZone: TIMEZONE })
const dayOfMonth = date.getDate()
const year = date.getFullYear()
const dayOfMonth = date.toLocaleDateString('en-US', { day: 'numeric', timeZone: TIMEZONE })
const year = date.toLocaleDateString('en-US', { year: 'numeric', timeZone: TIMEZONE })

return `${day}, ${month} ${dayOfMonth}, ${year}`
}

function dateAndTimeShort(
startsAt: Date,
endsAt: Date,
): string {
const weekDayShort = startsAt.toLocaleDateString('en-US', { weekday: 'short', timeZone: TIMEZONE })
const monthShort = startsAt.toLocaleDateString('en-US', { month: 'short', timeZone: TIMEZONE })
const dayOfMonth = startsAt.toLocaleDateString('en-US', { day: 'numeric', timeZone: TIMEZONE })

return `${weekDayShort} ${monthShort} ${dayOfMonth}, ${clockTime(startsAt, TIMEZONE)}${clockTime(endsAt, TIMEZONE)}`
}

export default {
'WelcomeMessage.Unauthorized': 'Welcome to IU Sport Bot.\n\nPlease, login:',

'Weekday.TwoLetters': (weekday: Weekday) => {
switch (weekday) {
case 'mon': return 'Mo'
Expand All @@ -27,20 +40,21 @@ export default {
},

'Buttons.Back': '← Back',
'Buttons.LoginWithInnohassle': 'Login with InNoHassle',

'HowGoodAmI.Thinking': 'Hmm... Let me think 🤔',
'HowGoodAmI.Answer': (percent: number) => `You're better than ${percent}% of students!`,
'HowGoodAmI.Failed': 'I don\'t know 🤷‍♂️',

'Alert.CheckInSuccessful': (training: TrainingDetailed) => [
'✅ Check-in successful',
'Alert.CheckInSuccessful': ({ title, startsAt, endsAt }: TrainingDetailed) => [
'✅ Check-in successful',
'',
`${training.title} at ${training.startsAt}`,
`${title}\n${dateAndTimeShort(startsAt, endsAt)}`,
].join('\n'),
'Alert.CheckInCancelled': (training: TrainingDetailed) => [
'❌ Check-in cancelled',
'Alert.CheckInCancelled': ({ title, startsAt, endsAt }: TrainingDetailed) => [
'❌ Check-in cancelled',
'',
`${training.title} at ${training.startsAt}`,
`${title}\n${dateAndTimeShort(startsAt, endsAt)}`,
].join('\n'),
'Alert.CheckInUnavailable': 'You cannot check-in for this training.',
'Alert.AlreadyCheckedIn': 'You are already checked in for this training.',
Expand Down Expand Up @@ -103,8 +117,4 @@ export default {
),
'Views.Training.Buttons.CheckIn': 'Check-in',
'Views.Training.Buttons.CancelCheckIn': 'Cancel check-in',

'InNoHassle.LinkAccountsRequest.Message': 'To use this Telegram bot, please login to InNoHassle with your Telegram account. When you\'re done, send /start to continue!',
'InNoHassle.LinkAccountsRequest.Button': 'Login with InNoHassle',
'InNoHassle.LinkAccountsRequest.ForwardText': 'Link your Telegram to InNoHassle.',
}
32 changes: 16 additions & 16 deletions pnpm-lock.yaml

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

0 comments on commit f588326

Please sign in to comment.