Files
hereconnect/services/tg-bot/src/bot/conversations/selectPredefinedMessages.ts
T

326 lines
11 KiB
TypeScript
Raw Normal View History

2024-12-17 02:41:14 +02:00
import { MyContext } from "../../types/myContext";
import { Conversation } from "@grammyjs/conversations";
import { defaultMessages } from "@hereconnect/constants";
import { InlineKeyboardMarkup } from "@grammyjs/types";
// Тип разговора
type MyConversation = Conversation<MyContext>;
export async function selectPredefinedMessages(
conversation: MyConversation,
ctx: MyContext,
placement: keyof typeof defaultMessages,
): Promise<string[]> {
const messages: string[] = [...defaultMessages[placement]];
let mode: "default" | "edit" | "sort" = "default";
let selectedIndex: number | null = null;
let sortOrder: number[] = [];
const updateKeyboard = (): InlineKeyboardMarkup => ({
inline_keyboard: messages
.map((message, index) => {
const prefix =
mode === "edit" && selectedIndex === index
? "📝 "
: mode === "sort" && sortOrder.includes(index)
? `${sortOrder.indexOf(index) + 1}. `
: "";
return [
{
text: `${prefix}${message}`,
callback_data: `select:${index}`,
},
];
})
.concat(
mode === "sort"
? [
[{ text: "✅ Завершить сортировку", callback_data: "done_sort" }],
[
{
text: "❌ Отменить сортировку",
callback_data: "cancel_sort",
},
],
]
: mode === "edit" && selectedIndex !== null
? [
[
{
text: `❌ Удалить «${messages[selectedIndex]}»`,
callback_data: `delete:${selectedIndex}`,
},
],
[
{
text: "❌ Отменить редактирование",
callback_data: "cancel_edit",
},
],
]
: messages.length > 0
? [
[{ text: "🔀 Поменять порядок", callback_data: "sort" }],
[{ text: "✅ Готово", callback_data: "done" }],
]
: [[{ text: "✅ Готово", callback_data: "done" }]],
),
});
// Функция для отправки или редактирования сообщения
const sendOrEditMessage = async (
text: string,
options: {
reply_markup: InlineKeyboardMarkup;
parse_mode?: "Markdown" | "MarkdownV2" | "HTML";
},
forceNew = false,
) => {
try {
if (forceNew && ctx.session.messageId) {
try {
await ctx.api.deleteMessage(ctx.chat!.id, ctx.session.messageId);
ctx.session.messageId = undefined;
console.log("deleteMessage", ctx.session.messageId);
} catch (deleteErr) {
console.warn(
"Ошибка удаления старого сообщения:",
ctx.session.messageId,
deleteErr,
);
ctx.session.messageId = undefined;
}
}
if (ctx.session.messageId) {
await ctx.api.editMessageText(
ctx.chat!.id,
ctx.session.messageId,
text,
options,
);
} else {
const replyMessage = await ctx.reply(text, options);
console.log("replyMessage.message_id", replyMessage.message_id);
ctx.session.messageId = replyMessage.message_id;
}
} catch (err) {
console.error(
"Ошибка обновления сообщения, создаем новое:",
ctx.session.messageId,
err,
);
if (ctx.session.messageId) {
try {
await ctx.api.deleteMessage(ctx.chat!.id, ctx.session.messageId);
console.log("deleteMessage", ctx.session.messageId);
} catch (deleteErr) {
console.warn(
"Ошибка удаления старого сообщения:",
ctx.session.messageId,
deleteErr,
);
}
}
const newMessage = await ctx.reply(text, options);
console.log("newMessage.message_id", newMessage.message_id);
ctx.session.messageId = newMessage.message_id;
}
};
// Начальное сообщение
await sendOrEditMessage(
`**Настройка предустановленных сообщений**
Эти сообщения будут предлагаться пользователю при сканировании QR‑кода. Он сможет выбрать одно из них или написать своё.
Напишите сообщение для добавления, нажмите на сообщение для редактирования или выберите "🔀 Поменять порядок" для сортировки.`,
{ parse_mode: "Markdown", reply_markup: updateKeyboard() },
);
while (true) {
const actionChoice = await conversation.waitFor([
"callback_query:data",
"message:text",
]);
const choice = actionChoice.update.callback_query?.data;
if (!choice && !actionChoice.message) {
if (choice) {
// await actionChoice.answerCallbackQuery({
// text: "Произошла ошибка. Попробуйте снова.",
// });
continue;
}
ctx.session.messageId = undefined;
break;
}
const messageText = actionChoice.message?.text.trim();
if (!choice) {
if (messageText) {
if (mode === "edit" && selectedIndex !== null) {
messages[selectedIndex] = messageText;
mode = "default";
selectedIndex = null;
// await ctx.reply(`Сообщение обновлено: ${messageText}`);
await sendOrEditMessage(
"Сообщение обновлено.",
{
parse_mode: "Markdown",
reply_markup: updateKeyboard(),
},
true,
);
} else {
messages.push(messageText);
// await ctx.reply(`Сообщение добавлено: ${messageText}`);
await sendOrEditMessage(
"Сообщение добавлено.",
{
parse_mode: "Markdown",
reply_markup: updateKeyboard(),
},
true,
);
}
} else {
await ctx.reply(`Введите текст сообщения.`);
}
continue;
}
if (choice === "done") {
// await actionChoice.answerCallbackQuery({ text: "Настройка завершена!" });
await ctx.api.deleteMessage(ctx.chat!.id, ctx.session.messageId!);
ctx.session.messageId = undefined;
break;
}
if (choice === "sort") {
mode = "sort";
sortOrder.length = 0;
// await actionChoice.answerCallbackQuery({ text: "Режим сортировки." });
await sendOrEditMessage("Нажмите на сообщения по порядку.", {
parse_mode: "Markdown",
reply_markup: updateKeyboard(),
});
continue;
}
if (mode === "sort" && choice.startsWith("select:")) {
const index = parseInt(choice.replace("select:", ""), 10);
if (sortOrder.includes(index)) {
sortOrder.splice(sortOrder.indexOf(index), 1);
} else {
sortOrder.push(index);
}
const sortedMessages: string[] = [];
sortOrder.forEach((sortIndex, messagesIndex) => {
sortedMessages[messagesIndex] = messages[sortIndex];
});
messages.forEach((message, index) => {
if (!sortOrder.includes(index)) {
sortedMessages.push(message);
}
});
// Обновляем порядок сообщений
for (let i = 0; i < sortedMessages.length; i++) {
messages[i] = sortedMessages[i];
}
for (let i = 0; i < sortOrder.length; i++) {
sortOrder[i] = i;
}
// await actionChoice.answerCallbackQuery({ text: "Сообщение перемещено." });
await sendOrEditMessage(
"Нажмите на сообщения по порядку, начиная с первого.",
{ parse_mode: "Markdown", reply_markup: updateKeyboard() },
);
continue;
}
if (choice === "cancel_sort") {
mode = "default";
sortOrder.length = 0;
// await actionChoice.answerCallbackQuery({ text: "Сортировка отменена." });
await sendOrEditMessage(
"Сортировка отменена. Возврат к стандартному режиму.",
{ parse_mode: "Markdown", reply_markup: updateKeyboard() },
);
continue;
}
if (choice === "done_sort") {
mode = "default";
sortOrder.length = 0;
// await actionChoice.answerCallbackQuery({ text: "Сортировка завершена." });
await sendOrEditMessage("Сортировка завершена.", {
parse_mode: "Markdown",
reply_markup: updateKeyboard(),
});
continue;
}
if (choice.startsWith("select:")) {
const index = parseInt(choice.replace("select:", ""), 10);
if (selectedIndex === index) {
// await actionChoice.answerCallbackQuery({
// text: "Редактирование отменено.",
// });
mode = "default";
selectedIndex = null;
await sendOrEditMessage("Редактирование отменено.", {
parse_mode: "Markdown",
reply_markup: updateKeyboard(),
});
continue;
}
mode = "edit";
selectedIndex = index;
// await actionChoice.answerCallbackQuery({
// text: `Редактирование сообщения: "${messages[index]}"`,
// });
await sendOrEditMessage(
`Редактирование сообщения: "${messages[index]}"`,
{ parse_mode: "Markdown", reply_markup: updateKeyboard() },
);
continue;
}
if (choice === "cancel_edit") {
mode = "default";
selectedIndex = null;
// await actionChoice.answerCallbackQuery({
// text: "Редактирование отменено.",
// });
await sendOrEditMessage("Редактирование отменено.", {
parse_mode: "Markdown",
reply_markup: updateKeyboard(),
});
continue;
}
if (choice.startsWith("delete:")) {
const index = parseInt(choice.replace("delete:", ""), 10);
const deletedMessage = messages.splice(index, 1)[0];
mode = "default";
selectedIndex = null;
// await actionChoice.answerCallbackQuery({
// text: `Сообщение "${deletedMessage}" удалено.`,
// });
await sendOrEditMessage(`Сообщение "${deletedMessage}" удалено.`, {
parse_mode: "Markdown",
reply_markup: updateKeyboard(),
});
}
}
return messages;
}