import TelegramBot from 'node-telegram-bot-api'; import { stateManager } from '../services/state'; import { logger, logUserAction } from '../services/logger'; import { messages } from '../messages'; import { getMainMenuKeyboard, getSettingsKeyboard } from '../utils/keyboards'; import { NotificationPreferences, DEFAULT_NOTIFICATIONS } from '../types'; /** * Handle /settings command (private chat only) */ export async function handleSettingsCommand( bot: TelegramBot, msg: TelegramBot.Message ): Promise { const chatId = msg.chat.id; const userId = msg.from?.id; if (!userId) return; // Only works in private chats if (msg.chat.type !== 'private') { await bot.sendMessage(chatId, '❌ This command only works in private chat. Message me directly!'); return; } logUserAction(userId, 'Viewed settings'); const user = await stateManager.getUser(userId); if (!user) { await bot.sendMessage(chatId, messages.errors.startFirst, { reply_markup: getMainMenuKeyboard(), }); return; } // Ensure notifications object exists const notifications = user.notifications || { ...DEFAULT_NOTIFICATIONS }; const displayName = stateManager.getDisplayName(user); await bot.sendMessage( chatId, messages.settings.overview(displayName, notifications), { parse_mode: 'Markdown', reply_markup: getSettingsKeyboard(displayName, notifications), } ); } /** * Handle settings callback */ export async function handleSettingsCallback( bot: TelegramBot, query: TelegramBot.CallbackQuery, action: string ): Promise { const chatId = query.message?.chat.id; const userId = query.from.id; const messageId = query.message?.message_id; if (!chatId || !messageId) return; const user = await stateManager.getUser(userId); if (!user) { await bot.answerCallbackQuery(query.id, { text: 'Please /start first' }); return; } try { // Handle notification toggles if (action.startsWith('toggle_notif_')) { const setting = action.replace('toggle_notif_', '') as keyof NotificationPreferences; const currentNotifications = user.notifications || { ...DEFAULT_NOTIFICATIONS }; const newValue = !currentNotifications[setting]; const updatedUser = await stateManager.updateNotifications(userId, { [setting]: newValue }); if (updatedUser) { logUserAction(userId, 'Updated notification setting', { setting, newValue }); await bot.answerCallbackQuery(query.id, { text: `${setting} ${newValue ? 'enabled' : 'disabled'}`, }); // Update message const displayName = stateManager.getDisplayName(updatedUser); await bot.editMessageText( messages.settings.overview(displayName, updatedUser.notifications), { chat_id: chatId, message_id: messageId, parse_mode: 'Markdown', reply_markup: getSettingsKeyboard(displayName, updatedUser.notifications), } ); } return; } // Handle display name change if (action === 'change_name') { await bot.answerCallbackQuery(query.id); await stateManager.updateUserState(userId, 'awaiting_display_name'); await bot.sendMessage( chatId, messages.settings.enterDisplayName, { parse_mode: 'Markdown' } ); return; } // Handle back to menu if (action === 'back_menu') { await bot.answerCallbackQuery(query.id); await bot.deleteMessage(chatId, messageId); await bot.sendMessage(chatId, messages.menu.header, { parse_mode: 'Markdown', reply_markup: getMainMenuKeyboard(), }); return; } await bot.answerCallbackQuery(query.id); } catch (error) { logger.error('Error in handleSettingsCallback', { error, userId, action }); await bot.answerCallbackQuery(query.id, { text: 'Error updating settings' }); } } /** * Handle display name input */ export async function handleDisplayNameInput( bot: TelegramBot, msg: TelegramBot.Message ): Promise { const chatId = msg.chat.id; const userId = msg.from?.id; const text = msg.text?.trim(); if (!userId || !text) return; // Validate display name (max 20 chars, alphanumeric + spaces + some symbols) if (text.length > 20) { await bot.sendMessage(chatId, messages.settings.nameTooLong); return; } // Clean the display name (allow @ for usernames) const cleanName = text.replace(/[^\w\s\-_.@]/g, '').trim() || 'Anon'; await stateManager.updateDisplayName(userId, cleanName); logUserAction(userId, 'Set display name', { displayName: cleanName }); const user = await stateManager.getUser(userId); const notifications = user?.notifications || { ...DEFAULT_NOTIFICATIONS }; await bot.sendMessage( chatId, messages.settings.nameUpdated(cleanName), { parse_mode: 'Markdown', reply_markup: getSettingsKeyboard(cleanName, notifications), } ); } export default { handleSettingsCommand, handleSettingsCallback, handleDisplayNameInput, };