307 lines
13 KiB
TypeScript
307 lines
13 KiB
TypeScript
import TelegramBot, { Message, InlineKeyboardMarkup } from 'node-telegram-bot-api';
|
||
import { ProfileService } from '../services/profileService';
|
||
import { MatchingService } from '../services/matchingService';
|
||
import { Profile } from '../models/Profile';
|
||
|
||
export class CommandHandlers {
|
||
private bot: TelegramBot;
|
||
private profileService: ProfileService;
|
||
private matchingService: MatchingService;
|
||
|
||
constructor(bot: TelegramBot) {
|
||
this.bot = bot;
|
||
this.profileService = new ProfileService();
|
||
this.matchingService = new MatchingService();
|
||
}
|
||
|
||
register(): void {
|
||
this.bot.onText(/\/start/, (msg: Message) => this.handleStart(msg));
|
||
this.bot.onText(/\/help/, (msg: Message) => this.handleHelp(msg));
|
||
this.bot.onText(/\/profile/, (msg: Message) => this.handleProfile(msg));
|
||
this.bot.onText(/\/browse/, (msg: Message) => this.handleBrowse(msg));
|
||
this.bot.onText(/\/matches/, (msg: Message) => this.handleMatches(msg));
|
||
this.bot.onText(/\/settings/, (msg: Message) => this.handleSettings(msg));
|
||
this.bot.onText(/\/create_profile/, (msg: Message) => this.handleCreateProfile(msg));
|
||
}
|
||
|
||
async handleStart(msg: Message): Promise<void> {
|
||
const userId = msg.from?.id.toString();
|
||
if (!userId) return;
|
||
|
||
// Проверяем есть ли у пользователя профиль
|
||
const existingProfile = await this.profileService.getProfileByTelegramId(userId);
|
||
|
||
if (existingProfile) {
|
||
const keyboard: InlineKeyboardMarkup = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '👤 Мой профиль', callback_data: 'view_my_profile' },
|
||
{ text: '🔍 Просмотр анкет', callback_data: 'start_browsing' }
|
||
],
|
||
[
|
||
{ text: '💕 Мои матчи', callback_data: 'view_matches' },
|
||
{ text: '⭐ VIP поиск', callback_data: 'vip_search' }
|
||
],
|
||
[
|
||
{ text: '⚙️ Настройки', callback_data: 'settings' }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(
|
||
msg.chat.id,
|
||
`🎉 С возвращением, ${existingProfile.name}!\n\n` +
|
||
`💖 Telegram Tinder Bot готов к работе!\n\n` +
|
||
`Что хотите сделать?`,
|
||
{ reply_markup: keyboard }
|
||
);
|
||
} else {
|
||
const keyboard: InlineKeyboardMarkup = {
|
||
inline_keyboard: [
|
||
[{ text: '<27> Создать профиль', callback_data: 'create_profile' }],
|
||
[{ text: 'ℹ️ Как это работает?', callback_data: 'how_it_works' }]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(
|
||
msg.chat.id,
|
||
`🎉 Добро пожаловать в Telegram Tinder Bot!\n\n` +
|
||
`💕 Здесь вы можете найти свою вторую половинку!\n\n` +
|
||
`Для начала создайте свой профиль:`,
|
||
{ reply_markup: keyboard }
|
||
);
|
||
}
|
||
}
|
||
|
||
async handleHelp(msg: Message): Promise<void> {
|
||
const helpText = `
|
||
🤖 Telegram Tinder Bot - Справка
|
||
|
||
📋 Доступные команды:
|
||
/start - Главное меню
|
||
/profile - Управление профилем
|
||
/browse - Просмотр анкет
|
||
/matches - Ваши матчи
|
||
/settings - Настройки
|
||
/help - Эта справка
|
||
|
||
<EFBFBD> Как использовать:
|
||
1. Создайте профиль с фото и описанием
|
||
2. Просматривайте анкеты других пользователей
|
||
3. Ставьте лайки понравившимся
|
||
4. Общайтесь с взаимными матчами!
|
||
|
||
❤️ Удачи в поиске любви!
|
||
`;
|
||
|
||
await this.bot.sendMessage(msg.chat.id, helpText.trim());
|
||
}
|
||
|
||
async handleProfile(msg: Message): Promise<void> {
|
||
const userId = msg.from?.id.toString();
|
||
if (!userId) return;
|
||
|
||
const profile = await this.profileService.getProfileByTelegramId(userId);
|
||
|
||
if (!profile) {
|
||
const keyboard: InlineKeyboardMarkup = {
|
||
inline_keyboard: [
|
||
[{ text: '🚀 Создать профиль', callback_data: 'create_profile' }]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(
|
||
msg.chat.id,
|
||
'❌ У вас пока нет профиля.\nСоздайте его для начала использования бота!',
|
||
{ reply_markup: keyboard }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Показываем профиль пользователя
|
||
await this.showUserProfile(msg.chat.id, profile, true);
|
||
}
|
||
|
||
async handleBrowse(msg: Message): Promise<void> {
|
||
const userId = msg.from?.id.toString();
|
||
if (!userId) return;
|
||
|
||
const profile = await this.profileService.getProfileByTelegramId(userId);
|
||
|
||
if (!profile) {
|
||
await this.bot.sendMessage(
|
||
msg.chat.id,
|
||
'❌ Сначала создайте профиль!\nИспользуйте команду /start'
|
||
);
|
||
return;
|
||
}
|
||
|
||
await this.showNextCandidate(msg.chat.id, userId);
|
||
}
|
||
|
||
async handleMatches(msg: Message): Promise<void> {
|
||
const userId = msg.from?.id.toString();
|
||
if (!userId) return;
|
||
|
||
// Получаем матчи пользователя
|
||
const matches = await this.matchingService.getUserMatches(userId);
|
||
|
||
if (matches.length === 0) {
|
||
await this.bot.sendMessage(
|
||
msg.chat.id,
|
||
'<27> У вас пока нет матчей.\n\n' +
|
||
'🔍 Попробуйте просмотреть больше анкет!\n' +
|
||
'Используйте /browse для поиска.'
|
||
);
|
||
return;
|
||
}
|
||
|
||
let matchText = `💕 Ваши матчи (${matches.length}):\n\n`;
|
||
|
||
for (const match of matches) {
|
||
const otherUserId = match.userId1 === userId ? match.userId2 : match.userId1;
|
||
const otherProfile = await this.profileService.getProfileByUserId(otherUserId);
|
||
|
||
if (otherProfile) {
|
||
matchText += `💖 ${otherProfile.name}, ${otherProfile.age}\n`;
|
||
matchText += `📍 ${otherProfile.city || 'Не указан'}\n`;
|
||
matchText += `💌 Матч: ${new Date(match.createdAt).toLocaleDateString()}\n\n`;
|
||
}
|
||
}
|
||
|
||
const keyboard: InlineKeyboardMarkup = {
|
||
inline_keyboard: [
|
||
[{ text: '💬 Открыть чаты', callback_data: 'open_chats' }],
|
||
[{ text: '<27> Нативные чаты', callback_data: 'native_chats' }],
|
||
[{ text: '<27>🔍 Найти еще', callback_data: 'start_browsing' }]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(msg.chat.id, matchText, { reply_markup: keyboard });
|
||
}
|
||
|
||
async handleSettings(msg: Message): Promise<void> {
|
||
const keyboard: InlineKeyboardMarkup = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '🔍 Настройки поиска', callback_data: 'search_settings' },
|
||
{ text: '🔔 Уведомления', callback_data: 'notification_settings' }
|
||
],
|
||
[
|
||
{ text: '🚫 Скрыть профиль', callback_data: 'hide_profile' },
|
||
{ text: '🗑 Удалить профиль', callback_data: 'delete_profile' }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(
|
||
msg.chat.id,
|
||
'⚙️ Настройки профиля\n\nВыберите что хотите изменить:',
|
||
{ reply_markup: keyboard }
|
||
);
|
||
}
|
||
|
||
async handleCreateProfile(msg: Message): Promise<void> {
|
||
const userId = msg.from?.id.toString();
|
||
if (!userId) return;
|
||
|
||
await this.bot.sendMessage(
|
||
msg.chat.id,
|
||
'👋 Давайте создадим ваш профиль!\n\n' +
|
||
'📝 Сначала напишите ваше имя:'
|
||
);
|
||
|
||
// Устанавливаем состояние ожидания имени
|
||
// Это будет обрабатываться в messageHandlers
|
||
}
|
||
|
||
// Вспомогательные методы
|
||
async showUserProfile(chatId: number, profile: Profile, isOwner: boolean = false): Promise<void> {
|
||
const mainPhotoFileId = profile.photos[0]; // Первое фото - главное
|
||
|
||
let profileText = `👤 ${profile.name}, ${profile.age}\n`;
|
||
profileText += `📍 ${profile.city || 'Не указан'}\n`;
|
||
if (profile.job) profileText += `💼 ${profile.job}\n`;
|
||
if (profile.education) profileText += `🎓 ${profile.education}\n`;
|
||
if (profile.height) profileText += `📏 ${profile.height} см\n`;
|
||
profileText += `\n📝 ${profile.bio || 'Описание не указано'}\n`;
|
||
|
||
if (profile.interests.length > 0) {
|
||
profileText += `\n🎯 Интересы: ${profile.interests.join(', ')}`;
|
||
}
|
||
|
||
const keyboard: InlineKeyboardMarkup = isOwner ? {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '✏️ Редактировать', callback_data: 'edit_profile' },
|
||
{ text: '📸 Фото', callback_data: 'manage_photos' }
|
||
],
|
||
[{ text: '🔍 Начать поиск', callback_data: 'start_browsing' }]
|
||
]
|
||
} : {
|
||
inline_keyboard: [
|
||
[{ text: '👈 Назад', callback_data: 'back_to_browsing' }]
|
||
]
|
||
};
|
||
|
||
if (mainPhotoFileId) {
|
||
await this.bot.sendPhoto(chatId, mainPhotoFileId, {
|
||
caption: profileText,
|
||
reply_markup: keyboard
|
||
});
|
||
} else {
|
||
await this.bot.sendMessage(chatId, profileText, { reply_markup: keyboard });
|
||
}
|
||
}
|
||
|
||
async showNextCandidate(chatId: number, userId: string): Promise<void> {
|
||
const candidate = await this.matchingService.getNextCandidate(userId);
|
||
|
||
if (!candidate) {
|
||
await this.bot.sendMessage(
|
||
chatId,
|
||
'🎉 Вы просмотрели всех доступных кандидатов!\n\n' +
|
||
'⏰ Попробуйте позже - возможно появятся новые анкеты!'
|
||
);
|
||
return;
|
||
}
|
||
|
||
const candidatePhotoFileId = candidate.photos[0]; // Первое фото - главное
|
||
|
||
let candidateText = `${candidate.name}, ${candidate.age}\n`;
|
||
candidateText += `📍 ${candidate.city || 'Не указан'}\n`;
|
||
if (candidate.job) candidateText += `💼 ${candidate.job}\n`;
|
||
if (candidate.education) candidateText += `🎓 ${candidate.education}\n`;
|
||
if (candidate.height) candidateText += `📏 ${candidate.height} см\n`;
|
||
candidateText += `\n📝 ${candidate.bio || 'Описание отсутствует'}\n`;
|
||
|
||
if (candidate.interests.length > 0) {
|
||
candidateText += `\n🎯 Интересы: ${candidate.interests.join(', ')}`;
|
||
}
|
||
|
||
const keyboard: InlineKeyboardMarkup = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '👎 Не нравится', callback_data: `dislike_${candidate.userId}` },
|
||
{ text: '💖 Супер лайк', callback_data: `superlike_${candidate.userId}` },
|
||
{ text: '👍 Нравится', callback_data: `like_${candidate.userId}` }
|
||
],
|
||
[
|
||
{ text: '👤 Профиль', callback_data: `view_profile_${candidate.userId}` },
|
||
{ text: '📸 Еще фото', callback_data: `more_photos_${candidate.userId}` }
|
||
],
|
||
[{ text: '⏭ Следующий', callback_data: 'next_candidate' }]
|
||
]
|
||
};
|
||
|
||
if (candidatePhotoFileId) {
|
||
await this.bot.sendPhoto(chatId, candidatePhotoFileId, {
|
||
caption: candidateText,
|
||
reply_markup: keyboard
|
||
});
|
||
} else {
|
||
await this.bot.sendMessage(chatId, candidateText, { reply_markup: keyboard });
|
||
}
|
||
}
|
||
}
|