refactor(tgbot-front): moved the navigation handler to a separate file
This commit is contained in:
parent
a22c96e7a0
commit
19164b8d9d
3 changed files with 150 additions and 145 deletions
|
|
@ -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 текущий контекст
|
||||
|
|
|
|||
147
modules/bot/front/src/handleNavigation.cpp
Normal file
147
modules/bot/front/src/handleNavigation.cpp
Normal file
|
|
@ -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<std::vector<BotStructs::Title>> 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<NavigationStep> 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<BotStructs::Title>& 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;
|
||||
}
|
||||
|
|
@ -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<BotStructs::Title> 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<std::vector<BotStructs::Title>> 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<NavigationStep> 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<BotStructs::Title>& 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue