fix(bot): issue #130 — crypto deposit photo-edit 400, chat cleanup via lastInlineMessageId
- depositHandler: handleDepositInstruction + handleDepositSelectWallet use editOrSendCallback (photo-safe fallback) — fixes 'no text in the message to edit' 400 - resetUserContext deletes lastInlineMessageId (stale inline menus cleaned on Reply Keyboard nav) - showProducts/showProfile/showBalance/showPurchases store lastInlineMessageId on sendMessage - answerCallbackQuery verified before dispatch (v1.2.4) - 48 tests pass; bump v1.2.5
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
<svg class="sa-icon sa-thin">
|
||||
<use href="/icons/sprite.svg#tag"></use>
|
||||
</svg>
|
||||
<span class="fs-xs opacity-70">v1.2.4</span>
|
||||
<span class="fs-xs opacity-70">v1.2.5</span>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
@@ -43,10 +43,10 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-info mb-3">
|
||||
<strong>Current:</strong> v1.2.4 · 2026-08-05
|
||||
<strong>Current:</strong> v1.2.5 · 2026-08-05
|
||||
</div>
|
||||
|
||||
<h6 class="fw-bold mb-2">v1.2.4 <span class="text-muted fs-sm">— 2026-08-05</span></h6>
|
||||
<h6 class="fw-bold mb-2">v1.2.5 <span class="text-muted fs-sm">— 2026-08-05</span></h6>
|
||||
<ul class="small mb-3">
|
||||
<li><span class="badge bg-info">refactor</span> Removed deposit amount-selection step; deposit_wallet_ now goes directly to Mercuryo instructions</li>
|
||||
<li><span class="badge bg-primary">feat</span> Updated Mercuryo button text to include VISA/Mastercard branding in all locales</li>
|
||||
|
||||
@@ -6,6 +6,7 @@ import UserService from "../../services/userService.js";
|
||||
import WalletService from "../../services/walletService.js";
|
||||
import logger from "../../utils/logger.js";
|
||||
import { resetUserContext } from "../../utils/messageUtils.js";
|
||||
import userStates from "../../context/userStates.js";
|
||||
import { tForUser, LANGUAGE_NAMES, AVAILABLE_LANGUAGES } from '../../i18n/index.js';
|
||||
|
||||
export default class UserHandler {
|
||||
@@ -85,10 +86,11 @@ ${t('profile.member_since')}: ${new Date(userStats.created_at).toLocaleDateStrin
|
||||
]
|
||||
};
|
||||
|
||||
await bot.sendMessage(chatId, text, {
|
||||
const result = await bot.sendMessage(chatId, text, {
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: keyboard
|
||||
});
|
||||
await userStates.set(chatId, { ...(await userStates.get(chatId) || {}), lastInlineMessageId: result.message_id });
|
||||
} catch (error) {
|
||||
logger.error({ err: error }, 'Error in showProfile');
|
||||
await bot.sendMessage(chatId, t('profile.error_loading'));
|
||||
|
||||
@@ -82,7 +82,8 @@ export default class UserProductHandler {
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
await bot.sendMessage(chatId, message, {reply_markup: keyboard});
|
||||
const result = await bot.sendMessage(chatId, message, {reply_markup: keyboard});
|
||||
await userStates.set(chatId, { ...(await userStates.get(chatId) || {}), lastInlineMessageId: result.message_id });
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error({ err: error }, 'Error in showProducts');
|
||||
|
||||
@@ -159,7 +159,8 @@ export default class UserPurchaseHandler {
|
||||
|
||||
const { text, markup } = await this.viewPurchasePage(user.id, 0, t);
|
||||
|
||||
await bot.sendMessage(chatId, text, { reply_markup: markup, parse_mode: 'Markdown' });
|
||||
const result = await bot.sendMessage(chatId, text, { reply_markup: markup, parse_mode: 'Markdown' });
|
||||
await userStates.set(chatId, { ...(await userStates.get(chatId) || {}), lastInlineMessageId: result.message_id });
|
||||
} catch (error) {
|
||||
logger.error({ err: error }, 'Error in showPurchases');
|
||||
const t = tForUser('en');
|
||||
|
||||
@@ -5,6 +5,7 @@ import WalletService from '../../../services/walletService.js';
|
||||
import bot from '../../../context/bot.js';
|
||||
import logger from '../../../utils/logger.js';
|
||||
import { editOrSendCallback } from '../../../utils/messageUtils.js';
|
||||
import userStates from '../../../context/userStates.js';
|
||||
import { tForUser } from '../../../i18n/index.js';
|
||||
|
||||
export default class BalanceHandler {
|
||||
@@ -86,7 +87,8 @@ export default class BalanceHandler {
|
||||
{ text: t('wallet.transaction_history'), callback_data: 'view_transaction_history_0' }
|
||||
]);
|
||||
|
||||
await bot.sendMessage(chatId, message, { reply_markup: keyboard, parse_mode: 'Markdown' });
|
||||
const result = await bot.sendMessage(chatId, message, { reply_markup: keyboard, parse_mode: 'Markdown' });
|
||||
await userStates.set(chatId, { ...(await userStates.get(chatId) || {}), lastInlineMessageId: result.message_id });
|
||||
} catch (error) {
|
||||
logger.error({ err: error }, 'Error in showBalance');
|
||||
await bot.sendMessage(chatId, t('wallet.error_loading_balance'));
|
||||
|
||||
@@ -35,19 +35,14 @@ export default class DepositHandler {
|
||||
);
|
||||
|
||||
if (cryptoWallets.length === 0) {
|
||||
await bot.editMessageText(
|
||||
t('wallet.no_wallets_prefix'),
|
||||
{
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: t('purchase.add_wallet'), callback_data: 'add_wallet' }],
|
||||
[{ text: t('wallet.back'), callback_data: 'back_to_balance' }]
|
||||
]
|
||||
}
|
||||
await editOrSendCallback(callbackQuery, t('wallet.no_wallets_prefix'), {
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: t('purchase.add_wallet'), callback_data: 'add_wallet' }],
|
||||
[{ text: t('wallet.back'), callback_data: 'back_to_balance' }]
|
||||
]
|
||||
}
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -61,15 +56,10 @@ export default class DepositHandler {
|
||||
|
||||
walletButtons.push([{ text: t('wallet.back'), callback_data: 'back_to_balance' }]);
|
||||
|
||||
await bot.editMessageText(
|
||||
t('wallet.deposit_select_gateway'),
|
||||
{
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: { inline_keyboard: walletButtons }
|
||||
}
|
||||
);
|
||||
await editOrSendCallback(callbackQuery, t('wallet.deposit_select_gateway'), {
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: { inline_keyboard: walletButtons }
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error({ err: error }, 'Error in handleDepositSelectWallet');
|
||||
await editOrSendCallback(callbackQuery, t('wallet.error_loading'));
|
||||
@@ -155,9 +145,7 @@ export default class DepositHandler {
|
||||
]
|
||||
};
|
||||
|
||||
await bot.editMessageText(message, {
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
await editOrSendCallback(callbackQuery, message, {
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: keyboard
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ export async function resetUserContext(chatId) {
|
||||
try {
|
||||
const state = await userStates.get(chatId);
|
||||
if (state) {
|
||||
const msgIds = [state.photoMessageId, state.productMessageId, state.hiddenPhotoMessageId].filter(Boolean);
|
||||
const msgIds = [state.photoMessageId, state.productMessageId, state.hiddenPhotoMessageId, state.lastInlineMessageId].filter(Boolean);
|
||||
for (const msgId of msgIds) {
|
||||
try { await bot.deleteMessage(chatId, msgId); } catch (_) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user