diff --git a/src/handlers/adminHandlers/product/categorySelectionHandler.js b/src/handlers/adminHandlers/product/categorySelectionHandler.js index 46f9e9a..f9333ff 100644 --- a/src/handlers/adminHandlers/product/categorySelectionHandler.js +++ b/src/handlers/adminHandlers/product/categorySelectionHandler.js @@ -4,6 +4,7 @@ import bot from '../../../context/bot.js'; import CategoryService from '../../../services/categoryService.js'; import ProductService from '../../../services/productService.js'; import logger from '../../../utils/logger.js'; +import { editOrSendCallback } from '../../../utils/messageUtils.js'; export default class CategorySelectionHandler { @@ -19,9 +20,9 @@ export default class CategorySelectionHandler { try { const category = await CategoryService.getCategoryById(categoryId); const location = await LocationService.getLocationById(locationId); - + const products = await ProductService.getProductsByCategoryId(categoryId); - + const keyboard = { inline_keyboard: [ ...products.map(prod => [{ @@ -29,7 +30,7 @@ export default class CategorySelectionHandler { callback_data: `view_product_${prod.id}` }]), [{ text: '➕ Add Product', callback_data: `add_product_${locationId}_${categoryId}` }], - [{ text: '« Back', callback_data: `prod_district_${location.country}_${location.city}_${location.district}` }] + [{ text: '« Back', callback_data: `prod_loc_${locationId}` }] ] }; @@ -43,7 +44,7 @@ export default class CategorySelectionHandler { ); } catch (error) { logger.error({ err: error }, 'Error in handleCategorySelection'); - await bot.sendMessage(chatId, 'Error loading products. Please try again.'); + await editOrSendCallback(callbackQuery, 'Error loading products. Please try again.'); } } -} +} \ No newline at end of file diff --git a/src/handlers/adminHandlers/product/districtHandler.js b/src/handlers/adminHandlers/product/districtHandler.js index 8f26b23..851c39a 100644 --- a/src/handlers/adminHandlers/product/districtHandler.js +++ b/src/handlers/adminHandlers/product/districtHandler.js @@ -4,6 +4,7 @@ import CategoryService from '../../../services/categoryService.js'; import bot from '../../../context/bot.js'; import userStates from '../../../context/userStates.js'; import logger from '../../../utils/logger.js'; +import { editOrSendCallback } from '../../../utils/messageUtils.js'; export default class DistrictHandler { @@ -14,18 +15,19 @@ export default class DistrictHandler { const chatId = callbackQuery.message.chat.id; const messageId = callbackQuery.message.message_id; - const [country, city] = callbackQuery.data.replace('prod_city_', '').split('_'); + const payload = callbackQuery.data.replace('prod_city_', ''); + const [country, city] = payload.split('|').map(decodeURIComponent); try { - const districts = await LocationService.getDistrictsByCountryAndCity(country, city); + const locations = await LocationService.getLocationsByCountryAndCity(country, city); const keyboard = { inline_keyboard: [ - ...districts.map(loc => [{ - text: loc.district, - callback_data: `prod_district_${country}_${city}_${loc.district}` + ...locations.map(loc => [{ + text: loc.district || loc.city, + callback_data: `prod_loc_${loc.id}` }]), - [{text: '« Back', callback_data: `prod_country_${country}`}] + [{text: '« Back', callback_data: `prod_country_${encodeURIComponent(country)}`}] ] }; @@ -39,7 +41,7 @@ export default class DistrictHandler { ); } catch (error) { logger.error({ err: error }, 'Error in handleCitySelection'); - await bot.sendMessage(chatId, 'Error loading districts. Please try again.'); + await editOrSendCallback(callbackQuery, 'Error loading districts. Please try again.'); } } @@ -50,12 +52,12 @@ export default class DistrictHandler { const chatId = callbackQuery.message.chat.id; const messageId = callbackQuery.message.message_id; - const [country, city, district] = callbackQuery.data.replace('prod_district_', '').split('_'); + const locationId = parseInt(callbackQuery.data.replace('prod_loc_', ''), 10); await userStates.delete(chatId); try { - const location = await LocationService.getLocation(country, city, district); + const location = await LocationService.getLocationById(locationId); if (!location) { throw new Error('Location not found'); @@ -70,7 +72,7 @@ export default class DistrictHandler { callback_data: `prod_category_${location.id}_${cat.id}` }]), [{text: '➕ Add Category', callback_data: `add_category_${location.id}`}], - [{text: '« Back', callback_data: `prod_city_${country}_${city}`}] + [{text: '« Back', callback_data: `prod_city_${encodeURIComponent(location.country)}|${encodeURIComponent(location.city)}`}] ] }; @@ -84,7 +86,7 @@ export default class DistrictHandler { ); } catch (error) { logger.error({ err: error }, 'Error in handleDistrictSelection'); - await bot.sendMessage(chatId, 'Error loading categories. Please try again.'); + await editOrSendCallback(callbackQuery, 'Error loading categories. Please try again.'); } } -} +} \ No newline at end of file diff --git a/src/handlers/adminHandlers/product/navigationHandler.js b/src/handlers/adminHandlers/product/navigationHandler.js index 8807ed3..11d6596 100644 --- a/src/handlers/adminHandlers/product/navigationHandler.js +++ b/src/handlers/adminHandlers/product/navigationHandler.js @@ -2,6 +2,7 @@ import { isAdmin } from '../../../middleware/auth.js'; import LocationService from '../../../services/locationService.js'; import bot from '../../../context/bot.js'; import logger from '../../../utils/logger.js'; +import { editOrSendCallback } from '../../../utils/messageUtils.js'; export default class NavigationHandler { @@ -14,7 +15,7 @@ export default class NavigationHandler { } try { - const countries = await LocationService.getCountries() + const countries = await LocationService.getCountries(); if (countries.length === 0) { await bot.sendMessage( @@ -34,7 +35,7 @@ export default class NavigationHandler { const keyboard = { inline_keyboard: countries.map(loc => [{ text: loc.country, - callback_data: `prod_country_${loc.country}` + callback_data: `prod_country_${encodeURIComponent(loc.country)}` }]) }; @@ -56,16 +57,16 @@ export default class NavigationHandler { const chatId = callbackQuery.message.chat.id; const messageId = callbackQuery.message.message_id; - const country = callbackQuery.data.replace('prod_country_', ''); + const country = decodeURIComponent(callbackQuery.data.replace('prod_country_', '')); try { - const cities = await LocationService.getCitiesByCountry(country) + const cities = await LocationService.getCitiesByCountry(country); const keyboard = { inline_keyboard: [ ...cities.map(loc => [{ text: loc.city, - callback_data: `prod_city_${country}_${loc.city}` + callback_data: `prod_city_${encodeURIComponent(country)}|${encodeURIComponent(loc.city)}` }]), [{text: '« Back', callback_data: 'manage_products'}] ] @@ -81,7 +82,7 @@ export default class NavigationHandler { ); } catch (error) { logger.error({ err: error }, 'Error in handleCountrySelection'); - await bot.sendMessage(chatId, 'Error loading cities. Please try again.'); + await editOrSendCallback(callbackQuery, 'Error loading cities. Please try again.'); } } -} +} \ No newline at end of file diff --git a/src/handlers/userHandlers/userProductHandler.js b/src/handlers/userHandlers/userProductHandler.js index ac3f227..867cf54 100644 --- a/src/handlers/userHandlers/userProductHandler.js +++ b/src/handlers/userHandlers/userProductHandler.js @@ -62,7 +62,7 @@ export default class UserProductHandler { const keyboard = { inline_keyboard: countries.map(loc => [{ text: loc.country, - callback_data: `shop_country_${loc.country}` + callback_data: `shop_country_${encodeURIComponent(loc.country)}` }]) }; @@ -88,7 +88,7 @@ export default class UserProductHandler { static async handleCountrySelection(callbackQuery) { const chatId = callbackQuery.message.chat.id; const messageId = callbackQuery.message.message_id; - const country = callbackQuery.data.replace('shop_country_', ''); + const country = decodeURIComponent(callbackQuery.data.replace('shop_country_', '')); try { const cities = await LocationService.getCitiesByCountry(country); @@ -97,7 +97,7 @@ export default class UserProductHandler { inline_keyboard: [ ...cities.map(loc => [{ text: loc.city, - callback_data: `shop_city_${country}_${loc.city}` + callback_data: `shop_city_${encodeURIComponent(country)}|${encodeURIComponent(loc.city)}` }]), [{text: '« Back to Countries', callback_data: 'shop_start'}] ] @@ -113,25 +113,26 @@ export default class UserProductHandler { ); } catch (error) { logger.error({ err: error }, 'Error in handleCountrySelection'); - await bot.sendMessage(chatId, 'Error loading cities. Please try again.'); + await editOrSendCallback(callbackQuery, 'Error loading cities. Please try again.'); } } static async handleCitySelection(callbackQuery) { const chatId = callbackQuery.message.chat.id; const messageId = callbackQuery.message.message_id; - const [country, city] = callbackQuery.data.replace('shop_city_', '').split('_'); + const payload = callbackQuery.data.replace('shop_city_', ''); + const [country, city] = payload.split('|').map(decodeURIComponent); try { - const districts = await LocationService.getDistrictsByCountryAndCity(country, city) + const locations = await LocationService.getLocationsByCountryAndCity(country, city); const keyboard = { inline_keyboard: [ - ...districts.map(loc => [{ - text: loc.district, - callback_data: `shop_district_${country}_${city}_${loc.district}` + ...locations.map(loc => [{ + text: loc.district || loc.city, + callback_data: `shop_loc_${loc.id}` }]), - [{text: '« Back to Cities', callback_data: `shop_country_${country}`}] + [{text: '« Back to Cities', callback_data: `shop_country_${encodeURIComponent(country)}`}] ] }; @@ -145,21 +146,19 @@ export default class UserProductHandler { ); } catch (error) { logger.error({ err: error }, 'Error in handleCitySelection'); - await bot.sendMessage(chatId, 'Error loading districts. Please try again.'); + await editOrSendCallback(callbackQuery, 'Error loading districts. Please try again.'); } } static async handleDistrictSelection(callbackQuery) { const chatId = callbackQuery.message.chat.id; const messageId = callbackQuery.message.message_id; - const [country, city, district] = callbackQuery.data.replace('shop_district_', '').split('_'); + const locationId = parseInt(callbackQuery.data.replace('shop_loc_', ''), 10); try { - // Получаем информацию о локации - const location = await LocationService.getLocation(country, city, district); + const location = await LocationService.getLocationById(locationId); if (!location) { - // Если локация не найдена, вернуть пользователя к предыдущему шагу await bot.editMessageText( 'Location not found. Returning to previous menu.', { @@ -167,7 +166,7 @@ export default class UserProductHandler { message_id: messageId, reply_markup: { inline_keyboard: [[ - { text: '« Back', callback_data: `shop_city_${country}_${city}` } + { text: '« Back', callback_data: `shop_city_${encodeURIComponent(location?.country || '')}|${encodeURIComponent(location?.city || '')}` } ]] } } @@ -175,12 +174,11 @@ export default class UserProductHandler { return; } - // Сохраняем текстовое представление локации в состоянии пользователя await userStates.set(chatId, { - location: `${country}_${city}_${district}` + location: `${location.country}_${location.city}_${location.district}`, + locationId: location.id }); - // Получаем категории для выбранной локации const categories = await CategoryService.getCategoriesByLocationId(location.id); const keyboard = { @@ -189,7 +187,7 @@ export default class UserProductHandler { text: cat.name, callback_data: `shop_category_${location.id}_${cat.id}` }]), - [{ text: '« Back', callback_data: `shop_city_${country}_${city}` }] + [{ text: '« Back', callback_data: `shop_city_${encodeURIComponent(location.country)}|${encodeURIComponent(location.city)}` }] ] }; diff --git a/src/router/routes.js b/src/router/routes.js index 50f8440..1041635 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -181,7 +181,7 @@ export function registerRoutes() { logDebug(cq.data, 'handleCitySelection'); await userProductHandler.handleCitySelection(cq); }); - callbackRouter.registerPrefix('shop_district_', async (cq) => { + callbackRouter.registerPrefix('shop_loc_', async (cq) => { logDebug(cq.data, 'handleDistrictSelection'); await userProductHandler.handleDistrictSelection(cq); }); @@ -233,7 +233,7 @@ export function registerRoutes() { logDebug(cq.data, 'handleCitySelection'); await productHandler.handleCitySelection(cq); }); - callbackRouter.registerPrefix('prod_district_', async (cq) => { + callbackRouter.registerPrefix('prod_loc_', async (cq) => { logDebug(cq.data, 'handleDistrictSelection'); await productHandler.handleDistrictSelection(cq); }); diff --git a/src/services/locationService.js b/src/services/locationService.js index 884ace7..ad0ed40 100644 --- a/src/services/locationService.js +++ b/src/services/locationService.js @@ -15,7 +15,14 @@ class LocationService { static async getDistrictsByCountryAndCity(country, city) { return await db.allAsync( - 'SELECT district FROM locations WHERE country = ? AND city = ? ORDER BY district', + 'SELECT id, district FROM locations WHERE country = ? AND city = ? ORDER BY district', + [country, city] + ); + } + + static async getLocationsByCountryAndCity(country, city) { + return await db.allAsync( + 'SELECT id, country, city, district FROM locations WHERE country = ? AND city = ? ORDER BY district', [country, city] ); }