From f4e5a496212d2e3961c17dda09be779ee5eddc9a Mon Sep 17 00:00:00 2001 From: whekin Date: Sun, 15 Mar 2026 01:17:22 +0400 Subject: [PATCH] feat(bot): restore /bind command and improve /setup welcoming experience --- apps/bot/src/household-setup.test.ts | 17 +- apps/bot/src/household-setup.ts | 314 +++++++-------------------- apps/bot/src/i18n/locales/en.ts | 58 ++--- apps/bot/src/i18n/locales/ru.ts | 58 ++--- apps/bot/src/i18n/types.ts | 30 +-- apps/bot/src/telegram-commands.ts | 5 - 6 files changed, 137 insertions(+), 345 deletions(-) diff --git a/apps/bot/src/household-setup.test.ts b/apps/bot/src/household-setup.test.ts index 2be96c9..3df9365 100644 --- a/apps/bot/src/household-setup.test.ts +++ b/apps/bot/src/household-setup.test.ts @@ -874,13 +874,14 @@ describe('registerHouseholdSetupCommands', () => { chat_id: -100123456 } }) - expect(sendPayload.text).toContain('Kojori House is ready!') - expect(sendPayload.text).toContain('Topics: 0/5 configured') - expect(sendPayload.text).toContain('⚪ purchases') - expect(sendPayload.text).toContain('⚪ payments') + expect(sendPayload.text).toContain('Welcome! Kojori House is successfully registered') + expect(sendPayload.text).toContain("Let's configure your household topics to get started") + expect(sendPayload.text).toContain('(0/5)') + expect(sendPayload.text).toContain('⚪ Purchases') + expect(sendPayload.text).toContain('⚪ Payments') // Check that join household button exists expect(JSON.stringify(sendPayload.reply_markup)).toContain('Join household') - expect(JSON.stringify(sendPayload.reply_markup)).toContain('+ purchases') + expect(JSON.stringify(sendPayload.reply_markup)).toContain('Setup Purchases') expect(JSON.stringify(sendPayload.reply_markup)).toContain('setup_topic:create:purchase') }) @@ -998,7 +999,7 @@ describe('registerHouseholdSetupCommands', () => { method: 'answerCallbackQuery', payload: { callback_query_id: 'callback-1', - text: 'purchases topic created and bound: Shared purchases.' + text: 'Purchases topic created and bound: Shared purchases.' } }) expect(calls[3]).toMatchObject({ @@ -1006,7 +1007,7 @@ describe('registerHouseholdSetupCommands', () => { payload: { chat_id: -100123456, message_id: 91, - text: expect.stringContaining('✅ purchases') + text: expect.stringContaining('✅ Purchases') } }) @@ -1134,7 +1135,7 @@ describe('registerHouseholdSetupCommands', () => { method: 'sendMessage', payload: { chat_id: -100123456, - text: 'Setup state reset for Kojori House. Run /setup again to bind topics from scratch.' + text: 'Setup state reset for Kojori House. Run /setup again to configure topics from scratch.' } }) expect(await repository.listHouseholdTopicBindings('household-1')).toEqual([]) diff --git a/apps/bot/src/household-setup.ts b/apps/bot/src/household-setup.ts index d98b129..4439afc 100644 --- a/apps/bot/src/household-setup.ts +++ b/apps/bot/src/household-setup.ts @@ -20,7 +20,7 @@ import { resolveReplyLocale } from './bot-locale' const APPROVE_MEMBER_CALLBACK_PREFIX = 'approve_member:' const SETUP_CREATE_TOPIC_CALLBACK_PREFIX = 'setup_topic:create:' -const SETUP_BIND_TOPIC_ACTION = 'setup_topic_binding' as const + const HOUSEHOLD_TOPIC_ROLE_ORDER: readonly HouseholdTopicRole[] = [ 'chat', 'purchase', @@ -39,11 +39,6 @@ function isGroupChat(ctx: Context): ctx is Context & { return ctx.chat?.type === 'group' || ctx.chat?.type === 'supergroup' } -function isTopicMessage(ctx: Context): boolean { - const message = ctx.msg - return !!message && 'is_topic_message' in message && message.is_topic_message === true -} - async function isGroupAdmin(ctx: Context): Promise { if (!ctx.chat || !ctx.from) { return false @@ -79,63 +74,6 @@ function unsetupRejectionMessage( } } -function bindRejectionMessage( - locale: BotLocale, - reason: 'not_admin' | 'household_not_found' | 'not_topic_message' -): string { - const t = getBotTranslations(locale).setup - switch (reason) { - case 'not_admin': - return t.onlyTelegramAdminsBindTopics - case 'household_not_found': - return t.householdNotConfigured - case 'not_topic_message': - return t.useCommandInTopic - } -} - -function bindTopicUsageMessage( - locale: BotLocale, - role: 'chat' | 'purchase' | 'feedback' | 'reminders' | 'payments' -): string { - const t = getBotTranslations(locale).setup - - switch (role) { - case 'chat': - return t.useBindChatTopicInGroup - case 'purchase': - return t.useBindPurchaseTopicInGroup - case 'feedback': - return t.useBindFeedbackTopicInGroup - case 'reminders': - return t.useBindRemindersTopicInGroup - case 'payments': - return t.useBindPaymentsTopicInGroup - } -} - -function bindTopicSuccessMessage( - locale: BotLocale, - role: 'chat' | 'purchase' | 'feedback' | 'reminders' | 'payments', - householdName: string, - threadId: string -): string { - const t = getBotTranslations(locale).setup - - switch (role) { - case 'chat': - return t.chatTopicSaved(householdName, threadId) - case 'purchase': - return t.purchaseTopicSaved(householdName, threadId) - case 'feedback': - return t.feedbackTopicSaved(householdName, threadId) - case 'reminders': - return t.remindersTopicSaved(householdName, threadId) - case 'payments': - return t.paymentsTopicSaved(householdName, threadId) - } -} - function adminRejectionMessage( locale: BotLocale, reason: 'not_admin' | 'household_not_found' | 'pending_not_found' @@ -473,63 +411,6 @@ export function registerHouseholdSetupCommands(options: { }) } - async function handleBindTopicCommand( - ctx: Context, - role: 'chat' | 'purchase' | 'feedback' | 'reminders' | 'payments' - ): Promise { - const locale = await resolveReplyLocale({ - ctx, - repository: options.householdConfigurationRepository - }) - - if (!isGroupChat(ctx)) { - await ctx.reply(bindTopicUsageMessage(locale, role)) - return - } - - const actorIsAdmin = await isGroupAdmin(ctx) - const telegramThreadId = - isTopicMessage(ctx) && ctx.msg && 'message_thread_id' in ctx.msg - ? ctx.msg.message_thread_id?.toString() - : undefined - const result = await options.householdSetupService.bindTopic({ - actorIsAdmin, - telegramChatId: ctx.chat.id.toString(), - role, - ...(telegramThreadId - ? { - telegramThreadId - } - : {}) - }) - - if (result.status === 'rejected') { - await ctx.reply(bindRejectionMessage(locale, result.reason)) - return - } - - options.logger?.info( - { - event: 'household_setup.topic_bound', - role: result.binding.role, - telegramChatId: result.household.telegramChatId, - telegramThreadId: result.binding.telegramThreadId, - householdId: result.household.householdId, - actorTelegramUserId: ctx.from?.id?.toString() - }, - 'Household topic bound' - ) - - await ctx.reply( - bindTopicSuccessMessage( - locale, - role, - result.household.householdName, - result.binding.telegramThreadId - ) - ) - } - options.bot.command('start', async (ctx) => { const fallbackLocale = await resolveReplyLocale({ ctx, @@ -714,7 +595,7 @@ export function registerHouseholdSetupCommands(options: { if (result.status === 'noop') { await options.promptRepository?.clearPendingActionsForChat( telegramChatId, - SETUP_BIND_TOPIC_ACTION + 'setup_topic_binding' ) await ctx.reply(t.setup.unsetupNoop) return @@ -722,7 +603,7 @@ export function registerHouseholdSetupCommands(options: { await options.promptRepository?.clearPendingActionsForChat( telegramChatId, - SETUP_BIND_TOPIC_ACTION + 'setup_topic_binding' ) options.logger?.info( @@ -738,103 +619,6 @@ export function registerHouseholdSetupCommands(options: { await ctx.reply(t.setup.unsetupComplete(result.household.householdName)) }) - options.bot.command('bind_chat_topic', async (ctx) => { - await handleBindTopicCommand(ctx, 'chat') - }) - - options.bot.command('bind_purchase_topic', async (ctx) => { - await handleBindTopicCommand(ctx, 'purchase') - }) - - options.bot.command('bind_feedback_topic', async (ctx) => { - await handleBindTopicCommand(ctx, 'feedback') - }) - - options.bot.command('bind_reminders_topic', async (ctx) => { - await handleBindTopicCommand(ctx, 'reminders') - }) - - options.bot.command('bind_payments_topic', async (ctx) => { - await handleBindTopicCommand(ctx, 'payments') - }) - - options.bot.command('bind', async (ctx) => { - const locale = await resolveReplyLocale({ - ctx, - repository: options.householdConfigurationRepository - }) - const t = getBotTranslations(locale) - - if (!isGroupChat(ctx)) { - await ctx.reply(t.setup.useBindInTopic) - return - } - - if (!options.householdConfigurationRepository) { - await ctx.reply(t.setup.householdNotConfigured) - return - } - - const household = await options.householdConfigurationRepository.getTelegramHouseholdChat( - ctx.chat.id.toString() - ) - if (!household) { - await ctx.reply(t.setup.householdNotConfigured) - return - } - - if (!(await isGroupAdmin(ctx))) { - await ctx.reply(t.setup.onlyTelegramAdminsBindTopics) - return - } - - const telegramThreadId = - ctx.msg && 'message_thread_id' in ctx.msg ? ctx.msg.message_thread_id?.toString() : null - - // If not in a topic, show error - if (!telegramThreadId) { - await ctx.reply(t.setup.useBindInTopic) - return - } - - // Check if this topic is already bound - const existingBinding = - await options.householdConfigurationRepository.findHouseholdTopicByTelegramContext({ - telegramChatId: ctx.chat.id.toString(), - telegramThreadId - }) - - if (existingBinding) { - const roleLabel = setupTopicRoleLabel(locale, existingBinding.role) - await ctx.reply(t.setup.topicAlreadyBound(roleLabel)) - return - } - - // Get all existing bindings to show which roles are available - const bindings = await options.householdConfigurationRepository.listHouseholdTopicBindings( - household.householdId - ) - const boundRoles = new Set(bindings.map((b) => b.role)) - const availableRoles = HOUSEHOLD_TOPIC_ROLE_ORDER.filter((role) => !boundRoles.has(role)) - - if (availableRoles.length === 0) { - await ctx.reply(t.setup.allRolesConfigured) - return - } - - // Show role selection buttons - await ctx.reply(t.setup.bindSelectRole, { - reply_markup: { - inline_keyboard: availableRoles.map((role) => [ - { - text: setupTopicRoleLabel(locale, role), - callback_data: `bind_topic:${role}:${telegramThreadId}` - } - ]) - } - }) - }) - options.bot.command('pending_members', async (ctx) => { const locale = await resolveReplyLocale({ ctx, @@ -974,6 +758,67 @@ export function registerHouseholdSetupCommands(options: { }) }) + options.bot.command('bind', async (ctx) => { + const locale = await resolveReplyLocale({ + ctx, + repository: options.householdConfigurationRepository + }) + const t = getBotTranslations(locale) + + if (!isGroupChat(ctx)) { + await ctx.reply(t.setup.useSetupInGroup) + return + } + + if (!ctx.message?.message_thread_id) { + await ctx.reply(t.setup.useCommandInTopic) + return + } + + const actorIsAdmin = await isGroupAdmin(ctx) + if (!actorIsAdmin) { + await ctx.reply(t.setup.onlyTelegramAdminsBindTopics) + return + } + + const telegramChatId = ctx.chat.id.toString() + const household = options.householdConfigurationRepository + ? await options.householdConfigurationRepository.getTelegramHouseholdChat(telegramChatId) + : null + + if (!household) { + await ctx.reply(t.setup.householdNotConfigured) + return + } + + const bindings = options.householdConfigurationRepository + ? await options.householdConfigurationRepository.listHouseholdTopicBindings( + household.householdId + ) + : [] + + const configuredRoles = new Set(bindings.map((b) => b.role)) + const availableRoles = HOUSEHOLD_TOPIC_ROLE_ORDER.filter((role) => !configuredRoles.has(role)) + + if (availableRoles.length === 0) { + await ctx.reply(t.setup.allRolesConfigured) + return + } + + const rows = availableRoles.map((role) => [ + { + text: setupTopicRoleLabel(locale, role), + callback_data: `bind_topic:${role}:${ctx.message!.message_thread_id}` + } + ]) + + await ctx.reply(t.setup.bindSelectRole, { + reply_markup: { + inline_keyboard: rows + } + }) + }) + options.bot.callbackQuery( new RegExp(`^${APPROVE_MEMBER_CALLBACK_PREFIX}(\\d+)$`), async (ctx) => { @@ -1095,7 +940,10 @@ export function registerHouseholdSetupCommands(options: { if (result.status === 'rejected') { await ctx.answerCallbackQuery({ - text: bindRejectionMessage(locale, result.reason), + text: + result.reason === 'not_admin' + ? t.onlyTelegramAdminsBindTopics + : t.householdNotConfigured, show_alert: true }) return @@ -1133,9 +981,8 @@ export function registerHouseholdSetupCommands(options: { } ) - // Bind topic callback from /bind command options.bot.callbackQuery( - new RegExp(`^bind_topic:(chat|purchase|feedback|reminders|payments):(\\d+)$`), + /^bind_topic:(chat|purchase|feedback|reminders|payments):(\d+)$/, async (ctx) => { const locale = await resolveReplyLocale({ ctx, @@ -1151,7 +998,11 @@ export function registerHouseholdSetupCommands(options: { return } + const role = ctx.match[1] as HouseholdTopicRole + const telegramThreadId = ctx.match[2]! + const telegramChatId = ctx.chat.id.toString() const actorIsAdmin = await isGroupAdmin(ctx) + if (!actorIsAdmin) { await ctx.answerCallbackQuery({ text: t.onlyTelegramAdminsBindTopics, @@ -1160,19 +1011,19 @@ export function registerHouseholdSetupCommands(options: { return } - const role = ctx.match[1] as HouseholdTopicRole - const telegramThreadId = ctx.match[2]! - const result = await options.householdSetupService.bindTopic({ actorIsAdmin, - telegramChatId: ctx.chat.id.toString(), + telegramChatId, telegramThreadId, role }) if (result.status === 'rejected') { await ctx.answerCallbackQuery({ - text: bindRejectionMessage(locale, result.reason), + text: + result.reason === 'not_admin' + ? t.onlyTelegramAdminsBindTopics + : t.householdNotConfigured, show_alert: true }) return @@ -1185,10 +1036,11 @@ export function registerHouseholdSetupCommands(options: { ) }) - // Edit the role selection message to show success - await ctx.editMessageText( - t.topicBoundSuccess(setupTopicRoleLabel(locale, role), result.household.householdName) - ) + if (ctx.msg) { + await ctx.editMessageText( + t.topicBoundSuccess(setupTopicRoleLabel(locale, role), result.household.householdName) + ) + } } ) } diff --git a/apps/bot/src/i18n/locales/en.ts b/apps/bot/src/i18n/locales/en.ts index 86aaa45..cdabba0 100644 --- a/apps/bot/src/i18n/locales/en.ts +++ b/apps/bot/src/i18n/locales/en.ts @@ -9,12 +9,7 @@ export const enBotTranslations: BotTranslationCatalog = { cancel: 'Cancel the current prompt', setup: 'Register this group as a household', unsetup: 'Reset topic setup for this group', - bind_chat_topic: 'Bind the current topic for casual conversation', - bind_purchase_topic: 'Bind the current topic as purchases', - bind_feedback_topic: 'Bind the current topic as feedback', - bind_reminders_topic: 'Bind the current topic as reminders', - bind_payments_topic: 'Bind the current topic as payments', - bind: 'Bind current topic to a household role', + bind: 'Bind current topic to a specific role', join_link: 'Get a shareable link for new members to join', payment_add: 'Record your rent or utilities payment', pending_members: 'List pending household join requests', @@ -56,12 +51,19 @@ export const enBotTranslations: BotTranslationCatalog = { joinRequestSent: (householdName) => `Join request sent for ${householdName}. Wait for a household admin to confirm you.`, setupSummary: ({ householdName, created }) => - `${created ? '✅' : 'ℹ️'} ${householdName} is ${created ? 'ready' : 'already registered'}!`, - setupTopicsHeading: (configured, total) => `Topics: ${configured}/${total} configured`, + `${created ? '✨' : 'ℹ️'} Welcome! ${householdName} is ${created ? 'successfully registered' : 'already active'} and ready to help.`, + setupTopicsHeading: (configured, total) => + `Let's configure your household topics to get started (${configured}/${total}):`, setupTopicBound: (role) => `✅ ${role}`, setupTopicMissing: (role) => `⚪ ${role}`, - setupTopicCreateButton: (role) => `+ ${role}`, + setupTopicCreateButton: (role) => `Setup ${role}`, setupTopicBindButton: (role) => `Bind ${role}`, + useBindInTopic: 'Run /bind inside a topic to link it to a role.', + topicAlreadyBound: (role) => `This topic is already linked to ${role}.`, + bindSelectRole: 'Link this topic to:', + topicBoundSuccess: (role, householdName) => + `Successfully linked as ${role} for ${householdName}.`, + allRolesConfigured: 'All topic roles are already configured.', setupTopicCreateFailed: 'I could not create that topic. Check bot admin permissions and forum settings.', setupTopicCreateForbidden: @@ -73,15 +75,15 @@ export const enBotTranslations: BotTranslationCatalog = { setupTopicBindRoleName: (role) => { switch (role) { case 'chat': - return 'chat' + return 'Discussions' case 'purchase': - return 'purchases' + return 'Purchases' case 'feedback': - return 'feedback' + return 'Feedback' case 'reminders': - return 'reminders' + return 'Reminders' case 'payments': - return 'payments' + return 'Payments' } }, setupTopicSuggestedName: (role) => { @@ -101,23 +103,8 @@ export const enBotTranslations: BotTranslationCatalog = { onlyTelegramAdminsUnsetup: 'Only Telegram group admins can run /unsetup.', useUnsetupInGroup: 'Use /unsetup inside the household group.', unsetupComplete: (householdName) => - `Setup state reset for ${householdName}. Run /setup again to bind topics from scratch.`, + `Setup state reset for ${householdName}. Run /setup again to configure topics from scratch.`, unsetupNoop: 'Nothing to reset for this group yet. Run /setup when you are ready.', - useBindChatTopicInGroup: 'Use /bind_chat_topic inside the household group topic.', - chatTopicSaved: (householdName, threadId) => - `Chat topic saved for ${householdName} (thread ${threadId}).`, - useBindPurchaseTopicInGroup: 'Use /bind_purchase_topic inside the household group topic.', - purchaseTopicSaved: (householdName, threadId) => - `Purchase topic saved for ${householdName} (thread ${threadId}).`, - useBindFeedbackTopicInGroup: 'Use /bind_feedback_topic inside the household group topic.', - feedbackTopicSaved: (householdName, threadId) => - `Feedback topic saved for ${householdName} (thread ${threadId}).`, - useBindRemindersTopicInGroup: 'Use /bind_reminders_topic inside the household group topic.', - remindersTopicSaved: (householdName, threadId) => - `Reminders topic saved for ${householdName} (thread ${threadId}).`, - useBindPaymentsTopicInGroup: 'Use /bind_payments_topic inside the household group topic.', - paymentsTopicSaved: (householdName, threadId) => - `Payments topic saved for ${householdName} (thread ${threadId}).`, usePendingMembersInGroup: 'Use /pending_members inside the household group.', useApproveMemberInGroup: 'Use /approve_member inside the household group.', approveMemberUsage: 'Usage: /approve_member ', @@ -130,12 +117,7 @@ export const enBotTranslations: BotTranslationCatalog = { useJoinLinkInGroup: 'Use /join_link inside the household group.', joinLinkUnavailable: 'Could not generate join link.', joinLinkReady: (link, householdName) => - `Join link for ${householdName}:\n${link}\n\nAnyone with this link can join the household. Share it carefully.`, - useBindInTopic: 'Use /bind inside a topic to bind it to a role.', - topicAlreadyBound: (role) => `This topic is already bound as ${role}.`, - bindSelectRole: 'Bind this topic as:', - topicBoundSuccess: (role, householdName) => `Bound as ${role} for ${householdName}.`, - allRolesConfigured: 'All topic roles are already configured.' + `Join link for ${householdName}:\n${link}\n\nAnyone with this link can join the household. Share it carefully.` }, anonymousFeedback: { title: 'Anonymous household note', @@ -147,7 +129,7 @@ export const enBotTranslations: BotTranslationCatalog = { multipleHouseholds: 'You belong to multiple households. Open the target household from its group until household selection is added.', feedbackTopicMissing: - 'Anonymous feedback is not configured for your household yet. Ask an admin to run /bind_feedback_topic.', + 'Anonymous feedback is not configured for your household yet. Ask an admin to run /setup and create a feedback topic.', duplicate: 'This anonymous feedback message was already processed.', delivered: 'Anonymous feedback delivered.', savedButPostFailed: 'Anonymous feedback was saved, but posting failed. Try again later.', @@ -325,7 +307,7 @@ export const enBotTranslations: BotTranslationCatalog = { }, payments: { topicMissing: - 'Payments topic is not configured for this household yet. Ask an admin to run /bind_payments_topic.', + 'Payments topic is not configured for this household yet. Ask an admin to run /setup and create a payments topic.', balanceReply: (kind) => kind === 'rent' ? 'Current rent payment guidance:' : 'Current utilities payment guidance:', proposal: (kind, amount, currency) => diff --git a/apps/bot/src/i18n/locales/ru.ts b/apps/bot/src/i18n/locales/ru.ts index 38fc42a..73bb1fb 100644 --- a/apps/bot/src/i18n/locales/ru.ts +++ b/apps/bot/src/i18n/locales/ru.ts @@ -9,12 +9,7 @@ export const ruBotTranslations: BotTranslationCatalog = { cancel: 'Отменить текущий ввод', setup: 'Подключить эту группу как дом', unsetup: 'Сбросить настройку топиков для этой группы', - bind_chat_topic: 'Назначить текущий топик для разговоров', - bind_purchase_topic: 'Назначить текущий топик для покупок', - bind_feedback_topic: 'Назначить текущий топик для анонимных сообщений', - bind_reminders_topic: 'Назначить текущий топик для напоминаний', - bind_payments_topic: 'Назначить текущий топик для оплат', - bind: 'Привязать текущий топик к роли дома', + bind: 'Привязать текущий топик к конкретной роли', join_link: 'Получить ссылку для приглашения новых участников', payment_add: 'Подтвердить оплату аренды или коммуналки', pending_members: 'Показать ожидающие заявки на вступление', @@ -58,12 +53,19 @@ export const ruBotTranslations: BotTranslationCatalog = { joinRequestSent: (householdName) => `Заявка на вступление в ${householdName} отправлена. Дождитесь подтверждения от админа дома.`, setupSummary: ({ householdName, created }) => - `${created ? '✅' : 'ℹ️'} ${householdName} ${created ? 'готов' : 'уже подключён'}!`, - setupTopicsHeading: (configured, total) => `Топики: ${configured}/${total} настроено`, + `${created ? '✨' : 'ℹ️'} Добро пожаловать! Дом ${householdName} ${created ? 'успешно зарегистрирован' : 'уже активен'} и готов к работе.`, + setupTopicsHeading: (configured, total) => + `Давайте настроим топики для вашего дома (${configured}/${total}):`, setupTopicBound: (role) => `✅ ${role}`, setupTopicMissing: (role) => `⚪ ${role}`, - setupTopicCreateButton: (role) => `+ ${role}`, + setupTopicCreateButton: (role) => `Настроить ${role}`, setupTopicBindButton: (role) => `Привязать ${role}`, + useBindInTopic: 'Используйте /bind внутри топика, чтобы привязать его к роли.', + topicAlreadyBound: (role) => `Этот топик уже привязан к роли «${role}».`, + bindSelectRole: 'Привязать этот топик к:', + topicBoundSuccess: (role, householdName) => + `Топик успешно привязан как «${role}» для ${householdName}.`, + allRolesConfigured: 'Все роли топиков уже настроены.', setupTopicCreateFailed: 'Не удалось создать этот топик. Проверьте права бота и включённые форум-топики в группе.', setupTopicCreateForbidden: @@ -75,15 +77,15 @@ export const ruBotTranslations: BotTranslationCatalog = { setupTopicBindRoleName: (role) => { switch (role) { case 'chat': - return 'разговоров' + return 'Общение' case 'purchase': - return 'покупки' + return 'Покупки' case 'feedback': - return 'обратной связи' + return 'Фидбек' case 'reminders': - return 'напоминаний' + return 'Напоминания' case 'payments': - return 'оплат' + return 'Оплаты' } }, setupTopicSuggestedName: (role) => { @@ -103,23 +105,8 @@ export const ruBotTranslations: BotTranslationCatalog = { onlyTelegramAdminsUnsetup: 'Только админы Telegram-группы могут запускать /unsetup.', useUnsetupInGroup: 'Используйте /unsetup внутри группы дома.', unsetupComplete: (householdName) => - `Состояние настройки для ${householdName} сброшено. Запустите /setup ещё раз, чтобы заново привязать топики.`, + `Состояние настройки для ${householdName} сброшено. Запустите /setup ещё раз, чтобы заново настроить топики.`, unsetupNoop: 'Для этой группы пока нечего сбрасывать. Когда будете готовы, запустите /setup.', - useBindChatTopicInGroup: 'Используйте /bind_chat_topic внутри топика группы дома.', - chatTopicSaved: (householdName, threadId) => - `Топик для разговоров сохранён для ${householdName} (тред ${threadId}).`, - useBindPurchaseTopicInGroup: 'Используйте /bind_purchase_topic внутри топика группы дома.', - purchaseTopicSaved: (householdName, threadId) => - `Топик покупок сохранён для ${householdName} (тред ${threadId}).`, - useBindFeedbackTopicInGroup: 'Используйте /bind_feedback_topic внутри топика группы дома.', - feedbackTopicSaved: (householdName, threadId) => - `Топик обратной связи сохранён для ${householdName} (тред ${threadId}).`, - useBindRemindersTopicInGroup: 'Используйте /bind_reminders_topic внутри топика группы дома.', - remindersTopicSaved: (householdName, threadId) => - `Топик напоминаний сохранён для ${householdName} (тред ${threadId}).`, - useBindPaymentsTopicInGroup: 'Используйте /bind_payments_topic внутри топика группы дома.', - paymentsTopicSaved: (householdName, threadId) => - `Топик оплат сохранён для ${householdName} (тред ${threadId}).`, usePendingMembersInGroup: 'Используйте /pending_members внутри группы дома.', useApproveMemberInGroup: 'Используйте /approve_member внутри группы дома.', approveMemberUsage: 'Использование: /approve_member ', @@ -132,12 +119,7 @@ export const ruBotTranslations: BotTranslationCatalog = { useJoinLinkInGroup: 'Используйте /join_link внутри группы дома.', joinLinkUnavailable: 'Не удалось сгенерировать ссылку для вступления.', joinLinkReady: (link, householdName) => - `Поделитесь этой ссылкой, чтобы пригласить участников в ${householdName}:\n\n${link}\n\nЛюбой, у кого есть эта ссылка, может подать заявку на вступление.`, - useBindInTopic: 'Используйте /bind внутри топика, чтобы привязать его к роли.', - topicAlreadyBound: (role) => `Этот топик уже привязан как ${role}.`, - bindSelectRole: 'Привязать этот топик как:', - topicBoundSuccess: (role, householdName) => `Привязан как ${role} для ${householdName}.`, - allRolesConfigured: 'Все роли топиков уже настроены.' + `Поделитесь этой ссылкой, чтобы пригласить участников в ${householdName}:\n\n${link}\n\nЛюбой, у кого есть эта ссылка, может подать заявку на вступление.` }, anonymousFeedback: { title: 'Анонимное сообщение по дому', @@ -149,7 +131,7 @@ export const ruBotTranslations: BotTranslationCatalog = { multipleHouseholds: 'Вы состоите в нескольких домах. Откройте нужный дом из его группы, пока выбор дома ещё не добавлен.', feedbackTopicMissing: - 'Для вашего дома ещё не настроен анонимный топик. Попросите админа выполнить /bind_feedback_topic.', + 'Для вашего дома ещё не настроен анонимный топик. Попросите админа выполнить /setup и создать топик для обратной связи.', duplicate: 'Это анонимное сообщение уже было обработано.', delivered: 'Анонимное сообщение отправлено.', savedButPostFailed: @@ -329,7 +311,7 @@ export const ruBotTranslations: BotTranslationCatalog = { }, payments: { topicMissing: - 'Для этого дома ещё не настроен топик оплат. Попросите админа выполнить /bind_payments_topic.', + 'Для этого дома ещё не настроен топик оплат. Попросите админа выполнить /setup и создать топик для оплат.', balanceReply: (kind) => kind === 'rent' ? 'Текущая сводка по аренде:' : 'Текущая сводка по коммуналке:', proposal: (kind, amount, currency) => diff --git a/apps/bot/src/i18n/types.ts b/apps/bot/src/i18n/types.ts index 9400a44..0f0b969 100644 --- a/apps/bot/src/i18n/types.ts +++ b/apps/bot/src/i18n/types.ts @@ -8,11 +8,6 @@ export type TelegramCommandName = | 'setup' | 'unsetup' | 'bind' - | 'bind_chat_topic' - | 'bind_purchase_topic' - | 'bind_feedback_topic' - | 'bind_reminders_topic' - | 'bind_payments_topic' | 'join_link' | 'payment_add' | 'pending_members' @@ -25,11 +20,6 @@ export interface BotCommandDescriptions { cancel: string setup: string unsetup: string - bind_chat_topic: string - bind_purchase_topic: string - bind_feedback_topic: string - bind_reminders_topic: string - bind_payments_topic: string bind: string join_link: string payment_add: string @@ -100,16 +90,11 @@ export interface BotTranslationCatalog { useUnsetupInGroup: string unsetupComplete: (householdName: string) => string unsetupNoop: string - useBindChatTopicInGroup: string - chatTopicSaved: (householdName: string, threadId: string) => string - useBindPurchaseTopicInGroup: string - purchaseTopicSaved: (householdName: string, threadId: string) => string - useBindFeedbackTopicInGroup: string - feedbackTopicSaved: (householdName: string, threadId: string) => string - useBindRemindersTopicInGroup: string - remindersTopicSaved: (householdName: string, threadId: string) => string - useBindPaymentsTopicInGroup: string - paymentsTopicSaved: (householdName: string, threadId: string) => string + useBindInTopic: string + topicAlreadyBound: (role: string) => string + bindSelectRole: string + topicBoundSuccess: (role: string, householdName: string) => string + allRolesConfigured: string usePendingMembersInGroup: string useApproveMemberInGroup: string approveMemberUsage: string @@ -121,11 +106,6 @@ export interface BotTranslationCatalog { useJoinLinkInGroup: string joinLinkUnavailable: string joinLinkReady: (link: string, householdName: string) => string - useBindInTopic: string - topicAlreadyBound: (role: string) => string - bindSelectRole: string - topicBoundSuccess: (role: string, householdName: string) => string - allRolesConfigured: string } anonymousFeedback: { title: string diff --git a/apps/bot/src/telegram-commands.ts b/apps/bot/src/telegram-commands.ts index 44a9282..f686a7a 100644 --- a/apps/bot/src/telegram-commands.ts +++ b/apps/bot/src/telegram-commands.ts @@ -36,11 +36,6 @@ const GROUP_ADMIN_COMMAND_NAMES = [ 'setup', 'unsetup', 'bind', - 'bind_chat_topic', - 'bind_purchase_topic', - 'bind_feedback_topic', - 'bind_reminders_topic', - 'bind_payments_topic', 'join_link', 'pending_members', 'approve_member'