init commit

This commit is contained in:
2025-09-12 21:25:54 +09:00
commit 17efb2fb53
37 changed files with 12637 additions and 0 deletions

View File

@@ -0,0 +1,802 @@
import TelegramBot, { CallbackQuery, InlineKeyboardMarkup } from 'node-telegram-bot-api';
import { ProfileService } from '../services/profileService';
import { MatchingService } from '../services/matchingService';
import { ChatService } from '../services/chatService';
import { Profile } from '../models/Profile';
import { MessageHandlers } from './messageHandlers';
export class CallbackHandlers {
private bot: TelegramBot;
private profileService: ProfileService;
private matchingService: MatchingService;
private chatService: ChatService;
private messageHandlers: MessageHandlers;
constructor(bot: TelegramBot, messageHandlers: MessageHandlers) {
this.bot = bot;
this.profileService = new ProfileService();
this.matchingService = new MatchingService();
this.chatService = new ChatService();
this.messageHandlers = messageHandlers;
}
register(): void {
this.bot.on('callback_query', (query) => this.handleCallback(query));
}
async handleCallback(query: CallbackQuery): Promise<void> {
if (!query.data || !query.from || !query.message) return;
const telegramId = query.from.id.toString();
const chatId = query.message.chat.id;
const data = query.data;
try {
// Основные действия профиля
if (data === 'create_profile') {
await this.handleCreateProfile(chatId, telegramId);
} else if (data.startsWith('gender_')) {
const gender = data.replace('gender_', '');
await this.handleGenderSelection(chatId, telegramId, gender);
} else if (data === 'view_my_profile') {
await this.handleViewMyProfile(chatId, telegramId);
} else if (data === 'edit_profile') {
await this.handleEditProfile(chatId, telegramId);
} else if (data === 'manage_photos') {
await this.handleManagePhotos(chatId, telegramId);
}
// Просмотр анкет и свайпы
else if (data === 'start_browsing') {
await this.handleStartBrowsing(chatId, telegramId);
} else if (data === 'next_candidate') {
await this.handleNextCandidate(chatId, telegramId);
} else if (data.startsWith('like_')) {
const targetUserId = data.replace('like_', '');
await this.handleLike(chatId, telegramId, targetUserId);
} else if (data.startsWith('dislike_')) {
const targetUserId = data.replace('dislike_', '');
await this.handleDislike(chatId, telegramId, targetUserId);
} else if (data.startsWith('superlike_')) {
const targetUserId = data.replace('superlike_', '');
await this.handleSuperlike(chatId, telegramId, targetUserId);
} else if (data.startsWith('view_profile_')) {
const targetUserId = data.replace('view_profile_', '');
await this.handleViewProfile(chatId, telegramId, targetUserId);
} else if (data.startsWith('more_photos_')) {
const targetUserId = data.replace('more_photos_', '');
await this.handleMorePhotos(chatId, telegramId, targetUserId);
}
// Матчи и чаты
else if (data === 'view_matches') {
await this.handleViewMatches(chatId, telegramId);
} else if (data === 'open_chats') {
await this.handleOpenChats(chatId, telegramId);
} else if (data.startsWith('chat_')) {
const matchId = data.replace('chat_', '');
await this.handleOpenChat(chatId, telegramId, matchId);
} else if (data.startsWith('send_message_')) {
const matchId = data.replace('send_message_', '');
await this.handleSendMessage(chatId, telegramId, matchId);
} else if (data.startsWith('view_chat_profile_')) {
const matchId = data.replace('view_chat_profile_', '');
await this.handleViewChatProfile(chatId, telegramId, matchId);
} else if (data.startsWith('unmatch_')) {
const matchId = data.replace('unmatch_', '');
await this.handleUnmatch(chatId, telegramId, matchId);
} else if (data.startsWith('confirm_unmatch_')) {
const matchId = data.replace('confirm_unmatch_', '');
await this.handleConfirmUnmatch(chatId, telegramId, matchId);
}
// Настройки
else if (data === 'settings') {
await this.handleSettings(chatId, telegramId);
} else if (data === 'search_settings') {
await this.handleSearchSettings(chatId, telegramId);
} else if (data === 'notification_settings') {
await this.handleNotificationSettings(chatId, telegramId);
}
// Информация
else if (data === 'how_it_works') {
await this.handleHowItWorks(chatId);
} else if (data === 'back_to_browsing') {
await this.handleStartBrowsing(chatId, telegramId);
}
else {
await this.bot.answerCallbackQuery(query.id, {
text: 'Функция в разработке!',
show_alert: false
});
return;
}
await this.bot.answerCallbackQuery(query.id);
} catch (error) {
console.error('Callback handler error:', error);
await this.bot.answerCallbackQuery(query.id, {
text: 'Произошла ошибка. Попробуйте еще раз.',
show_alert: true
});
}
}
// Создание профиля
async handleCreateProfile(chatId: number, telegramId: string): Promise<void> {
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[{ text: '👨 Мужской', callback_data: 'gender_male' }],
[{ text: '👩 Женский', callback_data: 'gender_female' }],
[{ text: '🔀 Другой', callback_data: 'gender_other' }]
]
};
await this.bot.sendMessage(
chatId,
'👋 Давайте создадим ваш профиль!\n\n' +
'🚹🚺 Сначала выберите ваш пол:',
{ reply_markup: keyboard }
);
}
// Выбор пола
async handleGenderSelection(chatId: number, telegramId: string, gender: string): Promise<void> {
this.messageHandlers.startProfileCreation(telegramId, gender);
await this.bot.sendMessage(
chatId,
'👍 Отлично!\n\n📝 Теперь напишите ваше имя:'
);
}
// Просмотр собственного профиля
async handleViewMyProfile(chatId: number, telegramId: string): Promise<void> {
const profile = await this.profileService.getProfileByTelegramId(telegramId);
if (!profile) {
await this.bot.sendMessage(chatId, '❌ Профиль не найден');
return;
}
await this.showProfile(chatId, profile, true);
}
// Редактирование профиля
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 }
);
}
// Управление фотографиями
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 }
);
}
// Начать просмотр анкет
async handleStartBrowsing(chatId: number, telegramId: string): Promise<void> {
const profile = await this.profileService.getProfileByTelegramId(telegramId);
if (!profile) {
await this.bot.sendMessage(chatId, '❌ Сначала создайте профиль!');
return;
}
await this.showNextCandidate(chatId, telegramId);
}
// Следующий кандидат
async handleNextCandidate(chatId: number, telegramId: string): Promise<void> {
await this.showNextCandidate(chatId, telegramId);
}
// Лайк
async handleLike(chatId: number, telegramId: string, targetUserId: string): Promise<void> {
try {
const result = await this.matchingService.performSwipe(telegramId, targetUserId, 'like');
if (result.isMatch) {
// Это матч!
const targetProfile = await this.profileService.getProfileByUserId(targetUserId);
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[
{ text: '💬 Написать сообщение', callback_data: 'chat_' + targetUserId },
{ text: '👤 Посмотреть профиль', callback_data: 'view_profile_' + targetUserId }
],
[{ text: '🔍 Продолжить поиск', callback_data: 'next_candidate' }]
]
};
await this.bot.sendMessage(
chatId,
'🎉 ЭТО МАТЧ! 💕\n\n' +
'Вы понравились друг другу с ' + (targetProfile?.name || 'этим пользователем') + '!\n\n' +
'Теперь вы можете начать общение!',
{ reply_markup: keyboard }
);
} else {
await this.bot.sendMessage(chatId, '👍 Лайк отправлен!');
await this.showNextCandidate(chatId, telegramId);
}
} catch (error) {
await this.bot.sendMessage(chatId, '❌ Ошибка при отправке лайка');
console.error('Like error:', error);
}
}
// Дизлайк
async handleDislike(chatId: number, telegramId: string, targetUserId: string): Promise<void> {
try {
await this.matchingService.performSwipe(telegramId, targetUserId, 'pass');
await this.showNextCandidate(chatId, telegramId);
} catch (error) {
await this.bot.sendMessage(chatId, '❌ Ошибка при отправке дизлайка');
console.error('Dislike error:', error);
}
}
// Супер лайк
async handleSuperlike(chatId: number, telegramId: string, targetUserId: string): Promise<void> {
try {
const result = await this.matchingService.performSwipe(telegramId, targetUserId, 'superlike');
if (result.isMatch) {
const targetProfile = await this.profileService.getProfileByUserId(targetUserId);
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[
{ text: '💬 Написать сообщение', callback_data: 'chat_' + targetUserId },
{ text: '👤 Посмотреть профиль', callback_data: 'view_profile_' + targetUserId }
],
[{ text: '🔍 Продолжить поиск', callback_data: 'next_candidate' }]
]
};
await this.bot.sendMessage(
chatId,
'💖 СУПЕР МАТЧ! ⭐\n\n' +
'Ваш супер лайк произвел впечатление на ' + (targetProfile?.name || 'этого пользователя') + '!\n\n' +
'Начните общение первыми!',
{ reply_markup: keyboard }
);
} else {
await this.bot.sendMessage(chatId, '💖 Супер лайк отправлен!');
await this.showNextCandidate(chatId, telegramId);
}
} catch (error) {
await this.bot.sendMessage(chatId, '❌ Ошибка при отправке супер лайка');
console.error('Superlike error:', error);
}
}
// Просмотр профиля кандидата
async handleViewProfile(chatId: number, telegramId: string, targetUserId: string): Promise<void> {
const targetProfile = await this.profileService.getProfileByUserId(targetUserId);
if (!targetProfile) {
await this.bot.sendMessage(chatId, '❌ Профиль не найден');
return;
}
await this.showProfile(chatId, targetProfile, false, telegramId);
}
// Показать больше фотографий
async handleMorePhotos(chatId: number, telegramId: string, targetUserId: string): Promise<void> {
const targetProfile = await this.profileService.getProfileByUserId(targetUserId);
if (!targetProfile || targetProfile.photos.length <= 1) {
await this.bot.sendMessage(chatId, '📷 У пользователя нет дополнительных фотографий');
return;
}
for (let i = 1; i < targetProfile.photos.length; i++) {
const photoFileId = targetProfile.photos[i];
await this.bot.sendPhoto(chatId, photoFileId);
}
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[
{ text: '👎 Не нравится', callback_data: 'dislike_' + targetUserId },
{ text: '💖 Супер лайк', callback_data: 'superlike_' + targetUserId },
{ text: '👍 Нравится', callback_data: 'like_' + targetUserId }
]
]
};
await this.bot.sendMessage(
chatId,
'📸 Все фотографии просмотрены!\n\nВаше решение?',
{ reply_markup: keyboard }
);
}
// Просмотр матчей
async handleViewMatches(chatId: number, telegramId: string): Promise<void> {
const matches = await this.matchingService.getUserMatches(telegramId);
if (matches.length === 0) {
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[{ text: '🔍 Начать поиск', callback_data: 'start_browsing' }]
]
};
await this.bot.sendMessage(
chatId,
'💔 У вас пока нет матчей\n\n' +
'Попробуйте просмотреть больше анкет!',
{ reply_markup: keyboard }
);
return;
}
let matchText = 'Ваши матчи (' + matches.length + '):\n\n';
for (const match of matches) {
const otherUserId = match.userId1 === telegramId ? match.userId2 : match.userId1;
const otherProfile = await this.profileService.getProfileByUserId(otherUserId);
if (otherProfile) {
matchText += '💖 ' + otherProfile.name + ', ' + otherProfile.age + '\n';
matchText += '📍 ' + (otherProfile.city || 'Не указан') + '\n\n';
}
}
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[{ text: '💬 Открыть чаты', callback_data: 'open_chats' }],
[{ text: '🔍 Найти еще', callback_data: 'start_browsing' }]
]
};
await this.bot.sendMessage(chatId, matchText, { reply_markup: keyboard });
}
// Открыть чаты
// Открыть список чатов
async handleOpenChats(chatId: number, telegramId: string): Promise<void> {
const chats = await this.chatService.getUserChats(telegramId);
if (chats.length === 0) {
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[{ text: '🔍 Найти матчи', callback_data: 'start_browsing' }],
[{ text: '💕 Мои матчи', callback_data: 'view_matches' }]
]
};
await this.bot.sendMessage(
chatId,
'💬 У вас пока нет активных чатов\n\n' +
'Начните просматривать анкеты и получите первые матчи!',
{ reply_markup: keyboard }
);
return;
}
let messageText = '💬 Ваши чаты:\n\n';
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: []
};
for (const chat of chats.slice(0, 10)) { // Показываем только первые 10 чатов
const unreadBadge = chat.unreadCount > 0 ? ` (${chat.unreadCount})` : '';
const lastMessagePreview = chat.lastMessage
? (chat.lastMessage.length > 30
? chat.lastMessage.substring(0, 30) + '...'
: chat.lastMessage)
: 'Новый матч';
messageText += `💕 ${chat.otherUserName}${unreadBadge}\n`;
messageText += `💬 ${lastMessagePreview}\n\n`;
keyboard.inline_keyboard.push([
{ text: `💬 ${chat.otherUserName}${unreadBadge}`, callback_data: `chat_${chat.matchId}` }
]);
}
if (chats.length > 10) {
messageText += `...и еще ${chats.length - 10} чатов`;
}
keyboard.inline_keyboard.push([
{ text: '🔍 Найти еще', callback_data: 'start_browsing' },
{ text: '💕 Матчи', callback_data: 'view_matches' }
]);
await this.bot.sendMessage(chatId, messageText, { reply_markup: keyboard });
}
// Открыть конкретный чат
async handleOpenChat(chatId: number, telegramId: string, matchId: string): Promise<void> {
const matchInfo = await this.chatService.getMatchInfo(matchId, telegramId);
if (!matchInfo) {
await this.bot.sendMessage(chatId, '❌ Чат не найден или недоступен');
return;
}
// Отмечаем сообщения как прочитанные
await this.chatService.markMessagesAsRead(matchId, telegramId);
// Получаем последние сообщения
const messages = await this.chatService.getChatMessages(matchId, 10);
let chatText = `💬 Чат с ${matchInfo.otherUserProfile?.name}\n\n`;
if (messages.length === 0) {
chatText += '📝 Начните общение! Напишите первое сообщение.\n\n';
} else {
chatText += '📝 Последние сообщения:\n\n';
for (const message of messages.slice(-5)) { // Показываем последние 5 сообщений
const currentUserId = await this.profileService.getUserIdByTelegramId(telegramId);
const isFromMe = message.senderId === currentUserId;
const sender = isFromMe ? 'Вы' : matchInfo.otherUserProfile?.name;
const time = message.createdAt.toLocaleTimeString('ru-RU', {
hour: '2-digit',
minute: '2-digit'
});
chatText += `${sender} (${time}):\n${message.content}\n\n`;
}
}
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[
{ text: '✍️ Написать сообщение', callback_data: `send_message_${matchId}` }
],
[
{ text: '👤 Профиль', callback_data: `view_chat_profile_${matchId}` },
{ text: '💔 Удалить матч', callback_data: `unmatch_${matchId}` }
],
[
{ text: '← Назад к чатам', callback_data: 'open_chats' }
]
]
};
await this.bot.sendMessage(chatId, chatText, { reply_markup: keyboard });
}
// Отправить сообщение
async handleSendMessage(chatId: number, telegramId: string, matchId: string): Promise<void> {
const matchInfo = await this.chatService.getMatchInfo(matchId, telegramId);
if (!matchInfo) {
await this.bot.sendMessage(chatId, '❌ Чат не найден или недоступен');
return;
}
// Устанавливаем состояние ожидания сообщения
this.messageHandlers.setWaitingForMessage(telegramId, matchId);
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[{ text: '❌ Отмена', callback_data: `chat_${matchId}` }]
]
};
await this.bot.sendMessage(
chatId,
`✍️ Напишите сообщение для ${matchInfo.otherUserProfile?.name}:\n\n` +
'💡 Просто отправьте текст в этот чат',
{ reply_markup: keyboard }
);
}
// Просмотр профиля в чате
async handleViewChatProfile(chatId: number, telegramId: string, matchId: string): Promise<void> {
const matchInfo = await this.chatService.getMatchInfo(matchId, telegramId);
if (!matchInfo || !matchInfo.otherUserProfile) {
await this.bot.sendMessage(chatId, '❌ Профиль не найден');
return;
}
await this.showProfile(chatId, matchInfo.otherUserProfile, false, telegramId);
}
// Удалить матч (размэтчиться)
async handleUnmatch(chatId: number, telegramId: string, matchId: string): Promise<void> {
const matchInfo = await this.chatService.getMatchInfo(matchId, telegramId);
if (!matchInfo) {
await this.bot.sendMessage(chatId, '❌ Матч не найден');
return;
}
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[
{ text: '✅ Да, удалить', callback_data: `confirm_unmatch_${matchId}` },
{ text: '❌ Отмена', callback_data: `chat_${matchId}` }
]
]
};
await this.bot.sendMessage(
chatId,
`💔 Вы уверены, что хотите удалить матч с ${matchInfo.otherUserProfile?.name}?\n\n` +
'⚠️ Это действие нельзя отменить. Вся переписка будет удалена.',
{ reply_markup: keyboard }
);
}
// Подтвердить удаление матча
async handleConfirmUnmatch(chatId: number, telegramId: string, matchId: string): Promise<void> {
const success = await this.chatService.unmatch(matchId, telegramId);
if (success) {
await this.bot.sendMessage(
chatId,
'💔 Матч удален\n\n' +
'Вы больше не увидите этого пользователя в своих матчах.'
);
// Возвращаемся к списку чатов
setTimeout(() => {
this.handleOpenChats(chatId, telegramId);
}, 2000);
} else {
await this.bot.sendMessage(chatId, '❌ Не удалось удалить матч. Попробуйте еще раз.');
}
}
// Настройки
async handleSettings(chatId: number, telegramId: string): 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(
chatId,
'⚙️ Настройки профиля\n\nВыберите что хотите изменить:',
{ reply_markup: keyboard }
);
}
// Настройки поиска
async handleSearchSettings(chatId: number, telegramId: string): Promise<void> {
await this.bot.sendMessage(
chatId,
'🔍 Настройки поиска будут доступны в следующем обновлении!'
);
}
// Настройки уведомлений
async handleNotificationSettings(chatId: number, telegramId: string): Promise<void> {
await this.bot.sendMessage(
chatId,
'🔔 Настройки уведомлений будут доступны в следующем обновлении!'
);
}
// Как это работает
async handleHowItWorks(chatId: number): Promise<void> {
const helpText =
'🎯 Как работает Telegram Tinder Bot?\n\n' +
'1⃣ Создайте профиль\n' +
' • Добавьте фото и описание\n' +
' • Укажите ваши предпочтения\n\n' +
'2⃣ Просматривайте анкеты\n' +
' • Ставьте лайки понравившимся\n' +
' • Используйте супер лайки для особых случаев\n\n' +
'3⃣ Получайте матчи\n' +
' • Когда ваш лайк взаимен - это матч!\n' +
' • Начинайте общение\n\n' +
'4⃣ Общайтесь и знакомьтесь\n' +
' • Находите общие интересы\n' +
' • Договаривайтесь о встрече\n\n' +
'<27><> Советы:\n' +
'• Используйте качественные фото\n' +
'• Напишите интересное описание\n' +
'• Будьте вежливы в общении\n\n' +
'❤️ Удачи в поиске любви!';
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[{ text: '🚀 Создать профиль', callback_data: 'create_profile' }]
]
};
await this.bot.sendMessage(chatId, helpText, { reply_markup: keyboard });
}
// Вспомогательные методы
async showProfile(chatId: number, profile: Profile, isOwner: boolean = false, viewerId?: string): 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(', ');
}
let keyboard: InlineKeyboardMarkup;
if (isOwner) {
keyboard = {
inline_keyboard: [
[
{ text: '✏️ Редактировать', callback_data: 'edit_profile' },
{ text: '📸 Фото', callback_data: 'manage_photos' }
],
[{ text: '🔍 Начать поиск', callback_data: 'start_browsing' }]
]
};
} else {
keyboard = {
inline_keyboard: [
[
{ text: '👎 Не нравится', callback_data: 'dislike_' + profile.userId },
{ text: '💖 Супер лайк', callback_data: 'superlike_' + profile.userId },
{ text: '👍 Нравится', callback_data: 'like_' + profile.userId }
],
[{ text: '🔍 Продолжить поиск', callback_data: 'next_candidate' }]
]
};
}
// Проверяем, есть ли валидное фото (file_id или URL)
const hasValidPhoto = mainPhotoFileId &&
(mainPhotoFileId.startsWith('http') ||
mainPhotoFileId.startsWith('AgAC') ||
mainPhotoFileId.length > 20); // file_id обычно длинные
if (hasValidPhoto) {
try {
await this.bot.sendPhoto(chatId, mainPhotoFileId, {
caption: profileText,
reply_markup: keyboard
});
} catch (error) {
// Если не удалось отправить фото, отправляем текст
await this.bot.sendMessage(chatId, '🖼 Фото недоступно\n\n' + profileText, {
reply_markup: keyboard
});
}
} else {
// Отправляем как текстовое сообщение
await this.bot.sendMessage(chatId, profileText, {
reply_markup: keyboard
});
}
}
async showNextCandidate(chatId: number, telegramId: string): Promise<void> {
const candidate = await this.matchingService.getNextCandidate(telegramId);
if (!candidate) {
const keyboard: InlineKeyboardMarkup = {
inline_keyboard: [
[{ text: '🔄 Попробовать еще раз', callback_data: 'start_browsing' }],
[{ text: '💕 Мои матчи', callback_data: 'view_matches' }]
]
};
await this.bot.sendMessage(
chatId,
'🎉 Вы просмотрели всех доступных кандидатов!\n\n' +
'⏰ Попробуйте позже - возможно появятся новые анкеты!',
{ reply_markup: keyboard }
);
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 += '<27><> ' + 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' }]
]
};
// Проверяем, есть ли валидное фото (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
});
}
}
}