Fix JSON format issues with photos and add multi-photo gallery support
This commit is contained in:
@@ -10,6 +10,7 @@ import { VipController } from '../controllers/vipController';
|
||||
import { VipService } from '../services/vipService';
|
||||
import { TranslationController } from '../controllers/translationController';
|
||||
import { t } from '../services/localizationService';
|
||||
import { LikeBackHandler } from './likeBackHandler';
|
||||
|
||||
export class CallbackHandlers {
|
||||
private bot: TelegramBot;
|
||||
@@ -22,6 +23,7 @@ export class CallbackHandlers {
|
||||
private vipController: VipController;
|
||||
private vipService: VipService;
|
||||
private translationController: TranslationController;
|
||||
private likeBackHandler: LikeBackHandler;
|
||||
|
||||
constructor(bot: TelegramBot, messageHandlers: MessageHandlers) {
|
||||
this.bot = bot;
|
||||
@@ -34,6 +36,7 @@ export class CallbackHandlers {
|
||||
this.vipController = new VipController(bot);
|
||||
this.vipService = new VipService();
|
||||
this.translationController = new TranslationController();
|
||||
this.likeBackHandler = new LikeBackHandler(bot);
|
||||
}
|
||||
|
||||
register(): void {
|
||||
@@ -167,6 +170,12 @@ export class CallbackHandlers {
|
||||
await this.handleMorePhotos(chatId, telegramId, targetUserId);
|
||||
}
|
||||
|
||||
// Обработка лайков и ответных лайков из уведомлений
|
||||
else if (data.startsWith('like_back:')) {
|
||||
const targetUserId = data.replace('like_back:', '');
|
||||
await this.likeBackHandler.handleLikeBack(chatId, telegramId, targetUserId);
|
||||
}
|
||||
|
||||
// Матчи и чаты
|
||||
else if (data === 'view_matches') {
|
||||
await this.handleViewMatches(chatId, telegramId);
|
||||
@@ -385,9 +394,15 @@ export class CallbackHandlers {
|
||||
await this.bot.sendMessage(chatId, '👍 Лайк отправлен!');
|
||||
await this.showNextCandidate(chatId, telegramId);
|
||||
}
|
||||
} catch (error) {
|
||||
await this.bot.sendMessage(chatId, '❌ Ошибка при отправке лайка');
|
||||
console.error('Like error:', error);
|
||||
} catch (error: any) {
|
||||
// Проверяем, связана ли ошибка с уже существующим свайпом
|
||||
if (error.message === 'Already swiped this profile' || error.code === 'ALREADY_SWIPED') {
|
||||
await this.bot.sendMessage(chatId, '❓ Вы уже оценивали этот профиль ранее');
|
||||
await this.showNextCandidate(chatId, telegramId);
|
||||
} else {
|
||||
await this.bot.sendMessage(chatId, '❌ Ошибка при отправке лайка');
|
||||
console.error('Like error:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,9 +417,15 @@ export class CallbackHandlers {
|
||||
|
||||
await this.matchingService.performSwipe(telegramId, targetTelegramId, 'pass');
|
||||
await this.showNextCandidate(chatId, telegramId);
|
||||
} catch (error) {
|
||||
await this.bot.sendMessage(chatId, '❌ Ошибка при отправке дизлайка');
|
||||
console.error('Dislike error:', error);
|
||||
} catch (error: any) {
|
||||
// Проверяем, связана ли ошибка с уже существующим свайпом
|
||||
if (error.message === 'Already swiped this profile' || error.code === 'ALREADY_SWIPED') {
|
||||
await this.bot.sendMessage(chatId, '❓ Вы уже оценивали этот профиль ранее');
|
||||
await this.showNextCandidate(chatId, telegramId);
|
||||
} else {
|
||||
await this.bot.sendMessage(chatId, '❌ Ошибка при отправке дизлайка');
|
||||
console.error('Dislike error:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,9 +464,73 @@ export class CallbackHandlers {
|
||||
await this.bot.sendMessage(chatId, '💖 Супер лайк отправлен!');
|
||||
await this.showNextCandidate(chatId, telegramId);
|
||||
}
|
||||
} catch (error: any) {
|
||||
// Проверяем, связана ли ошибка с уже существующим свайпом
|
||||
if (error.message === 'Already swiped this profile' || error.code === 'ALREADY_SWIPED') {
|
||||
await this.bot.sendMessage(chatId, '❓ Вы уже оценивали этот профиль ранее');
|
||||
await this.showNextCandidate(chatId, telegramId);
|
||||
} else {
|
||||
await this.bot.sendMessage(chatId, '❌ Ошибка при отправке супер лайка');
|
||||
console.error('Superlike error:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Обработка обратного лайка из уведомления
|
||||
async handleLikeBack(chatId: number, telegramId: string, targetUserId: string): Promise<void> {
|
||||
try {
|
||||
// Получаем информацию о пользователях
|
||||
const targetProfile = await this.profileService.getProfileByUserId(targetUserId);
|
||||
|
||||
if (!targetProfile) {
|
||||
await this.bot.sendMessage(chatId, '❌ Не удалось найти профиль');
|
||||
return;
|
||||
}
|
||||
|
||||
// Получаем telegram ID целевого пользователя для свайпа
|
||||
const targetTelegramId = await this.profileService.getTelegramIdByUserId(targetUserId);
|
||||
if (!targetTelegramId) {
|
||||
await this.bot.sendMessage(chatId, '❌ Не удалось найти пользователя');
|
||||
return;
|
||||
}
|
||||
|
||||
// Выполняем свайп
|
||||
const result = await this.matchingService.performSwipe(telegramId, targetTelegramId, 'like');
|
||||
|
||||
if (result.isMatch) {
|
||||
// Это матч!
|
||||
await this.bot.sendMessage(
|
||||
chatId,
|
||||
'🎉 *Поздравляем! Это взаимно!*\n\n' +
|
||||
`Вы и *${targetProfile.name}* понравились друг другу!\n` +
|
||||
'Теперь вы можете начать общение.',
|
||||
{
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: '💬 Начать общение', callback_data: `start_chat:${targetUserId}` }],
|
||||
[{ text: '👀 Посмотреть профиль', callback_data: `view_profile:${targetUserId}` }]
|
||||
]
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
await this.bot.sendMessage(
|
||||
chatId,
|
||||
'❤️ Вам понравился профиль ' + targetProfile.name + '!\n\n' +
|
||||
'Если вы также понравитесь этому пользователю, будет создан матч.',
|
||||
{
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: '🔍 Продолжить поиск', callback_data: 'start_browsing' }]
|
||||
]
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
await this.bot.sendMessage(chatId, '❌ Ошибка при отправке супер лайка');
|
||||
console.error('Superlike error:', error);
|
||||
console.error('Error in handleLikeBack:', error);
|
||||
await this.bot.sendMessage(chatId, '❌ Произошла ошибка при обработке лайка');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,9 +561,28 @@ export class CallbackHandlers {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 1; i < targetProfile.photos.length; i++) {
|
||||
const photoFileId = targetProfile.photos[i];
|
||||
await this.bot.sendPhoto(chatId, photoFileId);
|
||||
// Отправляем фотографии в виде медиа-группы (коллажа)
|
||||
// Создаем массив объектов медиа для группового отправления
|
||||
const mediaGroup = targetProfile.photos.slice(1).map((photoFileId, index) => ({
|
||||
type: 'photo' as const,
|
||||
media: photoFileId,
|
||||
caption: index === 0 ? `📸 Дополнительные фото ${targetProfile.name}` : undefined
|
||||
}));
|
||||
|
||||
try {
|
||||
// Отправляем все фото одним сообщением (медиа-группой)
|
||||
await this.bot.sendMediaGroup(chatId, mediaGroup);
|
||||
} catch (error) {
|
||||
console.error('Error sending media group:', error);
|
||||
|
||||
// Если не получилось отправить медиа-группой, отправляем по одной
|
||||
for (let i = 1; i < targetProfile.photos.length; i++) {
|
||||
try {
|
||||
await this.bot.sendPhoto(chatId, targetProfile.photos[i]);
|
||||
} catch (photoError) {
|
||||
console.error(`Error sending photo ${i}:`, photoError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const keyboard: InlineKeyboardMarkup = {
|
||||
@@ -807,6 +911,7 @@ export class CallbackHandlers {
|
||||
|
||||
// Вспомогательные методы
|
||||
async showProfile(chatId: number, profile: Profile, isOwner: boolean = false, viewerId?: string): Promise<void> {
|
||||
const hasMultiplePhotos = profile.photos.length > 1;
|
||||
const mainPhotoFileId = profile.photos[0]; // Первое фото - главное
|
||||
|
||||
let profileText = '👤 ' + profile.name + ', ' + profile.age + '\n';
|
||||
@@ -876,20 +981,43 @@ export class CallbackHandlers {
|
||||
|
||||
if (hasValidPhoto) {
|
||||
try {
|
||||
await this.bot.sendPhoto(chatId, mainPhotoFileId, {
|
||||
caption: profileText,
|
||||
reply_markup: keyboard
|
||||
});
|
||||
if (hasMultiplePhotos) {
|
||||
// Если есть несколько фото, отправляем их как медиа-группу (коллаж)
|
||||
const mediaGroup = profile.photos.map((photoFileId, index) => ({
|
||||
type: 'photo' as const,
|
||||
media: photoFileId,
|
||||
caption: index === 0 ? profileText : undefined,
|
||||
parse_mode: index === 0 ? 'Markdown' as const : undefined
|
||||
}));
|
||||
|
||||
// Сначала отправляем медиа-группу
|
||||
await this.bot.sendMediaGroup(chatId, mediaGroup);
|
||||
|
||||
// Затем отправляем отдельное сообщение с кнопками
|
||||
await this.bot.sendMessage(chatId, '📸 Выберите действие:', {
|
||||
reply_markup: keyboard
|
||||
});
|
||||
} else {
|
||||
// Если только одно фото, отправляем его с текстом
|
||||
await this.bot.sendPhoto(chatId, mainPhotoFileId, {
|
||||
caption: profileText,
|
||||
reply_markup: keyboard,
|
||||
parse_mode: 'Markdown'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error sending profile photos:', error);
|
||||
// Если не удалось отправить фото, отправляем текст
|
||||
await this.bot.sendMessage(chatId, '🖼 Фото недоступно\n\n' + profileText, {
|
||||
reply_markup: keyboard
|
||||
reply_markup: keyboard,
|
||||
parse_mode: 'Markdown'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Отправляем как текстовое сообщение
|
||||
await this.bot.sendMessage(chatId, profileText, {
|
||||
reply_markup: keyboard
|
||||
reply_markup: keyboard,
|
||||
parse_mode: 'Markdown'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,25 +168,24 @@ export class EnhancedChatHandlers {
|
||||
|
||||
// ===== СИСТЕМА УВЕДОМЛЕНИЙ =====
|
||||
|
||||
// Отправить уведомление о новом сообщении
|
||||
// Отправить уведомление о новом сообщении - теперь используем NotificationService
|
||||
async sendMessageNotification(receiverTelegramId: string, senderName: string, messagePreview: string, matchId: string): Promise<void> {
|
||||
try {
|
||||
const receiverChatId = parseInt(receiverTelegramId);
|
||||
// Получаем идентификаторы пользователей для использования в NotificationService
|
||||
const receiverUserId = await this.profileService.getUserIdByTelegramId(receiverTelegramId);
|
||||
const sender = await this.chatService.getMatchInfo(matchId, receiverTelegramId);
|
||||
|
||||
await this.bot.sendMessage(
|
||||
receiverChatId,
|
||||
`💌 *Новое сообщение от ${senderName}*\n\n` +
|
||||
`"${this.escapeMarkdown(messagePreview)}"\n\n` +
|
||||
'👆 Нажмите "Открыть чат" для ответа',
|
||||
{
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: '💬 Открыть чат', callback_data: `open_native_chat_${matchId}` }],
|
||||
[{ text: '📱 Все чаты', callback_data: 'native_chats' }]
|
||||
]
|
||||
}
|
||||
}
|
||||
if (!receiverUserId || !sender?.otherUserId) {
|
||||
console.error('Failed to get user IDs for notification');
|
||||
return;
|
||||
}
|
||||
|
||||
// Используем сервис уведомлений для отправки более красивого уведомления
|
||||
await this.notificationService.sendMessageNotification(
|
||||
receiverUserId,
|
||||
sender.otherUserId,
|
||||
messagePreview,
|
||||
matchId
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error sending message notification:', error);
|
||||
|
||||
76
src/handlers/likeBackHandler.ts
Normal file
76
src/handlers/likeBackHandler.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import TelegramBot from 'node-telegram-bot-api';
|
||||
import { ProfileService } from '../services/profileService';
|
||||
import { MatchingService } from '../services/matchingService';
|
||||
|
||||
export class LikeBackHandler {
|
||||
private bot: TelegramBot;
|
||||
private profileService: ProfileService;
|
||||
private matchingService: MatchingService;
|
||||
|
||||
constructor(bot: TelegramBot) {
|
||||
this.bot = bot;
|
||||
this.profileService = new ProfileService();
|
||||
this.matchingService = new MatchingService();
|
||||
}
|
||||
|
||||
// Функция для обработки обратного лайка из уведомления
|
||||
async handleLikeBack(chatId: number, telegramId: string, targetUserId: string): Promise<void> {
|
||||
try {
|
||||
// Получаем информацию о пользователях
|
||||
const [userId, targetProfile] = await Promise.all([
|
||||
this.profileService.getUserIdByTelegramId(telegramId),
|
||||
this.profileService.getProfileByUserId(targetUserId)
|
||||
]);
|
||||
|
||||
if (!userId || !targetProfile) {
|
||||
await this.bot.sendMessage(chatId, '❌ Не удалось найти профиль');
|
||||
return;
|
||||
}
|
||||
|
||||
// Проверяем, есть ли уже свайп
|
||||
const existingSwipe = await this.matchingService.getSwipeBetweenUsers(userId, targetUserId);
|
||||
if (existingSwipe) {
|
||||
await this.bot.sendMessage(chatId, '❓ Вы уже оценили этот профиль ранее.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Создаем свайп (лайк)
|
||||
const result = await this.matchingService.createSwipe(userId, targetUserId, 'like');
|
||||
|
||||
if (result.isMatch) {
|
||||
// Это матч!
|
||||
await this.bot.sendMessage(
|
||||
chatId,
|
||||
'🎉 *Поздравляем! Это взаимно!*\n\n' +
|
||||
`Вы и *${targetProfile.name}* понравились друг другу!\n` +
|
||||
'Теперь вы можете начать общение.',
|
||||
{
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: '💬 Начать общение', callback_data: `start_chat:${targetUserId}` }],
|
||||
[{ text: '👀 Посмотреть профиль', callback_data: `view_profile:${targetUserId}` }]
|
||||
]
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
await this.bot.sendMessage(
|
||||
chatId,
|
||||
'❤️ Вам понравился профиль ' + targetProfile.name + '!\n\n' +
|
||||
'Если вы также понравитесь этому пользователю, будет создан матч.',
|
||||
{
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: '🔍 Продолжить поиск', callback_data: 'start_browsing' }]
|
||||
]
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in handleLikeBack:', error);
|
||||
await this.bot.sendMessage(chatId, '❌ Произошла ошибка при обработке лайка');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user