mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 17:44:03 +00:00
feat: add chat topic binding for casual conversation
Add ability to bind a dedicated chat topic where normal conversation happens, separate from functional topics (purchases, payments, etc.) - Add 'chat' to HOUSEHOLD_TOPIC_ROLES - Add /bind_chat_topic command for admins - Update i18n strings for en/ru - Add command to admin scope in telegram-commands
This commit is contained in:
@@ -28,6 +28,7 @@ const GROUP_INVITE_TTL_MS = 3 * 24 * 60 * 60 * 1000
|
|||||||
const SETUP_BIND_TOPIC_ACTION = 'setup_topic_binding' as const
|
const SETUP_BIND_TOPIC_ACTION = 'setup_topic_binding' as const
|
||||||
const SETUP_BIND_TOPIC_TTL_MS = 10 * 60 * 1000
|
const SETUP_BIND_TOPIC_TTL_MS = 10 * 60 * 1000
|
||||||
const HOUSEHOLD_TOPIC_ROLE_ORDER: readonly HouseholdTopicRole[] = [
|
const HOUSEHOLD_TOPIC_ROLE_ORDER: readonly HouseholdTopicRole[] = [
|
||||||
|
'chat',
|
||||||
'purchase',
|
'purchase',
|
||||||
'feedback',
|
'feedback',
|
||||||
'reminders',
|
'reminders',
|
||||||
@@ -106,11 +107,13 @@ function bindRejectionMessage(
|
|||||||
|
|
||||||
function bindTopicUsageMessage(
|
function bindTopicUsageMessage(
|
||||||
locale: BotLocale,
|
locale: BotLocale,
|
||||||
role: 'purchase' | 'feedback' | 'reminders' | 'payments'
|
role: 'chat' | 'purchase' | 'feedback' | 'reminders' | 'payments'
|
||||||
): string {
|
): string {
|
||||||
const t = getBotTranslations(locale).setup
|
const t = getBotTranslations(locale).setup
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
case 'chat':
|
||||||
|
return t.useBindChatTopicInGroup
|
||||||
case 'purchase':
|
case 'purchase':
|
||||||
return t.useBindPurchaseTopicInGroup
|
return t.useBindPurchaseTopicInGroup
|
||||||
case 'feedback':
|
case 'feedback':
|
||||||
@@ -124,13 +127,15 @@ function bindTopicUsageMessage(
|
|||||||
|
|
||||||
function bindTopicSuccessMessage(
|
function bindTopicSuccessMessage(
|
||||||
locale: BotLocale,
|
locale: BotLocale,
|
||||||
role: 'purchase' | 'feedback' | 'reminders' | 'payments',
|
role: 'chat' | 'purchase' | 'feedback' | 'reminders' | 'payments',
|
||||||
householdName: string,
|
householdName: string,
|
||||||
threadId: string
|
threadId: string
|
||||||
): string {
|
): string {
|
||||||
const t = getBotTranslations(locale).setup
|
const t = getBotTranslations(locale).setup
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
case 'chat':
|
||||||
|
return t.chatTopicSaved(householdName, threadId)
|
||||||
case 'purchase':
|
case 'purchase':
|
||||||
return t.purchaseTopicSaved(householdName, threadId)
|
return t.purchaseTopicSaved(householdName, threadId)
|
||||||
case 'feedback':
|
case 'feedback':
|
||||||
@@ -358,7 +363,11 @@ function setupReply(input: {
|
|||||||
|
|
||||||
function isHouseholdTopicRole(value: string): value is HouseholdTopicRole {
|
function isHouseholdTopicRole(value: string): value is HouseholdTopicRole {
|
||||||
return (
|
return (
|
||||||
value === 'purchase' || value === 'feedback' || value === 'reminders' || value === 'payments'
|
value === 'chat' ||
|
||||||
|
value === 'purchase' ||
|
||||||
|
value === 'feedback' ||
|
||||||
|
value === 'reminders' ||
|
||||||
|
value === 'payments'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,7 +656,7 @@ export function registerHouseholdSetupCommands(options: {
|
|||||||
|
|
||||||
async function handleBindTopicCommand(
|
async function handleBindTopicCommand(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
role: 'purchase' | 'feedback' | 'reminders' | 'payments'
|
role: 'chat' | 'purchase' | 'feedback' | 'reminders' | 'payments'
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const locale = await resolveReplyLocale({
|
const locale = await resolveReplyLocale({
|
||||||
ctx,
|
ctx,
|
||||||
@@ -1129,6 +1138,10 @@ export function registerHouseholdSetupCommands(options: {
|
|||||||
await ctx.reply(t.setup.unsetupComplete(result.household.householdName))
|
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) => {
|
options.bot.command('bind_purchase_topic', async (ctx) => {
|
||||||
await handleBindTopicCommand(ctx, 'purchase')
|
await handleBindTopicCommand(ctx, 'purchase')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export const enBotTranslations: BotTranslationCatalog = {
|
|||||||
cancel: 'Cancel the current prompt',
|
cancel: 'Cancel the current prompt',
|
||||||
setup: 'Register this group as a household',
|
setup: 'Register this group as a household',
|
||||||
unsetup: 'Reset topic setup for this group',
|
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_purchase_topic: 'Bind the current topic as purchases',
|
||||||
bind_feedback_topic: 'Bind the current topic as feedback',
|
bind_feedback_topic: 'Bind the current topic as feedback',
|
||||||
bind_reminders_topic: 'Bind the current topic as reminders',
|
bind_reminders_topic: 'Bind the current topic as reminders',
|
||||||
@@ -76,6 +77,8 @@ export const enBotTranslations: BotTranslationCatalog = {
|
|||||||
setupTopicBindNotAvailable: 'That topic-binding action is no longer available.',
|
setupTopicBindNotAvailable: 'That topic-binding action is no longer available.',
|
||||||
setupTopicBindRoleName: (role) => {
|
setupTopicBindRoleName: (role) => {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
case 'chat':
|
||||||
|
return 'chat'
|
||||||
case 'purchase':
|
case 'purchase':
|
||||||
return 'purchases'
|
return 'purchases'
|
||||||
case 'feedback':
|
case 'feedback':
|
||||||
@@ -88,6 +91,8 @@ export const enBotTranslations: BotTranslationCatalog = {
|
|||||||
},
|
},
|
||||||
setupTopicSuggestedName: (role) => {
|
setupTopicSuggestedName: (role) => {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
case 'chat':
|
||||||
|
return 'Chat'
|
||||||
case 'purchase':
|
case 'purchase':
|
||||||
return 'Shared purchases'
|
return 'Shared purchases'
|
||||||
case 'feedback':
|
case 'feedback':
|
||||||
@@ -103,6 +108,9 @@ export const enBotTranslations: BotTranslationCatalog = {
|
|||||||
unsetupComplete: (householdName) =>
|
unsetupComplete: (householdName) =>
|
||||||
`Setup state reset for ${householdName}. Run /setup again to bind topics from scratch.`,
|
`Setup state reset for ${householdName}. Run /setup again to bind topics from scratch.`,
|
||||||
unsetupNoop: 'Nothing to reset for this group yet. Run /setup when you are ready.',
|
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.',
|
useBindPurchaseTopicInGroup: 'Use /bind_purchase_topic inside the household group topic.',
|
||||||
purchaseTopicSaved: (householdName, threadId) =>
|
purchaseTopicSaved: (householdName, threadId) =>
|
||||||
`Purchase topic saved for ${householdName} (thread ${threadId}).`,
|
`Purchase topic saved for ${householdName} (thread ${threadId}).`,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export const ruBotTranslations: BotTranslationCatalog = {
|
|||||||
cancel: 'Отменить текущий ввод',
|
cancel: 'Отменить текущий ввод',
|
||||||
setup: 'Подключить эту группу как дом',
|
setup: 'Подключить эту группу как дом',
|
||||||
unsetup: 'Сбросить настройку топиков для этой группы',
|
unsetup: 'Сбросить настройку топиков для этой группы',
|
||||||
|
bind_chat_topic: 'Назначить текущий топик для разговоров',
|
||||||
bind_purchase_topic: 'Назначить текущий топик для покупок',
|
bind_purchase_topic: 'Назначить текущий топик для покупок',
|
||||||
bind_feedback_topic: 'Назначить текущий топик для анонимных сообщений',
|
bind_feedback_topic: 'Назначить текущий топик для анонимных сообщений',
|
||||||
bind_reminders_topic: 'Назначить текущий топик для напоминаний',
|
bind_reminders_topic: 'Назначить текущий топик для напоминаний',
|
||||||
@@ -78,6 +79,8 @@ export const ruBotTranslations: BotTranslationCatalog = {
|
|||||||
setupTopicBindNotAvailable: 'Это действие привязки топика уже недоступно.',
|
setupTopicBindNotAvailable: 'Это действие привязки топика уже недоступно.',
|
||||||
setupTopicBindRoleName: (role) => {
|
setupTopicBindRoleName: (role) => {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
case 'chat':
|
||||||
|
return 'разговоров'
|
||||||
case 'purchase':
|
case 'purchase':
|
||||||
return 'покупки'
|
return 'покупки'
|
||||||
case 'feedback':
|
case 'feedback':
|
||||||
@@ -90,6 +93,8 @@ export const ruBotTranslations: BotTranslationCatalog = {
|
|||||||
},
|
},
|
||||||
setupTopicSuggestedName: (role) => {
|
setupTopicSuggestedName: (role) => {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
case 'chat':
|
||||||
|
return 'Разговоры'
|
||||||
case 'purchase':
|
case 'purchase':
|
||||||
return 'Общие покупки'
|
return 'Общие покупки'
|
||||||
case 'feedback':
|
case 'feedback':
|
||||||
@@ -105,6 +110,9 @@ export const ruBotTranslations: BotTranslationCatalog = {
|
|||||||
unsetupComplete: (householdName) =>
|
unsetupComplete: (householdName) =>
|
||||||
`Состояние настройки для ${householdName} сброшено. Запустите /setup ещё раз, чтобы заново привязать топики.`,
|
`Состояние настройки для ${householdName} сброшено. Запустите /setup ещё раз, чтобы заново привязать топики.`,
|
||||||
unsetupNoop: 'Для этой группы пока нечего сбрасывать. Когда будете готовы, запустите /setup.',
|
unsetupNoop: 'Для этой группы пока нечего сбрасывать. Когда будете готовы, запустите /setup.',
|
||||||
|
useBindChatTopicInGroup: 'Используйте /bind_chat_topic внутри топика группы дома.',
|
||||||
|
chatTopicSaved: (householdName, threadId) =>
|
||||||
|
`Топик для разговоров сохранён для ${householdName} (тред ${threadId}).`,
|
||||||
useBindPurchaseTopicInGroup: 'Используйте /bind_purchase_topic внутри топика группы дома.',
|
useBindPurchaseTopicInGroup: 'Используйте /bind_purchase_topic внутри топика группы дома.',
|
||||||
purchaseTopicSaved: (householdName, threadId) =>
|
purchaseTopicSaved: (householdName, threadId) =>
|
||||||
`Топик покупок сохранён для ${householdName} (тред ${threadId}).`,
|
`Топик покупок сохранён для ${householdName} (тред ${threadId}).`,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export type TelegramCommandName =
|
|||||||
| 'cancel'
|
| 'cancel'
|
||||||
| 'setup'
|
| 'setup'
|
||||||
| 'unsetup'
|
| 'unsetup'
|
||||||
|
| 'bind_chat_topic'
|
||||||
| 'bind_purchase_topic'
|
| 'bind_purchase_topic'
|
||||||
| 'bind_feedback_topic'
|
| 'bind_feedback_topic'
|
||||||
| 'bind_reminders_topic'
|
| 'bind_reminders_topic'
|
||||||
@@ -23,6 +24,7 @@ export interface BotCommandDescriptions {
|
|||||||
cancel: string
|
cancel: string
|
||||||
setup: string
|
setup: string
|
||||||
unsetup: string
|
unsetup: string
|
||||||
|
bind_chat_topic: string
|
||||||
bind_purchase_topic: string
|
bind_purchase_topic: string
|
||||||
bind_feedback_topic: string
|
bind_feedback_topic: string
|
||||||
bind_reminders_topic: string
|
bind_reminders_topic: string
|
||||||
@@ -90,12 +92,18 @@ export interface BotTranslationCatalog {
|
|||||||
setupTopicBindPending: (role: string) => string
|
setupTopicBindPending: (role: string) => string
|
||||||
setupTopicBindCancelled: string
|
setupTopicBindCancelled: string
|
||||||
setupTopicBindNotAvailable: string
|
setupTopicBindNotAvailable: string
|
||||||
setupTopicBindRoleName: (role: 'purchase' | 'feedback' | 'reminders' | 'payments') => string
|
setupTopicBindRoleName: (
|
||||||
setupTopicSuggestedName: (role: 'purchase' | 'feedback' | 'reminders' | 'payments') => string
|
role: 'chat' | 'purchase' | 'feedback' | 'reminders' | 'payments'
|
||||||
|
) => string
|
||||||
|
setupTopicSuggestedName: (
|
||||||
|
role: 'chat' | 'purchase' | 'feedback' | 'reminders' | 'payments'
|
||||||
|
) => string
|
||||||
onlyTelegramAdminsUnsetup: string
|
onlyTelegramAdminsUnsetup: string
|
||||||
useUnsetupInGroup: string
|
useUnsetupInGroup: string
|
||||||
unsetupComplete: (householdName: string) => string
|
unsetupComplete: (householdName: string) => string
|
||||||
unsetupNoop: string
|
unsetupNoop: string
|
||||||
|
useBindChatTopicInGroup: string
|
||||||
|
chatTopicSaved: (householdName: string, threadId: string) => string
|
||||||
useBindPurchaseTopicInGroup: string
|
useBindPurchaseTopicInGroup: string
|
||||||
purchaseTopicSaved: (householdName: string, threadId: string) => string
|
purchaseTopicSaved: (householdName: string, threadId: string) => string
|
||||||
useBindFeedbackTopicInGroup: string
|
useBindFeedbackTopicInGroup: string
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ const GROUP_ADMIN_COMMAND_NAMES = [
|
|||||||
...GROUP_MEMBER_COMMAND_NAMES,
|
...GROUP_MEMBER_COMMAND_NAMES,
|
||||||
'setup',
|
'setup',
|
||||||
'unsetup',
|
'unsetup',
|
||||||
|
'bind_chat_topic',
|
||||||
'bind_purchase_topic',
|
'bind_purchase_topic',
|
||||||
'bind_feedback_topic',
|
'bind_feedback_topic',
|
||||||
'bind_reminders_topic',
|
'bind_reminders_topic',
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import type { CurrencyCode, SupportedLocale } from '@household/domain'
|
import type { CurrencyCode, SupportedLocale } from '@household/domain'
|
||||||
import type { ReminderTarget } from './reminders'
|
import type { ReminderTarget } from './reminders'
|
||||||
|
|
||||||
export const HOUSEHOLD_TOPIC_ROLES = ['purchase', 'feedback', 'reminders', 'payments'] as const
|
export const HOUSEHOLD_TOPIC_ROLES = [
|
||||||
|
'chat',
|
||||||
|
'purchase',
|
||||||
|
'feedback',
|
||||||
|
'reminders',
|
||||||
|
'payments'
|
||||||
|
] as const
|
||||||
export const HOUSEHOLD_MEMBER_LIFECYCLE_STATUSES = ['active', 'away', 'left'] as const
|
export const HOUSEHOLD_MEMBER_LIFECYCLE_STATUSES = ['active', 'away', 'left'] as const
|
||||||
export const HOUSEHOLD_MEMBER_ABSENCE_POLICIES = [
|
export const HOUSEHOLD_MEMBER_ABSENCE_POLICIES = [
|
||||||
'resident',
|
'resident',
|
||||||
|
|||||||
Reference in New Issue
Block a user