feat: VIP search now shows only opposite gender - Modified VIP search filtering to always show opposite gender regardless of user's interested_in preference - Male users see only female profiles - Female users see only male profiles - Improved gender filtering logic in vipService.ts
This commit is contained in:
291
src/controllers/vipController.ts
Normal file
291
src/controllers/vipController.ts
Normal file
@@ -0,0 +1,291 @@
|
||||
import TelegramBot, { InlineKeyboardMarkup } from 'node-telegram-bot-api';
|
||||
import { VipService, VipSearchFilters } from '../services/vipService';
|
||||
import { ProfileService } from '../services/profileService';
|
||||
|
||||
interface VipSearchState {
|
||||
filters: VipSearchFilters;
|
||||
currentStep: string;
|
||||
}
|
||||
|
||||
export class VipController {
|
||||
private bot: TelegramBot;
|
||||
private vipService: VipService;
|
||||
private profileService: ProfileService;
|
||||
private vipSearchStates: Map<string, VipSearchState> = new Map();
|
||||
|
||||
constructor(bot: TelegramBot) {
|
||||
this.bot = bot;
|
||||
this.vipService = new VipService();
|
||||
this.profileService = new ProfileService();
|
||||
}
|
||||
|
||||
// Показать VIP поиск или информацию о премиум
|
||||
async showVipSearch(chatId: number, telegramId: string): Promise<void> {
|
||||
try {
|
||||
const premiumInfo = await this.vipService.checkPremiumStatus(telegramId);
|
||||
|
||||
if (!premiumInfo.isPremium) {
|
||||
// Показываем информацию о премиум
|
||||
await this.showPremiumInfo(chatId);
|
||||
} else {
|
||||
// Показываем VIP поиск
|
||||
await this.showVipSearchMenu(chatId, telegramId, premiumInfo);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error showing VIP search:', error);
|
||||
await this.bot.sendMessage(chatId, '❌ Ошибка при загрузке VIP поиска');
|
||||
}
|
||||
}
|
||||
|
||||
// Показать информацию о премиум подписке
|
||||
private async showPremiumInfo(chatId: number): Promise<void> {
|
||||
const premiumText = this.vipService.getPremiumFeatures();
|
||||
|
||||
const keyboard: InlineKeyboardMarkup = {
|
||||
inline_keyboard: [
|
||||
[{ text: '💎 Купить VIP', url: 'https://t.me/admin_bot' }],
|
||||
[{ text: '🔙 Назад в меню', callback_data: 'main_menu' }]
|
||||
]
|
||||
};
|
||||
|
||||
await this.bot.sendMessage(chatId, premiumText, {
|
||||
reply_markup: keyboard
|
||||
});
|
||||
}
|
||||
|
||||
// Показать меню VIP поиска
|
||||
private async showVipSearchMenu(chatId: number, telegramId: string, premiumInfo: any): Promise<void> {
|
||||
const daysText = premiumInfo.daysLeft ? ` (остался ${premiumInfo.daysLeft} дн.)` : '';
|
||||
|
||||
const text = `💎 VIP ПОИСК 💎\n\n` +
|
||||
`✅ Премиум статус активен${daysText}\n\n` +
|
||||
`🎯 Выберите тип поиска:`;
|
||||
|
||||
const keyboard: InlineKeyboardMarkup = {
|
||||
inline_keyboard: [
|
||||
[{ text: '🔍 Быстрый VIP поиск', callback_data: 'vip_quick_search' }],
|
||||
[{ text: '⚙️ Расширенный поиск с фильтрами', callback_data: 'vip_advanced_search' }],
|
||||
[{ text: '🎯 Поиск по целям знакомства', callback_data: 'vip_dating_goal_search' }],
|
||||
[{ text: '🎨 Поиск по хобби', callback_data: 'vip_hobbies_search' }],
|
||||
[{ text: '🔙 Назад в меню', callback_data: 'main_menu' }]
|
||||
]
|
||||
};
|
||||
|
||||
await this.bot.sendMessage(chatId, text, {
|
||||
reply_markup: keyboard
|
||||
});
|
||||
}
|
||||
|
||||
// Быстрый VIP поиск
|
||||
async performQuickVipSearch(chatId: number, telegramId: string): Promise<void> {
|
||||
try {
|
||||
const filters: VipSearchFilters = {
|
||||
hasPhotos: true,
|
||||
isOnline: true
|
||||
};
|
||||
|
||||
const results = await this.vipService.vipSearch(telegramId, filters);
|
||||
await this.showSearchResults(chatId, telegramId, results, 'Быстрый VIP поиск');
|
||||
} catch (error) {
|
||||
console.error('Error in quick VIP search:', error);
|
||||
await this.bot.sendMessage(chatId, '❌ Ошибка при выполнении поиска');
|
||||
}
|
||||
}
|
||||
|
||||
// Начать настройку фильтров для расширенного поиска
|
||||
async startAdvancedSearch(chatId: number, telegramId: string): Promise<void> {
|
||||
const state: VipSearchState = {
|
||||
filters: {},
|
||||
currentStep: 'age_min'
|
||||
};
|
||||
|
||||
this.vipSearchStates.set(telegramId, state);
|
||||
|
||||
await this.bot.sendMessage(
|
||||
chatId,
|
||||
'⚙️ Расширенный VIP поиск\n\n' +
|
||||
'🔢 Укажите минимальный возраст (18-65) или отправьте "-" чтобы пропустить:',
|
||||
{ }
|
||||
);
|
||||
}
|
||||
|
||||
// Поиск по целям знакомства
|
||||
async showDatingGoalSearch(chatId: number, telegramId: string): Promise<void> {
|
||||
const keyboard: InlineKeyboardMarkup = {
|
||||
inline_keyboard: [
|
||||
[{ text: '💕 Серьёзные отношения', callback_data: 'vip_goal_serious' }],
|
||||
[{ text: '🎉 Лёгкие отношения', callback_data: 'vip_goal_casual' }],
|
||||
[{ text: '👥 Дружба', callback_data: 'vip_goal_friends' }],
|
||||
[{ text: '🔥 Одна ночь', callback_data: 'vip_goal_one_night' }],
|
||||
[{ text: '😏 FWB', callback_data: 'vip_goal_fwb' }],
|
||||
[{ text: '💎 Спонсорство', callback_data: 'vip_goal_sugar' }],
|
||||
[{ text: '💍 Брак с переездом', callback_data: 'vip_goal_marriage_abroad' }],
|
||||
[{ text: '💫 Полиамория', callback_data: 'vip_goal_polyamory' }],
|
||||
[{ text: '🤷♀️ Пока не определился', callback_data: 'vip_goal_unsure' }],
|
||||
[{ text: '🔙 Назад', callback_data: 'vip_search' }]
|
||||
]
|
||||
};
|
||||
|
||||
await this.bot.sendMessage(
|
||||
chatId,
|
||||
'🎯 Поиск по целям знакомства\n\nВыберите цель:',
|
||||
{
|
||||
reply_markup: keyboard
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Выполнить поиск по цели знакомства
|
||||
async performDatingGoalSearch(chatId: number, telegramId: string, goal: string): Promise<void> {
|
||||
try {
|
||||
// Используем значения из базы данных как есть
|
||||
const filters: VipSearchFilters = {
|
||||
datingGoal: goal,
|
||||
hasPhotos: true
|
||||
};
|
||||
|
||||
const results = await this.vipService.vipSearch(telegramId, filters);
|
||||
|
||||
const goalNames: { [key: string]: string } = {
|
||||
'serious': 'Серьёзные отношения',
|
||||
'casual': 'Лёгкие отношения',
|
||||
'friends': 'Дружба',
|
||||
'one_night': 'Одна ночь',
|
||||
'fwb': 'FWB',
|
||||
'sugar': 'Спонсорство',
|
||||
'marriage_abroad': 'Брак с переездом',
|
||||
'polyamory': 'Полиамория',
|
||||
'unsure': 'Пока не определился'
|
||||
};
|
||||
|
||||
const goalName = goalNames[goal] || goal;
|
||||
await this.showSearchResults(chatId, telegramId, results, `Поиск: ${goalName}`);
|
||||
} catch (error) {
|
||||
console.error('Error in dating goal search:', error);
|
||||
await this.bot.sendMessage(chatId, '❌ Ошибка при выполнении поиска');
|
||||
}
|
||||
}
|
||||
|
||||
// Показать результаты поиска
|
||||
private async showSearchResults(chatId: number, telegramId: string, results: any[], searchType: string): Promise<void> {
|
||||
if (results.length === 0) {
|
||||
const keyboard: InlineKeyboardMarkup = {
|
||||
inline_keyboard: [
|
||||
[{ text: '🔍 Новый поиск', callback_data: 'vip_search' }],
|
||||
[{ text: '🔙 Главное меню', callback_data: 'main_menu' }]
|
||||
]
|
||||
};
|
||||
|
||||
await this.bot.sendMessage(
|
||||
chatId,
|
||||
`😔 ${searchType}\n\n` +
|
||||
'К сожалению, никого не найдено по вашим критериям.\n\n' +
|
||||
'💡 Попробуйте изменить фильтры или выполнить обычный поиск.',
|
||||
{
|
||||
reply_markup: keyboard,
|
||||
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.bot.sendMessage(
|
||||
chatId,
|
||||
`🎉 ${searchType}\n\n` +
|
||||
`Найдено: ${results.length} ${this.getCountText(results.length)}\n\n` +
|
||||
'Начинаем просмотр профилей...',
|
||||
{ }
|
||||
);
|
||||
|
||||
// Показываем первый профиль из результатов
|
||||
const firstProfile = results[0];
|
||||
await this.showVipSearchProfile(chatId, telegramId, firstProfile, results, 0);
|
||||
}
|
||||
|
||||
// Показать профиль из VIP поиска
|
||||
private async showVipSearchProfile(chatId: number, telegramId: string, profile: any, allResults: any[], currentIndex: number): Promise<void> {
|
||||
try {
|
||||
let profileText = `💎 VIP Поиск (${currentIndex + 1}/${allResults.length})\n\n`;
|
||||
profileText += `👤 ${profile.name}, ${profile.age}\n`;
|
||||
profileText += `📍 ${profile.city || 'Не указан'}\n`;
|
||||
|
||||
if (profile.dating_goal) {
|
||||
const goalText = this.getDatingGoalText(profile.dating_goal);
|
||||
profileText += `🎯 ${goalText}\n`;
|
||||
}
|
||||
|
||||
if (profile.bio) {
|
||||
profileText += `\n📝 ${profile.bio}\n`;
|
||||
}
|
||||
|
||||
if (profile.is_online) {
|
||||
profileText += `\n🟢 Онлайн\n`;
|
||||
}
|
||||
|
||||
const keyboard: InlineKeyboardMarkup = {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: '❤️', callback_data: `vip_like_${profile.telegram_id}` },
|
||||
{ text: '⭐', callback_data: `vip_superlike_${profile.telegram_id}` },
|
||||
{ text: '👎', callback_data: `vip_dislike_${profile.telegram_id}` }
|
||||
],
|
||||
[{ text: '👤 Полный профиль', callback_data: `view_profile_${profile.user_id}` }],
|
||||
[
|
||||
{ text: '⬅️ Предыдущий', callback_data: `vip_prev_${currentIndex}` },
|
||||
{ text: '➡️ Следующий', callback_data: `vip_next_${currentIndex}` }
|
||||
],
|
||||
[{ text: '🔍 Новый поиск', callback_data: 'vip_search' }],
|
||||
[{ text: '🔙 Главное меню', callback_data: 'main_menu' }]
|
||||
]
|
||||
};
|
||||
|
||||
// Проверяем есть ли фотографии
|
||||
if (profile.photos && Array.isArray(profile.photos) && profile.photos.length > 0) {
|
||||
await this.bot.sendPhoto(chatId, profile.photos[0], {
|
||||
caption: profileText,
|
||||
reply_markup: keyboard,
|
||||
|
||||
});
|
||||
} else {
|
||||
await this.bot.sendMessage(chatId, profileText, {
|
||||
reply_markup: keyboard,
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// Сохраняем результаты поиска для навигации
|
||||
// Можно сохранить в Redis или временной переменной
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error showing VIP search profile:', error);
|
||||
await this.bot.sendMessage(chatId, '❌ Ошибка при показе профиля');
|
||||
}
|
||||
}
|
||||
|
||||
private getCountText(count: number): string {
|
||||
const lastDigit = count % 10;
|
||||
const lastTwoDigits = count % 100;
|
||||
|
||||
if (lastTwoDigits >= 11 && lastTwoDigits <= 14) {
|
||||
return 'пользователей';
|
||||
}
|
||||
|
||||
switch (lastDigit) {
|
||||
case 1: return 'пользователь';
|
||||
case 2:
|
||||
case 3:
|
||||
case 4: return 'пользователя';
|
||||
default: return 'пользователей';
|
||||
}
|
||||
}
|
||||
|
||||
private getDatingGoalText(goal: string): string {
|
||||
const goals: { [key: string]: string } = {
|
||||
'serious_relationship': 'Серьезные отношения',
|
||||
'friendship': 'Общение и дружба',
|
||||
'fun': 'Развлечения',
|
||||
'networking': 'Деловые знакомства'
|
||||
};
|
||||
return goals[goal] || 'Не указано';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user