From 19164b8d9dc9e72585250df09a2bd51e44723ee4 Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 5 Dec 2025 23:42:30 +0300 Subject: [PATCH] refactor(tgbot-front): moved the navigation handler to a separate file --- modules/bot/front/include/handlers.hpp | 2 +- modules/bot/front/src/handleNavigation.cpp | 147 +++++++++++++++++++++ modules/bot/front/src/handlers.cpp | 146 +------------------- 3 files changed, 150 insertions(+), 145 deletions(-) create mode 100644 modules/bot/front/src/handleNavigation.cpp diff --git a/modules/bot/front/include/handlers.hpp b/modules/bot/front/include/handlers.hpp index cb462cd..873d74c 100644 --- a/modules/bot/front/include/handlers.hpp +++ b/modules/bot/front/include/handlers.hpp @@ -71,7 +71,7 @@ private: /// @param userId Идентификатор пользователя /// @param payload Полезная нагрузка /// @return HandlerResult - static HandlerResult returnMyTitles(int64_t userId, int64_t payload); + /// static HandlerResult returnMyTitles(int64_t userId, int64_t payload); /// @brief Вход в новое состояние /// @param ctx текущий контекст diff --git a/modules/bot/front/src/handleNavigation.cpp b/modules/bot/front/src/handleNavigation.cpp new file mode 100644 index 0000000..0bd02a3 --- /dev/null +++ b/modules/bot/front/src/handleNavigation.cpp @@ -0,0 +1,147 @@ +#include "handlers.hpp" +#include "KeyboardFactory.hpp" +#include "structs.hpp" +#include "constants.hpp" + +void BotHandlers::handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext& ctx) { + const auto& current = ctx.history.back(); // текущий экран + const std::string& data = query->data; + + // Пагинация (в списках) + if ((data == BotConstants::Callback::LIST_PREV || data == BotConstants::Callback::LIST_NEXT) + && (current.state == UserState::VIEWING_MY_TITLES || current.state == UserState::VIEWING_REVIEW_LIST || + current.state == UserState::VIEWING_FOUND_TITLES)) { + + int64_t newPayload = current.payload; + if (data == BotConstants::Callback::LIST_PREV && newPayload > 0) { + reducePayload(newPayload, current.state); + } else if (data == BotConstants::Callback::LIST_NEXT) { + increasePayload(newPayload, current.state); + } else { + if (data == BotConstants::Callback::LIST_PREV) { + std::cout << "Error: navigation:prev callback for 1st page" << std::endl; + return; + } + // TODO: log + std::cout << "Error: navigation:prev unknown error" << std::endl; + } + + ctx.history.back().payload = newPayload; + + auto result = renderCurrent(query, ctx); + if(result.message == "meow") return; // TODO: убрать + editMessage(query, result); + return; + } + + // Обработка back по интерфейсу + if (data == BotConstants::Callback::NAV_BACK) { + if (!popState(ctx)) { + sendError(query, BotConstants::Text::SAD_ERROR); + return; + } + auto result = renderCurrent(query, ctx); + if(result.message == "meow") return; // TODO: убрать + editMessage(query, result); + return; + } + + // Переходы вперёд (push) + auto newStepOpt = computeNextStep(query, current); + if (!newStepOpt.has_value()) { + sendError(query, BotConstants::Text::SAD_ERROR); + return; + } + + ctx.history.push_back(*newStepOpt); + auto result = renderCurrent(query, ctx); + if(result.message == "meow") return; // TODO: убрать + editMessage(query, result); +} + +HandlerResult BotHandlers::renderCurrent(TgBot::CallbackQuery::Ptr query, const UserContext& ctx) { + const auto& step = ctx.history.back(); + int64_t userId = query->from->id; + switch (step.state) { + case UserState::MAIN_MENU: + return showMainMenu(); + case UserState::VIEWING_MY_TITLES: + server_.fetchUserTitlesAsync(std::to_string(2)) // ALARM: тестовое значение вместо userId + .then([this, query](pplx::task> t) { + try { + auto titles = t.get(); + + std::string message = formatTitlesList(titles); + auto keyboard = KeyboardFactory::createMyTitles(titles); + + editMessage(query, {message, keyboard}); + + } catch (const std::exception& e) { + sendError(query, BotConstants::Text::SERVER_ERROR); + // Логирование ошибки (например, в cerr) + } + }); + + return {"meow", nullptr}; + /* + case UserState::VIEWING_TITLE_PAGE: + return returnTitlePage(step.payload); // payload = titleId + case UserState::VIEWING_REVIEW: + return returnReview(step.payload); // payload = reviewId + case UserState::AWAITING_REVIEW: + return HandlerResult{"Пришлите текст отзыва:", nullptr}; + // ... + */ + default: + return HandlerResult{BotConstants::Text::SAD_ERROR, nullptr}; + } +} + +std::optional BotHandlers::computeNextStep( + const TgBot::CallbackQuery::Ptr& query, + const NavigationStep& current +) { + const std::string& data = query->data; + + switch (current.state) { + case UserState::MAIN_MENU: + if (data == BotConstants::Callback::MY_TITLES) { + return NavigationStep{UserState::VIEWING_MY_TITLES, 0}; + } + break; + /* + case UserState::VIEWING_MY_TITLES: + if (data.starts_with("title_")) { + int64_t titleId = parseId(data); + return NavigationStep{UserState::VIEWING_TITLE_PAGE, titleId}; + } + break; + + case UserState::VIEWING_TITLE_PAGE: + if (data == BotConstants::Callback::ACTION_ADD_REVIEW) { + return NavigationStep{UserState::AWAITING_REVIEW, current.payload}; + } + if (data.starts_with("review_")) { + int64_t reviewId = parseId(data); + return NavigationStep{UserState::VIEWING_REVIEW, reviewId}; + } + break; + */ + default: + break; + } + return std::nullopt; +} + +std::string BotHandlers::formatTitlesList(const std::vector& titles) { + if (titles.empty()) { + return "У вас пока нет тайтлов."; + } + + std::string msg; + for (size_t i = 0; i < titles.size(); ++i) { + // num — 0-based, но в сообщении показываем 1-based + msg += std::to_string(i + 1) + ". " + titles[i].name + "\n"; + } + return msg; +} \ No newline at end of file diff --git a/modules/bot/front/src/handlers.cpp b/modules/bot/front/src/handlers.cpp index 88e026e..d19166a 100644 --- a/modules/bot/front/src/handlers.cpp +++ b/modules/bot/front/src/handlers.cpp @@ -20,6 +20,7 @@ void BotHandlers::handleCallback(TgBot::CallbackQuery::Ptr query) { processCallbackImpl(query); } +/* deprecated. will be deleted soon. HandlerResult BotHandlers::returnMyTitles(int64_t userId, int64_t payload) { // Здесь должен происходить запрос на сервер std::vector titles = {{123, "Школа мертвяков", "", 1}, {321, "KissXsis", "", 2}}; @@ -29,7 +30,7 @@ HandlerResult BotHandlers::returnMyTitles(int64_t userId, int64_t payload) { result.message = "1. Школа мертвяков\n2. KissXsis\n"; return result; -} +}*/ void BotHandlers::handleMessage(TgBot::Message::Ptr message) { //TODO: просмотр состояния пользователя @@ -60,62 +61,6 @@ void BotHandlers::processCallbackImpl(TgBot::CallbackQuery::Ptr query) { } } -void BotHandlers::handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext& ctx) { - const auto& current = ctx.history.back(); // текущий экран - const std::string& data = query->data; - - // Пагинация (в списках) - if ((data == BotConstants::Callback::LIST_PREV || data == BotConstants::Callback::LIST_NEXT) - && (current.state == UserState::VIEWING_MY_TITLES || current.state == UserState::VIEWING_REVIEW_LIST || - current.state == UserState::VIEWING_FOUND_TITLES)) { - - int64_t newPayload = current.payload; - if (data == BotConstants::Callback::LIST_PREV && newPayload > 0) { - reducePayload(newPayload, current.state); - } else if (data == BotConstants::Callback::LIST_NEXT) { - increasePayload(newPayload, current.state); - } else { - if (data == BotConstants::Callback::LIST_PREV) { - std::cout << "Error: navigation:prev callback for 1st page" << std::endl; - return; - } - // TODO: log - std::cout << "Error: navigation:prev unknown error" << std::endl; - } - - ctx.history.back().payload = newPayload; - - auto result = renderCurrent(query, ctx); - if(result.message == "meow") return; // TODO: убрать - editMessage(query, result); - return; - } - - // Обработка back по интерфейсу - if (data == BotConstants::Callback::NAV_BACK) { - if (!popState(ctx)) { - sendError(query, BotConstants::Text::SAD_ERROR); - return; - } - auto result = renderCurrent(query, ctx); - if(result.message == "meow") return; // TODO: убрать - editMessage(query, result); - return; - } - - // Переходы вперёд (push) - auto newStepOpt = computeNextStep(query, current); - if (!newStepOpt.has_value()) { - sendError(query, BotConstants::Text::SAD_ERROR); - return; - } - - ctx.history.push_back(*newStepOpt); - auto result = renderCurrent(query, ctx); - if(result.message == "meow") return; // TODO: убрать - editMessage(query, result); -} - void BotHandlers::pushState(UserContext& ctx, UserState newState, int64_t payload) { ctx.history.push_back({newState, payload}); } @@ -164,44 +109,6 @@ void BotHandlers::editMessage(TgBot::CallbackQuery::Ptr query, HandlerResult res ); } -HandlerResult BotHandlers::renderCurrent(TgBot::CallbackQuery::Ptr query, const UserContext& ctx) { - const auto& step = ctx.history.back(); - int64_t userId = query->from->id; - switch (step.state) { - case UserState::MAIN_MENU: - return showMainMenu(); - case UserState::VIEWING_MY_TITLES: - server_.fetchUserTitlesAsync(std::to_string(2)) // ALARM: тестовое значение вместо userId - .then([this, query](pplx::task> t) { - try { - auto titles = t.get(); - - std::string message = formatTitlesList(titles); - auto keyboard = KeyboardFactory::createMyTitles(titles); - - editMessage(query, {message, keyboard}); - - } catch (const std::exception& e) { - sendError(query, BotConstants::Text::SERVER_ERROR); - // Логирование ошибки (например, в cerr) - } - }); - - return {"meow", nullptr}; - /* - case UserState::VIEWING_TITLE_PAGE: - return returnTitlePage(step.payload); // payload = titleId - case UserState::VIEWING_REVIEW: - return returnReview(step.payload); // payload = reviewId - case UserState::AWAITING_REVIEW: - return HandlerResult{"Пришлите текст отзыва:", nullptr}; - // ... - */ - default: - return HandlerResult{BotConstants::Text::SAD_ERROR, nullptr}; - } -} - HandlerResult BotHandlers::showMainMenu() { auto keyboard = KeyboardFactory::createMainMenu(); @@ -221,42 +128,6 @@ void BotHandlers::sendError(TgBot::CallbackQuery::Ptr query, const std::string& editMessage(query, {errText, keyboard}); } -std::optional BotHandlers::computeNextStep( - const TgBot::CallbackQuery::Ptr& query, - const NavigationStep& current -) { - const std::string& data = query->data; - - switch (current.state) { - case UserState::MAIN_MENU: - if (data == BotConstants::Callback::MY_TITLES) { - return NavigationStep{UserState::VIEWING_MY_TITLES, 0}; - } - break; - /* - case UserState::VIEWING_MY_TITLES: - if (data.starts_with("title_")) { - int64_t titleId = parseId(data); - return NavigationStep{UserState::VIEWING_TITLE_PAGE, titleId}; - } - break; - - case UserState::VIEWING_TITLE_PAGE: - if (data == BotConstants::Callback::ACTION_ADD_REVIEW) { - return NavigationStep{UserState::AWAITING_REVIEW, current.payload}; - } - if (data.starts_with("review_")) { - int64_t reviewId = parseId(data); - return NavigationStep{UserState::VIEWING_REVIEW, reviewId}; - } - break; - */ - default: - break; - } - return std::nullopt; -} - void BotHandlers::createInitContext(int64_t chatId) { NavigationStep init = {UserState::MAIN_MENU, BotConstants::NULL_PAYLOAD}; userContexts[chatId] = {chatId, {init}}; @@ -276,17 +147,4 @@ void BotHandlers::handleError(TgBot::CallbackQuery::Ptr query, UserContext& ctx) HandlerResult result = {BotConstants::Text::AUTH_ERROR, nullptr}; editMessage(query, result); } -} - -std::string BotHandlers::formatTitlesList(const std::vector& titles) { - if (titles.empty()) { - return "У вас пока нет тайтлов."; - } - - std::string msg; - for (size_t i = 0; i < titles.size(); ++i) { - // num — 0-based, но в сообщении показываем 1-based - msg += std::to_string(i + 1) + ". " + titles[i].name + "\n"; - } - return msg; } \ No newline at end of file