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:
2025-09-13 08:45:41 +09:00
parent 321547bf27
commit 975eb348dd
5 changed files with 807 additions and 14 deletions

257
src/services/vipService.ts Normal file
View File

@@ -0,0 +1,257 @@
import { query } from '../database/connection';
import { BotError } from '../types/index';
export interface VipSearchFilters {
ageMin?: number;
ageMax?: number;
city?: string;
datingGoal?: string;
hobbies?: string[];
lifestyle?: string[];
distance?: number;
hasPhotos?: boolean;
isOnline?: boolean;
}
export interface PremiumInfo {
isPremium: boolean;
expiresAt?: Date;
daysLeft?: number;
}
export class VipService {
// Проверить премиум статус пользователя
async checkPremiumStatus(telegramId: string): Promise<PremiumInfo> {
try {
const result = await query(`
SELECT premium, premium_expires_at
FROM users
WHERE telegram_id = $1
`, [telegramId]);
if (result.rows.length === 0) {
throw new BotError('User not found', 'USER_NOT_FOUND', 404);
}
const user = result.rows[0];
const isPremium = user.premium;
const expiresAt = user.premium_expires_at ? new Date(user.premium_expires_at) : undefined;
let daysLeft = undefined;
if (isPremium && expiresAt) {
const now = new Date();
const timeDiff = expiresAt.getTime() - now.getTime();
daysLeft = Math.ceil(timeDiff / (1000 * 3600 * 24));
// Если премиум истек
if (daysLeft <= 0) {
await this.removePremium(telegramId);
return { isPremium: false };
}
}
return {
isPremium,
expiresAt,
daysLeft
};
} catch (error) {
console.error('Error checking premium status:', error);
throw error;
}
}
// Добавить премиум статус
async addPremium(telegramId: string, durationDays: number = 30): Promise<void> {
try {
const expiresAt = new Date();
expiresAt.setDate(expiresAt.getDate() + durationDays);
await query(`
UPDATE users
SET premium = true, premium_expires_at = $2
WHERE telegram_id = $1
`, [telegramId, expiresAt]);
} catch (error) {
console.error('Error adding premium:', error);
throw error;
}
}
// Удалить премиум статус
async removePremium(telegramId: string): Promise<void> {
try {
await query(`
UPDATE users
SET premium = false, premium_expires_at = NULL
WHERE telegram_id = $1
`, [telegramId]);
} catch (error) {
console.error('Error removing premium:', error);
throw error;
}
}
// VIP поиск с фильтрами
async vipSearch(telegramId: string, filters: VipSearchFilters): Promise<any[]> {
try {
// Проверяем премиум статус
const premiumInfo = await this.checkPremiumStatus(telegramId);
if (!premiumInfo.isPremium) {
throw new BotError('Premium subscription required', 'PREMIUM_REQUIRED', 403);
}
// Получаем профиль пользователя
const userProfile = await query(`
SELECT p.*, u.telegram_id
FROM profiles p
JOIN users u ON p.user_id = u.id
WHERE u.telegram_id = $1
`, [telegramId]);
if (userProfile.rows.length === 0) {
throw new BotError('Profile not found', 'PROFILE_NOT_FOUND', 404);
}
const currentUser = userProfile.rows[0];
// Строим запрос с фильтрами
let query_text = `
SELECT p.*, u.telegram_id,
CASE WHEN u.updated_at > NOW() - INTERVAL '15 minutes' THEN true ELSE false END as is_online
FROM profiles p
JOIN users u ON p.user_id = u.id
LEFT JOIN swipes s ON (
s.swiper_id = $1 AND s.swiped_id = u.id
)
WHERE u.telegram_id != $2
AND s.id IS NULL
AND p.is_active = true
`;
let params = [currentUser.user_id, telegramId];
let paramIndex = 3;
// Фильтр по противоположному полу
if (currentUser.gender === 'male') {
query_text += ` AND p.gender = 'female'`;
} else if (currentUser.gender === 'female') {
query_text += ` AND p.gender = 'male'`;
} else {
// Если пол не определен или 'other', показываем всех кроме того же пола
query_text += ` AND p.gender != $${paramIndex}`;
params.push(currentUser.gender);
paramIndex++;
}
// Фильтр по возрасту
if (filters.ageMin) {
query_text += ` AND p.age >= $${paramIndex}`;
params.push(filters.ageMin);
paramIndex++;
}
if (filters.ageMax) {
query_text += ` AND p.age <= $${paramIndex}`;
params.push(filters.ageMax);
paramIndex++;
}
// Фильтр по городу
if (filters.city) {
query_text += ` AND LOWER(p.city) LIKE LOWER($${paramIndex})`;
params.push(`%${filters.city}%`);
paramIndex++;
}
// Фильтр по цели знакомства
if (filters.datingGoal) {
query_text += ` AND p.dating_goal = $${paramIndex}`;
params.push(filters.datingGoal);
paramIndex++;
}
// Фильтр по хобби
if (filters.hobbies && filters.hobbies.length > 0) {
const hobbyConditions = filters.hobbies.map((_, index) => {
return `LOWER(p.hobbies) LIKE LOWER($${paramIndex + index})`;
});
query_text += ` AND (${hobbyConditions.join(' OR ')})`;
filters.hobbies.forEach(hobby => {
params.push(`%${hobby}%`);
});
paramIndex += filters.hobbies.length;
}
// Фильтр по образу жизни
if (filters.lifestyle && filters.lifestyle.length > 0) {
const lifestyleConditions = filters.lifestyle.map((field) => {
const condition = `p.lifestyle ? $${paramIndex}`;
params.push(field);
paramIndex++;
return condition;
});
query_text += ` AND (${lifestyleConditions.join(' OR ')})`;
}
// Фильтр по наличию фото
if (filters.hasPhotos) {
query_text += ` AND p.photos IS NOT NULL AND array_length(p.photos, 1) > 0`;
}
// Фильтр по онлайн статусу
if (filters.isOnline) {
query_text += ` AND u.updated_at > NOW() - INTERVAL '15 minutes'`;
}
query_text += ` ORDER BY
CASE WHEN u.updated_at > NOW() - INTERVAL '15 minutes' THEN 0 ELSE 1 END,
u.updated_at DESC,
p.created_at DESC
LIMIT 50`;
const result = await query(query_text, params);
return result.rows;
} catch (error) {
console.error('Error in VIP search:', error);
throw error;
}
}
// Получить информацию о премиум возможностях
getPremiumFeatures(): string {
return `💎 ПРЕМИУМ ПОДПИСКА 💎
🔥 Что дает VIP статус:
🎯 VIP Поиск с фильтрами:
• Поиск по возрасту
• Поиск по городу
• Фильтр по целям знакомства
• Поиск по хобби и интересам
• Фильтр по образу жизни
• Только пользователи с фото
• Только онлайн пользователи
⚡ Дополнительные возможности:
• Неограниченные супер-лайки
• Просмотр кто лайкнул вас
• Возможность отменить свайп
• Приоритет в показе другим
• Расширенная статистика
• Скрытый режим просмотра
💰 Тарифы:
• 1 месяц - 299₽
• 3 месяца - 699₽ (экономия 25%)
• 6 месяцев - 1199₽ (экономия 33%)
• 1 год - 1999₽ (экономия 44%)
📞 Для покупки обратитесь к администратору:
@admin_bot
✨ Попробуйте VIP уже сегодня!`;
}
}