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:
@@ -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(', ');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,9 @@ export class CommandHandlers {
|
||||
],
|
||||
[
|
||||
{ text: '💕 Мои матчи', callback_data: 'view_matches' },
|
||||
{ text: '⭐ VIP поиск', callback_data: 'vip_search' }
|
||||
],
|
||||
[
|
||||
{ text: '⚙️ Настройки', callback_data: 'settings' }
|
||||
]
|
||||
]
|
||||
|
||||
@@ -14,12 +14,19 @@ interface ChatState {
|
||||
matchId: string;
|
||||
}
|
||||
|
||||
// Состояния пользователей для редактирования профиля
|
||||
interface ProfileEditState {
|
||||
waitingForInput: boolean;
|
||||
field: string;
|
||||
}
|
||||
|
||||
export class MessageHandlers {
|
||||
private bot: TelegramBot;
|
||||
private profileService: ProfileService;
|
||||
private chatService: ChatService;
|
||||
private userStates: Map<string, UserState> = new Map();
|
||||
private chatStates: Map<string, ChatState> = new Map();
|
||||
private profileEditStates: Map<string, ProfileEditState> = new Map();
|
||||
|
||||
constructor(bot: TelegramBot) {
|
||||
this.bot = bot;
|
||||
@@ -42,6 +49,7 @@ export class MessageHandlers {
|
||||
|
||||
const userState = this.userStates.get(userId);
|
||||
const chatState = this.chatStates.get(userId);
|
||||
const profileEditState = this.profileEditStates.get(userId);
|
||||
|
||||
// Если пользователь в процессе отправки сообщения в чат
|
||||
if (chatState?.waitingForMessage && msg.text) {
|
||||
@@ -49,6 +57,12 @@ export class MessageHandlers {
|
||||
return;
|
||||
}
|
||||
|
||||
// Если пользователь редактирует профиль
|
||||
if (profileEditState?.waitingForInput) {
|
||||
await this.handleProfileEdit(msg, userId, profileEditState.field);
|
||||
return;
|
||||
}
|
||||
|
||||
// Если пользователь в процессе создания профиля
|
||||
if (userState) {
|
||||
await this.handleProfileCreation(msg, userId, userState);
|
||||
@@ -312,4 +326,206 @@ export class MessageHandlers {
|
||||
await this.bot.sendMessage(msg.chat.id, '❌ Не удалось отправить сообщение. Попробуйте еще раз.');
|
||||
}
|
||||
}
|
||||
|
||||
// ===== МЕТОДЫ ДЛЯ РЕДАКТИРОВАНИЯ ПРОФИЛЯ =====
|
||||
|
||||
// Установить состояние ожидания ввода для редактирования профиля
|
||||
setWaitingForInput(telegramId: number, field: string): void {
|
||||
this.profileEditStates.set(telegramId.toString(), {
|
||||
waitingForInput: true,
|
||||
field: field
|
||||
});
|
||||
}
|
||||
|
||||
// Очистить состояние редактирования профиля
|
||||
clearProfileEditState(userId: string): void {
|
||||
this.profileEditStates.delete(userId);
|
||||
}
|
||||
|
||||
// Обработка редактирования профиля
|
||||
async handleProfileEdit(msg: Message, userId: string, field: string): Promise<void> {
|
||||
const chatId = msg.chat.id;
|
||||
|
||||
try {
|
||||
let value: any = msg.text;
|
||||
let isValid = true;
|
||||
let errorMessage = '';
|
||||
|
||||
// Валидация в зависимости от поля
|
||||
switch (field) {
|
||||
case 'name':
|
||||
if (!value || value.length < 2 || value.length > 50) {
|
||||
isValid = false;
|
||||
errorMessage = 'Имя должно быть от 2 до 50 символов';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'age':
|
||||
const age = parseInt(value);
|
||||
if (isNaN(age) || age < 18 || age > 100) {
|
||||
isValid = false;
|
||||
errorMessage = 'Возраст должен быть числом от 18 до 100';
|
||||
}
|
||||
value = age;
|
||||
break;
|
||||
|
||||
case 'bio':
|
||||
if (value && value.length > 500) {
|
||||
isValid = false;
|
||||
errorMessage = 'Описание не должно превышать 500 символов';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'height':
|
||||
const height = parseInt(value);
|
||||
if (isNaN(height) || height < 100 || height > 250) {
|
||||
isValid = false;
|
||||
errorMessage = 'Рост должен быть числом от 100 до 250 см';
|
||||
}
|
||||
value = height;
|
||||
break;
|
||||
|
||||
case 'photo':
|
||||
if (!msg.photo || !msg.photo.length) {
|
||||
isValid = false;
|
||||
errorMessage = 'Отправьте фотографию';
|
||||
} else {
|
||||
// Берём фото наибольшего размера
|
||||
value = msg.photo[msg.photo.length - 1].file_id;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'age_range':
|
||||
const ageRangeParts = value.split('-');
|
||||
if (ageRangeParts.length !== 2) {
|
||||
isValid = false;
|
||||
errorMessage = 'Неверный формат. Используйте: минимальный-максимальный возраст (например: 18-35)';
|
||||
} else {
|
||||
const minAge = parseInt(ageRangeParts[0]);
|
||||
const maxAge = parseInt(ageRangeParts[1]);
|
||||
if (isNaN(minAge) || isNaN(maxAge) || minAge < 18 || maxAge > 100 || minAge >= maxAge) {
|
||||
isValid = false;
|
||||
errorMessage = 'Возраст должен быть от 18 до 100, минимальный меньше максимального';
|
||||
}
|
||||
value = { minAge, maxAge };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'distance':
|
||||
const distance = parseInt(value);
|
||||
if (isNaN(distance) || distance < 1 || distance > 1000) {
|
||||
isValid = false;
|
||||
errorMessage = 'Расстояние должно быть числом от 1 до 1000 км';
|
||||
}
|
||||
value = distance;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
await this.bot.sendMessage(chatId, `❌ ${errorMessage}\n\nПопробуйте еще раз:`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Обновляем профиль
|
||||
await this.updateProfileField(userId, field, value);
|
||||
|
||||
// Очищаем состояние
|
||||
this.clearProfileEditState(userId);
|
||||
|
||||
// Отправляем подтверждение и возвращаем к меню редактирования
|
||||
await this.bot.sendMessage(chatId, '✅ Данные успешно обновлены!');
|
||||
|
||||
setTimeout(async () => {
|
||||
const keyboard = {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: '✏️ Продолжить редактирование', callback_data: 'edit_profile' },
|
||||
{ text: '👀 Предпросмотр', callback_data: 'preview_profile' }
|
||||
],
|
||||
[
|
||||
{ text: '⬅️ Главное меню', callback_data: 'main_menu' }
|
||||
]
|
||||
]
|
||||
};
|
||||
|
||||
await this.bot.sendMessage(
|
||||
chatId,
|
||||
'🛠️ Что дальше?',
|
||||
{ reply_markup: keyboard }
|
||||
);
|
||||
}, 1000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error handling profile edit:', error);
|
||||
await this.bot.sendMessage(chatId, '❌ Произошла ошибка. Попробуйте еще раз.');
|
||||
this.clearProfileEditState(userId);
|
||||
}
|
||||
}
|
||||
|
||||
// Обновление поля профиля
|
||||
async updateProfileField(userId: string, field: string, value: any): Promise<void> {
|
||||
const profile = await this.profileService.getProfileByTelegramId(userId);
|
||||
if (!profile) {
|
||||
throw new Error('Profile not found');
|
||||
}
|
||||
|
||||
const updates: any = {};
|
||||
|
||||
switch (field) {
|
||||
case 'name':
|
||||
updates.name = value;
|
||||
break;
|
||||
case 'age':
|
||||
updates.age = value;
|
||||
break;
|
||||
case 'bio':
|
||||
updates.bio = value;
|
||||
break;
|
||||
case 'hobbies':
|
||||
updates.hobbies = value;
|
||||
break;
|
||||
case 'city':
|
||||
// В БД поле называется 'location', но мы используем city в модели
|
||||
updates.city = value;
|
||||
break;
|
||||
case 'job':
|
||||
// В БД поле называется 'occupation', но мы используем job в модели
|
||||
updates.job = value;
|
||||
break;
|
||||
case 'education':
|
||||
updates.education = value;
|
||||
break;
|
||||
case 'height':
|
||||
updates.height = value;
|
||||
break;
|
||||
case 'religion':
|
||||
updates.religion = value === 'нет' ? null : value;
|
||||
break;
|
||||
case 'age_range':
|
||||
updates.searchPreferences = {
|
||||
minAge: value.minAge,
|
||||
maxAge: value.maxAge,
|
||||
maxDistance: profile.searchPreferences?.maxDistance || 50
|
||||
};
|
||||
break;
|
||||
case 'distance':
|
||||
updates.searchPreferences = {
|
||||
minAge: profile.searchPreferences?.minAge || 18,
|
||||
maxAge: profile.searchPreferences?.maxAge || 50,
|
||||
maxDistance: value
|
||||
};
|
||||
break;
|
||||
case 'photo':
|
||||
// Добавляем фото к существующим
|
||||
profile.addPhoto(value);
|
||||
await this.profileService.updateProfile(profile.userId, {
|
||||
photos: profile.photos
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (Object.keys(updates).length > 0) {
|
||||
await this.profileService.updateProfile(profile.userId, updates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user