feat: add VIP search option and profile editing functionality

- Added a new button for ' VIP поиск' in command handlers.
- Implemented profile editing states and methods in message handlers.
- Enhanced profile model to include hobbies, religion, dating goals, and lifestyle preferences.
- Updated profile service to handle new fields and ensure proper database interactions.
- Introduced a VIP function in matching service to find candidates based on dating goals.
This commit is contained in:
2025-09-12 22:13:26 +09:00
parent 17efb2fb53
commit 8893b4ad22
9 changed files with 1528 additions and 50 deletions

View File

@@ -4,6 +4,7 @@ import { MatchingService } from '../services/matchingService';
import { ChatService } from '../services/chatService';
import { Profile } from '../models/Profile';
import { MessageHandlers } from './messageHandlers';
import { ProfileEditController } from '../controllers/profileEditController';
export class CallbackHandlers {
private bot: TelegramBot;
@@ -11,6 +12,7 @@ export class CallbackHandlers {
private matchingService: MatchingService;
private chatService: ChatService;
private messageHandlers: MessageHandlers;
private profileEditController: ProfileEditController;
constructor(bot: TelegramBot, messageHandlers: MessageHandlers) {
this.bot = bot;
@@ -18,6 +20,7 @@ export class CallbackHandlers {
this.matchingService = new MatchingService();
this.chatService = new ChatService();
this.messageHandlers = messageHandlers;
this.profileEditController = new ProfileEditController(this.profileService);
}
register(): void {
@@ -44,11 +47,91 @@ export class CallbackHandlers {
await this.handleEditProfile(chatId, telegramId);
} else if (data === 'manage_photos') {
await this.handleManagePhotos(chatId, telegramId);
} else if (data === 'preview_profile') {
await this.handlePreviewProfile(chatId, telegramId);
}
// Редактирование полей профиля
else if (data === 'edit_name') {
await this.handleEditName(chatId, telegramId);
} else if (data === 'edit_age') {
await this.handleEditAge(chatId, telegramId);
} else if (data === 'edit_bio') {
await this.handleEditBio(chatId, telegramId);
} else if (data === 'edit_hobbies') {
await this.handleEditHobbies(chatId, telegramId);
} else if (data === 'edit_city') {
await this.handleEditCity(chatId, telegramId);
} else if (data === 'edit_job') {
await this.handleEditJob(chatId, telegramId);
} else if (data === 'edit_education') {
await this.handleEditEducation(chatId, telegramId);
} else if (data === 'edit_height') {
await this.handleEditHeight(chatId, telegramId);
} else if (data === 'edit_religion') {
await this.handleEditReligion(chatId, telegramId);
} else if (data === 'edit_dating_goal') {
await this.handleEditDatingGoal(chatId, telegramId);
} else if (data === 'edit_lifestyle') {
await this.handleEditLifestyle(chatId, telegramId);
} else if (data === 'edit_search_preferences') {
await this.handleEditSearchPreferences(chatId, telegramId);
}
// Управление фотографиями
else if (data === 'add_photo') {
await this.handleAddPhoto(chatId, telegramId);
} else if (data === 'delete_photo') {
await this.handleDeletePhoto(chatId, telegramId);
} else if (data === 'set_main_photo') {
await this.handleSetMainPhoto(chatId, telegramId);
} else if (data.startsWith('delete_photo_')) {
const photoIndex = parseInt(data.replace('delete_photo_', ''));
await this.handleDeletePhotoByIndex(chatId, telegramId, photoIndex);
} else if (data.startsWith('set_main_photo_')) {
const photoIndex = parseInt(data.replace('set_main_photo_', ''));
await this.handleSetMainPhotoByIndex(chatId, telegramId, photoIndex);
}
// Цели знакомства
else if (data.startsWith('set_dating_goal_')) {
const goal = data.replace('set_dating_goal_', '');
await this.handleSetDatingGoal(chatId, telegramId, goal);
}
// Образ жизни
else if (data === 'edit_smoking') {
await this.handleEditSmoking(chatId, telegramId);
} else if (data === 'edit_drinking') {
await this.handleEditDrinking(chatId, telegramId);
} else if (data === 'edit_kids') {
await this.handleEditKids(chatId, telegramId);
} else if (data.startsWith('set_smoking_')) {
const value = data.replace('set_smoking_', '');
await this.handleSetLifestyle(chatId, telegramId, 'smoking', value);
} else if (data.startsWith('set_drinking_')) {
const value = data.replace('set_drinking_', '');
await this.handleSetLifestyle(chatId, telegramId, 'drinking', value);
} else if (data.startsWith('set_kids_')) {
const value = data.replace('set_kids_', '');
await this.handleSetLifestyle(chatId, telegramId, 'kids', value);
}
// Настройки поиска
else if (data === 'edit_age_range') {
await this.handleEditAgeRange(chatId, telegramId);
} else if (data === 'edit_distance') {
await this.handleEditDistance(chatId, telegramId);
}
// Просмотр анкет и свайпы
else if (data === 'start_browsing') {
await this.handleStartBrowsing(chatId, telegramId);
} else if (data === 'vip_search') {
await this.handleVipSearch(chatId, telegramId);
} else if (data.startsWith('search_by_goal_')) {
const goal = data.replace('search_by_goal_', '');
await this.handleSearchByGoal(chatId, telegramId, goal);
} else if (data === 'next_candidate') {
await this.handleNextCandidate(chatId, telegramId);
} else if (data.startsWith('like_')) {
@@ -167,52 +250,12 @@ export class CallbackHandlers {
// Редактирование профиля
async handleEditProfile(chatId: number, telegramId: string): Promise<void> {
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[
{ text: '📝 Имя', callback_data: 'edit_name' },
{ text: '📅 Возраст', callback_data: 'edit_age' }
],
[
{ text: '📍 Город', callback_data: 'edit_city' },
{ text: '💼 Работа', callback_data: 'edit_job' }
],
[
{ text: '📖 О себе', callback_data: 'edit_bio' },
{ text: '🎯 Интересы', callback_data: 'edit_interests' }
],
[{ text: '👈 Назад к профилю', callback_data: 'view_my_profile' }]
]
};
await this.bot.sendMessage(
chatId,
'✏️ Что хотите изменить в профиле?',
{ reply_markup: keyboard }
);
await this.profileEditController.showProfileEditMenu(this.bot, chatId, parseInt(telegramId));
}
// Управление фотографиями
async handleManagePhotos(chatId: number, telegramId: string): Promise<void> {
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[
{ text: '📷 Добавить фото', callback_data: 'add_photo' },
{ text: '🗑 Удалить фото', callback_data: 'delete_photo' }
],
[
{ text: '⭐ Сделать главным', callback_data: 'set_main_photo' },
{ text: '🔄 Изменить порядок', callback_data: 'reorder_photos' }
],
[{ text: '👈 Назад к профилю', callback_data: 'view_my_profile' }]
]
};
await this.bot.sendMessage(
chatId,
'📸 Управление фотографиями\n\nВыберите действие:',
{ reply_markup: keyboard }
);
await this.profileEditController.showPhotoManagementMenu(this.bot, chatId, parseInt(telegramId));
}
// Начать просмотр анкет
@@ -669,10 +712,33 @@ export class CallbackHandlers {
if (profile.job) profileText += '💼 ' + profile.job + '\n';
if (profile.education) profileText += '🎓 ' + profile.education + '\n';
if (profile.height) profileText += '📏 ' + profile.height + ' см\n';
if (profile.religion) profileText += '🕊️ ' + profile.religion + '\n';
// Цель знакомства
if (profile.datingGoal) {
const goalText = this.getDatingGoalText(profile.datingGoal);
profileText += '💕 ' + goalText + '\n';
}
// Образ жизни
if (profile.lifestyle) {
const lifestyleText = this.getLifestyleText(profile.lifestyle);
if (lifestyleText) {
profileText += lifestyleText + '\n';
}
}
profileText += '\n📝 ' + (profile.bio || 'Описание не указано') + '\n';
// Хобби с хэштегами
if (profile.hobbies && profile.hobbies.trim()) {
const hobbiesArray = profile.hobbies.split(',').map(hobby => hobby.trim()).filter(hobby => hobby);
const formattedHobbies = hobbiesArray.map(hobby => '#' + hobby).join(' ');
profileText += '\n🎯 ' + formattedHobbies + '\n';
}
if (profile.interests.length > 0) {
profileText += '\n🎯 Интересы: ' + profile.interests.join(', ');
profileText += '\n<EFBFBD> Интересы: ' + profile.interests.join(', ');
}
let keyboard: InlineKeyboardMarkup;
@@ -752,12 +818,17 @@ export class CallbackHandlers {
candidateText += '📍 ' + (candidate.city || 'Не указан') + '\n';
if (candidate.job) candidateText += '💼 ' + candidate.job + '\n';
if (candidate.education) candidateText += '🎓 ' + candidate.education + '\n';
if (candidate.height) candidateText += '<EFBFBD><EFBFBD> ' + candidate.height + ' см\n';
if (candidate.height) candidateText += '📏 ' + candidate.height + ' см\n';
if (candidate.religion) candidateText += '🕊️ ' + candidate.religion + '\n';
candidateText += '\n📝 ' + (candidate.bio || 'Описание отсутствует') + '\n';
if (candidate.interests.length > 0) {
candidateText += '\n🎯 Интересы: ' + candidate.interests.join(', ');
}
if (candidate.hobbies) {
candidateText += '\n🎮 Хобби: ' + candidate.hobbies;
}
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
@@ -799,4 +870,711 @@ export class CallbackHandlers {
});
}
}
// ===== НОВЫЕ МЕТОДЫ ДЛЯ РЕДАКТИРОВАНИЯ ПРОФИЛЯ =====
// Предпросмотр профиля
async handlePreviewProfile(chatId: number, telegramId: string): Promise<void> {
await this.profileEditController.showProfilePreview(this.bot, chatId, parseInt(telegramId));
}
// Редактирование имени
async handleEditName(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'name');
await this.bot.sendMessage(chatId, '📝 *Введите ваше новое имя:*\n\nНапример: Анна', {
parse_mode: 'Markdown'
});
}
// Редактирование возраста
async handleEditAge(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'age');
await this.bot.sendMessage(chatId, '🎂 *Введите ваш возраст:*\n\nВозраст должен быть от 18 до 100 лет', {
parse_mode: 'Markdown'
});
}
// Редактирование описания "О себе"
async handleEditBio(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'bio');
await this.bot.sendMessage(chatId,
'📖 *Расскажите о себе:*\n\n' +
'Напишите несколько предложений, которые помогут людям лучше вас узнать.\n\n' +
'_Максимум 500 символов_', {
parse_mode: 'Markdown'
});
}
// Редактирование хобби
async handleEditHobbies(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'hobbies');
await this.bot.sendMessage(chatId,
'🎯 *Введите ваши хобби через запятую:*\n\n' +
'Например: футбол, чтение, путешествия, кулинария\n\n' +
'_В анкете они будут отображаться как хэштеги: #футбол #чтение #путешествия_', {
parse_mode: 'Markdown'
});
}
// Редактирование города
async handleEditCity(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'city');
await this.bot.sendMessage(chatId, '🏙️ *Введите ваш город:*\n\nНапример: Москва', {
parse_mode: 'Markdown'
});
}
// Редактирование работы
async handleEditJob(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'job');
await this.bot.sendMessage(chatId, '💼 *Введите вашу профессию или место работы:*\n\nНапример: Дизайнер в IT-компании', {
parse_mode: 'Markdown'
});
}
// Редактирование образования
async handleEditEducation(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'education');
await this.bot.sendMessage(chatId, '🎓 *Введите ваше образование:*\n\nНапример: МГУ, факультет журналистики', {
parse_mode: 'Markdown'
});
}
// Редактирование роста
async handleEditHeight(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'height');
await this.bot.sendMessage(chatId, '📏 *Введите ваш рост в сантиметрах:*\n\nНапример: 175', {
parse_mode: 'Markdown'
});
}
// Редактирование религии
async handleEditReligion(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'religion');
await this.bot.sendMessage(chatId, '🕊️ *Введите вашу религию или напишите "нет":*\n\nНапример: православие, ислам, атеизм, нет', {
parse_mode: 'Markdown'
});
}
// Редактирование цели знакомства
async handleEditDatingGoal(chatId: number, telegramId: string): Promise<void> {
const keyboard = {
inline_keyboard: [
[
{ text: '💕 Серьёзные отношения', callback_data: 'set_dating_goal_serious' },
{ text: '🎉 Лёгкие отношения', callback_data: 'set_dating_goal_casual' }
],
[
{ text: '👥 Дружба', callback_data: 'set_dating_goal_friends' },
{ text: '🔥 Одна ночь', callback_data: 'set_dating_goal_one_night' }
],
[
{ text: '😏 FWB', callback_data: 'set_dating_goal_fwb' },
{ text: '💎 Спонсорство', callback_data: 'set_dating_goal_sugar' }
],
[
{ text: '💍 Брак с переездом', callback_data: 'set_dating_goal_marriage_abroad' },
{ text: '💫 Полиамория', callback_data: 'set_dating_goal_polyamory' }
],
[
{ text: '🤷‍♀️ Пока не определился', callback_data: 'set_dating_goal_unsure' }
],
[
{ text: '⬅️ Назад', callback_data: 'edit_profile' }
]
]
};
await this.bot.sendMessage(chatId, '💕 *Выберите цель знакомства:*', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
}
// Редактирование образа жизни
async handleEditLifestyle(chatId: number, telegramId: string): Promise<void> {
const keyboard = {
inline_keyboard: [
[
{ text: '🚬 Курение', callback_data: 'edit_smoking' },
{ text: '🍷 Алкоголь', callback_data: 'edit_drinking' }
],
[
{ text: '👶 Отношение к детям', callback_data: 'edit_kids' }
],
[
{ text: '⬅️ Назад', callback_data: 'edit_profile' }
]
]
};
await this.bot.sendMessage(chatId, '🚬 *Выберите что хотите изменить в образе жизни:*', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
}
// Редактирование предпочтений поиска
async handleEditSearchPreferences(chatId: number, telegramId: string): Promise<void> {
const keyboard = {
inline_keyboard: [
[
{ text: '🔢 Возрастной диапазон', callback_data: 'edit_age_range' },
{ text: '📍 Максимальное расстояние', callback_data: 'edit_distance' }
],
[
{ text: '⬅️ Назад', callback_data: 'edit_profile' }
]
]
};
await this.bot.sendMessage(chatId, '⚙️ *Настройки поиска:*', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
}
// Добавление фото
async handleAddPhoto(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'photo');
await this.bot.sendMessage(chatId, '📷 *Отправьте фотографию:*\n\nМаксимум 9 фотографий в профиле', {
parse_mode: 'Markdown'
});
}
// Удаление фото
async handleDeletePhoto(chatId: number, telegramId: string): Promise<void> {
try {
const profile = await this.profileService.getProfileByTelegramId(telegramId);
if (!profile || profile.photos.length === 0) {
await this.bot.sendMessage(chatId, '❌ У вас нет фотографий для удаления');
return;
}
const keyboard = {
inline_keyboard: [
...profile.photos.map((photo, index) => [
{ text: `🗑️ Удалить фото ${index + 1}`, callback_data: `delete_photo_${index}` }
]),
[{ text: '⬅️ Назад', callback_data: 'manage_photos' }]
]
};
await this.bot.sendMessage(chatId, '🗑️ *Выберите фото для удаления:*', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
} catch (error) {
console.error('Error in handleDeletePhoto:', error);
await this.bot.sendMessage(chatId, '❌ Произошла ошибка');
}
}
// Установка главного фото
async handleSetMainPhoto(chatId: number, telegramId: string): Promise<void> {
try {
const profile = await this.profileService.getProfileByTelegramId(telegramId);
if (!profile || profile.photos.length <= 1) {
await this.bot.sendMessage(chatId, '❌ У вас недостаточно фотографий');
return;
}
const keyboard = {
inline_keyboard: [
...profile.photos.map((photo, index) => [
{ text: `⭐ Сделать главным фото ${index + 1}`, callback_data: `set_main_photo_${index}` }
]),
[{ text: '⬅️ Назад', callback_data: 'manage_photos' }]
]
};
await this.bot.sendMessage(chatId, '⭐ *Выберите главное фото:*', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
} catch (error) {
console.error('Error in handleSetMainPhoto:', error);
await this.bot.sendMessage(chatId, '❌ Произошла ошибка');
}
}
// ===== НОВЫЕ МЕТОДЫ ДЛЯ РАСШИРЕННОГО РЕДАКТИРОВАНИЯ =====
// Удаление фото по индексу
async handleDeletePhotoByIndex(chatId: number, telegramId: string, photoIndex: number): Promise<void> {
try {
const profile = await this.profileService.getProfileByTelegramId(telegramId);
if (!profile || photoIndex >= profile.photos.length) {
await this.bot.sendMessage(chatId, '❌ Фото не найдено');
return;
}
profile.removePhoto(profile.photos[photoIndex]);
await this.profileService.updateProfile(profile.userId, {
photos: profile.photos
});
await this.bot.sendMessage(chatId, '✅ Фото удалено!');
setTimeout(() => {
this.handleManagePhotos(chatId, telegramId);
}, 1000);
} catch (error) {
console.error('Error deleting photo:', error);
await this.bot.sendMessage(chatId, '❌ Произошла ошибка');
}
}
// Установка главного фото по индексу
async handleSetMainPhotoByIndex(chatId: number, telegramId: string, photoIndex: number): Promise<void> {
try {
const profile = await this.profileService.getProfileByTelegramId(telegramId);
if (!profile || photoIndex >= profile.photos.length) {
await this.bot.sendMessage(chatId, '❌ Фото не найдено');
return;
}
profile.setMainPhoto(profile.photos[photoIndex]);
await this.profileService.updateProfile(profile.userId, {
photos: profile.photos
});
await this.bot.sendMessage(chatId, '✅ Главное фото установлено!');
setTimeout(() => {
this.handleManagePhotos(chatId, telegramId);
}, 1000);
} catch (error) {
console.error('Error setting main photo:', error);
await this.bot.sendMessage(chatId, '❌ Произошла ошибка');
}
}
// Установка цели знакомства
async handleSetDatingGoal(chatId: number, telegramId: string, goal: string): Promise<void> {
try {
const profile = await this.profileService.getProfileByTelegramId(telegramId);
if (!profile) {
await this.bot.sendMessage(chatId, '❌ Профиль не найден');
return;
}
await this.profileService.updateProfile(profile.userId, {
datingGoal: goal as any
});
const goalTexts: { [key: string]: string } = {
'serious': 'Серьёзные отношения',
'casual': 'Лёгкие отношения',
'friends': 'Дружба',
'unsure': 'Пока не определился',
'one_night': 'Отношения на одну ночь',
'fwb': 'Друзья с привилегиями',
'marriage_abroad': 'Брак с переездом',
'sugar': 'Спонсорство',
'polyamory': 'Полиамория'
};
await this.bot.sendMessage(chatId, `✅ Цель знакомства установлена: ${goalTexts[goal]}`);
setTimeout(() => {
this.profileEditController.showProfileEditMenu(this.bot, chatId, parseInt(telegramId));
}, 1500);
} catch (error) {
console.error('Error setting dating goal:', error);
await this.bot.sendMessage(chatId, '❌ Произошла ошибка');
}
}
// Редактирование курения
async handleEditSmoking(chatId: number, telegramId: string): Promise<void> {
const keyboard = {
inline_keyboard: [
[
{ text: '🚭 Не курю', callback_data: 'set_smoking_never' },
{ text: '🚬 Иногда', callback_data: 'set_smoking_sometimes' }
],
[
{ text: '🚬 Регулярно', callback_data: 'set_smoking_regularly' }
],
[
{ text: '⬅️ Назад', callback_data: 'edit_lifestyle' }
]
]
};
await this.bot.sendMessage(chatId, '🚬 *Выберите ваше отношение к курению:*', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
}
// Редактирование алкоголя
async handleEditDrinking(chatId: number, telegramId: string): Promise<void> {
const keyboard = {
inline_keyboard: [
[
{ text: '🚫 Не пью', callback_data: 'set_drinking_never' },
{ text: '🍷 Иногда', callback_data: 'set_drinking_sometimes' }
],
[
{ text: '🍺 Регулярно', callback_data: 'set_drinking_regularly' }
],
[
{ text: '⬅️ Назад', callback_data: 'edit_lifestyle' }
]
]
};
await this.bot.sendMessage(chatId, '🍷 *Выберите ваше отношение к алкоголю:*', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
}
// Редактирование отношения к детям
async handleEditKids(chatId: number, telegramId: string): Promise<void> {
const keyboard = {
inline_keyboard: [
[
{ text: '👶 Есть дети', callback_data: 'set_kids_have' },
{ text: '💕 Хочу детей', callback_data: 'set_kids_want' }
],
[
{ text: '🚫 Не хочу детей', callback_data: 'set_kids_dont_want' },
{ text: '🤷‍♀️ Пока не знаю', callback_data: 'set_kids_unsure' }
],
[
{ text: '⬅️ Назад', callback_data: 'edit_lifestyle' }
]
]
};
await this.bot.sendMessage(chatId, '👶 *Выберите ваше отношение к детям:*', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
}
// Установка параметра образа жизни
async handleSetLifestyle(chatId: number, telegramId: string, type: string, value: string): Promise<void> {
try {
const profile = await this.profileService.getProfileByTelegramId(telegramId);
if (!profile) {
await this.bot.sendMessage(chatId, '❌ Профиль не найден');
return;
}
const lifestyle = profile.lifestyle || {};
lifestyle[type as keyof typeof lifestyle] = value as any;
await this.profileService.updateProfile(profile.userId, {
lifestyle: lifestyle
});
const typeTexts: { [key: string]: string } = {
'smoking': 'курение',
'drinking': 'алкоголь',
'kids': 'отношение к детям'
};
const valueTexts: { [key: string]: { [key: string]: string } } = {
smoking: { 'never': 'не курю', 'sometimes': 'иногда', 'regularly': 'регулярно' },
drinking: { 'never': 'не пью', 'sometimes': 'иногда', 'regularly': 'регулярно' },
kids: { 'have': 'есть дети', 'want': 'хочу детей', 'dont_want': 'не хочу детей', 'unsure': 'пока не знаю' }
};
const typeText = typeTexts[type] || type;
const valueText = valueTexts[type]?.[value] || value;
await this.bot.sendMessage(chatId, `${typeText}: ${valueText}`);
setTimeout(() => {
this.profileEditController.showProfileEditMenu(this.bot, chatId, parseInt(telegramId));
}, 1500);
} catch (error) {
console.error('Error setting lifestyle:', error);
await this.bot.sendMessage(chatId, '❌ Произошла ошибка');
}
}
// Редактирование возрастного диапазона
async handleEditAgeRange(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'age_range');
await this.bot.sendMessage(chatId,
'🔢 *Введите возрастной диапазон:*\n\n' +
'Формат: минимальный-максимальный возраст\n' +
'Например: 18-35', {
parse_mode: 'Markdown'
});
}
// Редактирование максимального расстояния
async handleEditDistance(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'distance');
await this.bot.sendMessage(chatId,
'📍 *Введите максимальное расстояние для поиска:*\n\n' +
'В километрах (например: 50)', {
parse_mode: 'Markdown'
});
}
// ===== VIP ФУНКЦИИ =====
// VIP поиск по целям знакомства
async handleVipSearch(chatId: number, telegramId: string): Promise<void> {
try {
// Проверяем VIP статус пользователя
const user = await this.profileService.getUserByTelegramId(telegramId);
if (!user || !user.isPremium) {
const keyboard = {
inline_keyboard: [
[
{ text: '💎 Получить VIP', callback_data: 'get_vip' },
{ text: '⬅️ Назад', callback_data: 'main_menu' }
]
]
};
await this.bot.sendMessage(chatId,
'🔒 *VIP Поиск*\n\n' +
'Эта функция доступна только для VIP пользователей!\n\n' +
'✨ *VIP возможности:*\n' +
'• Поиск по целям знакомства\n' +
'• Расширенные фильтры\n' +
'• Приоритет в показе анкет\n' +
'• Безлимитные суперлайки', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
return;
}
const keyboard = {
inline_keyboard: [
[
{ text: '💕 Серьёзные отношения', callback_data: 'search_by_goal_serious' },
{ text: '🎉 Лёгкие отношения', callback_data: 'search_by_goal_casual' }
],
[
{ text: '👥 Дружба', callback_data: 'search_by_goal_friends' },
{ text: '🔥 Одна ночь', callback_data: 'search_by_goal_one_night' }
],
[
{ text: '😏 FWB', callback_data: 'search_by_goal_fwb' },
{ text: '💎 Спонсорство', callback_data: 'search_by_goal_sugar' }
],
[
{ text: '💍 Брак с переездом', callback_data: 'search_by_goal_marriage_abroad' },
{ text: '💫 Полиамория', callback_data: 'search_by_goal_polyamory' }
],
[
{ text: '🎲 Все цели', callback_data: 'start_browsing' }
],
[
{ text: '⬅️ Главное меню', callback_data: 'main_menu' }
]
]
};
await this.bot.sendMessage(chatId,
'🔍 *VIP Поиск по целям знакомства*\n\n' +
'Выберите интересующую вас цель:', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
} catch (error) {
console.error('Error in VIP search:', error);
await this.bot.sendMessage(chatId, '❌ Произошла ошибка');
}
}
// Поиск по конкретной цели
async handleSearchByGoal(chatId: number, telegramId: string, goal: string): Promise<void> {
try {
const profile = await this.profileService.getProfileByTelegramId(telegramId);
if (!profile) {
await this.bot.sendMessage(chatId, '❌ Сначала создайте профиль!');
return;
}
// Получаем кандидатов с определенной целью знакомства
const candidates = await this.matchingService.getCandidatesWithGoal(profile, goal);
if (candidates.length === 0) {
const goalTexts: { [key: string]: string } = {
'serious': 'серьёзные отношения',
'casual': 'лёгкие отношения',
'friends': 'дружбу',
'one_night': 'отношения на одну ночь',
'fwb': 'друзей с привилегиями',
'marriage_abroad': 'брак с переездом',
'sugar': 'спонсорство',
'polyamory': 'полиаморию'
};
const keyboard = {
inline_keyboard: [
[
{ text: '🔍 Другие цели', callback_data: 'vip_search' },
{ text: '🎲 Обычный поиск', callback_data: 'start_browsing' }
],
[
{ text: '⬅️ Главное меню', callback_data: 'main_menu' }
]
]
};
await this.bot.sendMessage(chatId,
`😔 *Пока нет анкет*\n\n` +
`К сожалению, сейчас нет пользователей, которые ищут ${goalTexts[goal] || goal}.\n\n` +
'Попробуйте позже или выберите другую цель!', {
parse_mode: 'Markdown',
reply_markup: keyboard
});
return;
}
// Показываем первого кандидата
const candidate = candidates[0];
await this.displayCandidate(chatId, candidate);
} catch (error) {
console.error('Error searching by goal:', error);
await this.bot.sendMessage(chatId, '❌ Произошла ошибка при поиске');
}
}
// Показ конкретного кандидата (для VIP поиска)
async displayCandidate(chatId: number, candidate: Profile): Promise<void> {
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';
if (candidate.religion) candidateText += '🕊️ ' + candidate.religion + '\n';
// Цель знакомства
if (candidate.datingGoal) {
const goalText = this.getDatingGoalText(candidate.datingGoal);
candidateText += '💕 ' + goalText + '\n';
}
// Образ жизни
if (candidate.lifestyle) {
const lifestyleText = this.getLifestyleText(candidate.lifestyle);
if (lifestyleText) {
candidateText += lifestyleText + '\n';
}
}
candidateText += '\n📝 ' + (candidate.bio || 'Описание отсутствует') + '\n';
// Хобби с хэштегами
if (candidate.hobbies && candidate.hobbies.trim()) {
const hobbiesArray = candidate.hobbies.split(',').map(hobby => hobby.trim()).filter(hobby => hobby);
const formattedHobbies = hobbiesArray.map(hobby => '#' + hobby).join(' ');
candidateText += '\n🎯 ' + formattedHobbies + '\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' },
{ text: '🔍 VIP поиск', callback_data: 'vip_search' }
]
]
};
// Проверяем, есть ли валидное фото (file_id или URL)
const hasValidPhoto = candidatePhotoFileId &&
(candidatePhotoFileId.startsWith('http') ||
candidatePhotoFileId.startsWith('AgAC') ||
candidatePhotoFileId.length > 20); // file_id обычно длинные
if (hasValidPhoto) {
try {
await this.bot.sendPhoto(chatId, candidatePhotoFileId, {
caption: candidateText,
reply_markup: keyboard
});
} catch (error) {
// Если не удалось отправить фото, отправляем текст
await this.bot.sendMessage(chatId, '🖼 Фото недоступно\n\n' + candidateText, {
reply_markup: keyboard
});
}
} else {
// Отправляем как текстовое сообщение
await this.bot.sendMessage(chatId, '📝 ' + candidateText, {
reply_markup: keyboard
});
}
}
// Получить текст цели знакомства
private getDatingGoalText(goal: string): string {
const goals: { [key: string]: string } = {
'serious': 'Серьёзные отношения',
'casual': 'Лёгкие отношения',
'friends': 'Дружба',
'unsure': 'Пока не определился',
'one_night': 'Отношения на одну ночь',
'fwb': 'Друзья с привилегиями',
'marriage_abroad': 'Брак с переездом',
'sugar': 'Спонсорство',
'polyamory': 'Полиамория'
};
return goals[goal] || goal;
}
// Получить текст образа жизни
private getLifestyleText(lifestyle: any): string {
const parts: string[] = [];
if (lifestyle?.smoking) {
const smokingTexts: { [key: string]: string } = {
'never': 'Не курю',
'sometimes': 'Иногда курю',
'regularly': 'Курю'
};
parts.push('🚬 ' + (smokingTexts[lifestyle.smoking] || lifestyle.smoking));
}
if (lifestyle?.drinking) {
const drinkingTexts: { [key: string]: string } = {
'never': 'Не пью',
'sometimes': 'Иногда пью',
'regularly': 'Пью'
};
parts.push('🍷 ' + (drinkingTexts[lifestyle.drinking] || lifestyle.drinking));
}
if (lifestyle?.kids) {
const kidsTexts: { [key: string]: string } = {
'have': 'Есть дети',
'want': 'Хочу детей',
'dont_want': 'Не хочу детей',
'unsure': 'Пока не знаю'
};
parts.push('👶 ' + (kidsTexts[lifestyle.kids] || lifestyle.kids));
}
return parts.join(', ');
}
}