geo detection

This commit is contained in:
2025-11-06 15:09:15 +09:00
parent 88d9ccd75d
commit 0bbeb0767b
47 changed files with 1355 additions and 93 deletions

View File

@@ -31,7 +31,9 @@ export class CallbackHandlers {
this.bot = bot;
this.profileService = new ProfileService();
this.matchingService = new MatchingService();
this.chatService = new ChatService();
// Получаем notificationService из messageHandlers (если есть)
const notificationService = (messageHandlers as any).notificationService;
this.chatService = new ChatService(notificationService);
this.messageHandlers = messageHandlers;
this.profileEditController = new ProfileEditController(this.profileService);
this.enhancedChatHandlers = new EnhancedChatHandlers(bot);
@@ -86,6 +88,107 @@ export class CallbackHandlers {
await this.handleEditHobbies(chatId, telegramId);
} else if (data === 'edit_city') {
await this.handleEditCity(chatId, telegramId);
} else if (data === 'confirm_city') {
try {
const states = (this.messageHandlers as any).userStates as Map<string, any>;
const userState = states ? states.get(telegramId) : null;
if (userState && userState.step === 'confirm_city') {
// Подтверждаем город и переводим пользователя к вводу био
userState.step = 'waiting_bio';
console.log(`User ${telegramId} confirmed city: ${userState.data.city}`);
// Убираем inline-кнопки из сообщения с подтверждением
try {
// clear inline keyboard
await this.bot.editMessageReplyMarkup({ inline_keyboard: [] } as any, { chat_id: chatId, message_id: query.message?.message_id });
} catch (e) {
// ignore
}
await this.bot.sendMessage(chatId, `✅ Город подтверждён: *${userState.data.city}*\n\n📝 Теперь расскажите немного о себе (био):`, { parse_mode: 'Markdown' });
} else {
await this.bot.answerCallbackQuery(query.id, { text: 'Контекст не найден. Повторите, пожалуйста.' });
}
} catch (error) {
console.error('Error confirming city via callback:', error);
await this.bot.answerCallbackQuery(query.id, { text: 'Ошибка при подтверждении города' });
}
} else if (data === 'edit_city_manual') {
try {
const states = (this.messageHandlers as any).userStates as Map<string, any>;
const userState = states ? states.get(telegramId) : null;
if (userState) {
userState.step = 'waiting_city';
console.log(`User ${telegramId} chose to enter city manually`);
try {
// clear inline keyboard
await this.bot.editMessageReplyMarkup({ inline_keyboard: [] } as any, { chat_id: chatId, message_id: query.message?.message_id });
} catch (e) { }
await this.bot.sendMessage(chatId, '✏️ Введите название вашего города вручную:', { reply_markup: { remove_keyboard: true } });
} else {
await this.bot.answerCallbackQuery(query.id, { text: 'Контекст не найден. Повторите, пожалуйста.' });
}
} catch (error) {
console.error('Error switching to manual city input via callback:', error);
await this.bot.answerCallbackQuery(query.id, { text: 'Ошибка' });
}
} else if (data === 'confirm_city_edit') {
try {
const editState = this.messageHandlers.profileEditStates.get(telegramId);
if (editState && editState.field === 'city' && editState.tempCity) {
console.log(`User ${telegramId} confirmed city edit: ${editState.tempCity}`);
// Обновляем город в профиле
await this.messageHandlers.updateProfileField(telegramId, 'city', editState.tempCity);
// Очищаем состояние
this.messageHandlers.clearProfileEditState(telegramId);
// Убираем inline-кнопки
try {
await this.bot.editMessageReplyMarkup({ inline_keyboard: [] } as any, { chat_id: chatId, message_id: query.message?.message_id });
} catch (e) { }
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 });
}, 500);
} else {
await this.bot.answerCallbackQuery(query.id, { text: 'Контекст не найден. Повторите, пожалуйста.' });
}
} catch (error) {
console.error('Error confirming city edit via callback:', error);
await this.bot.answerCallbackQuery(query.id, { text: 'Ошибка при подтверждении города' });
}
} else if (data === 'edit_city_manual_edit') {
try {
const editState = this.messageHandlers.profileEditStates.get(telegramId);
if (editState && editState.field === 'city') {
console.log(`User ${telegramId} chose to re-enter city during edit`);
// Очищаем временный город, но оставляем состояние редактирования
delete editState.tempCity;
try {
await this.bot.editMessageReplyMarkup({ inline_keyboard: [] } as any, { chat_id: chatId, message_id: query.message?.message_id });
} catch (e) { }
await this.bot.sendMessage(chatId, '✏️ Введите название вашего города вручную или отправьте геолокацию:', {
reply_markup: {
keyboard: [
[{ text: '📍 Отправить геолокацию', request_location: true }]
],
resize_keyboard: true,
one_time_keyboard: true
}
});
} else {
await this.bot.answerCallbackQuery(query.id, { text: 'Контекст не найден. Повторите, пожалуйста.' });
}
} catch (error) {
console.error('Error switching to re-enter city during edit via callback:', error);
await this.bot.answerCallbackQuery(query.id, { text: 'Ошибка' });
}
} else if (data === 'edit_job') {
await this.handleEditJob(chatId, telegramId);
} else if (data === 'edit_education') {
@@ -184,6 +287,12 @@ export class CallbackHandlers {
await this.likeBackHandler.handleLikeBack(chatId, telegramId, targetUserId);
}
// Быстрый переход в чат из уведомлений
else if (data.startsWith('open_chat:')) {
const matchId = data.replace('open_chat:', '');
await this.enhancedChatHandlers.openNativeChat(chatId, telegramId, matchId);
}
// Матчи и чаты
else if (data === 'view_matches') {
await this.handleViewMatches(chatId, telegramId);
@@ -975,14 +1084,22 @@ export class CallbackHandlers {
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.hobbies) {
let hobbiesArray: string[] = [];
if (typeof profile.hobbies === 'string') {
hobbiesArray = profile.hobbies.split(',').map(hobby => hobby.trim()).filter(hobby => hobby);
} else if (Array.isArray(profile.hobbies)) {
hobbiesArray = (profile.hobbies as string[]).filter((hobby: string) => hobby && hobby.trim());
}
if (hobbiesArray.length > 0) {
const formattedHobbies = hobbiesArray.map(hobby => '#' + hobby).join(' ');
profileText += '\n🎯 ' + formattedHobbies + '\n';
}
}
if (profile.interests.length > 0) {
profileText += '\n<EFBFBD> Интересы: ' + profile.interests.join(', ');
profileText += '\n💡 Интересы: ' + profile.interests.join(', ');
}
let keyboard: InlineKeyboardMarkup;
@@ -1192,8 +1309,15 @@ export class CallbackHandlers {
// Редактирование города
async handleEditCity(chatId: number, telegramId: string): Promise<void> {
this.messageHandlers.setWaitingForInput(parseInt(telegramId), 'city');
await this.bot.sendMessage(chatId, '🏙️ *Введите ваш город:*\n\nНапример: Москва', {
parse_mode: 'Markdown'
await this.bot.sendMessage(chatId, '🏙️ *Укажите ваш город:*\n\nВыберите один из вариантов:', {
parse_mode: 'Markdown',
reply_markup: {
keyboard: [
[{ text: '📍 Отправить геолокацию', request_location: true }]
],
resize_keyboard: true,
one_time_keyboard: true
}
});
}
@@ -1762,10 +1886,18 @@ export class CallbackHandlers {
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.hobbies) {
let hobbiesArray: string[] = [];
if (typeof candidate.hobbies === 'string') {
hobbiesArray = candidate.hobbies.split(',').map(hobby => hobby.trim()).filter(hobby => hobby);
} else if (Array.isArray(candidate.hobbies)) {
hobbiesArray = (candidate.hobbies as string[]).filter((hobby: string) => hobby && hobby.trim());
}
if (hobbiesArray.length > 0) {
const formattedHobbies = hobbiesArray.map(hobby => '#' + hobby).join(' ');
candidateText += '\n🎯 ' + formattedHobbies + '\n';
}
}
if (candidate.interests.length > 0) {