Files
hereconnect/services/tg-bot/src/bot/conversations/newQRCodeConversation.ts
T
ti e07d748e87
Deploy app frontend / app frontend (push) Failing after 49s
Deploy db-migrations / db-migrations (push) Failing after 39s
Deploy service message-delivery-method-web-push / service message-delivery-method-web-push (push) Failing after 46s
add tg_bot_sessions, padding to qrcode
2024-12-12 13:30:28 +02:00

120 lines
4.4 KiB
TypeScript

import { type QRCodeDocument } from "@hereconnect/types";
import { Conversation } from "@grammyjs/conversations";
import { InputFile } from "grammy";
import type { MyContext } from "../../types/myContext";
import { qrCodePlacements } from "../../models/types";
import {
buildPlacementKeyboard,
buildActionsKeyboard,
} from "../utils/keyboards";
import { createQRCode } from "../../api/qrCodes";
import { generateQRCodeImage } from "../../services/qrGenerator";
// Тип разговора (конверсии)
type MyConversation = Conversation<MyContext>;
export async function newQRCodeConversation(
conversation: MyConversation,
ctx: MyContext,
) {
if (!ctx.userDoc) {
await ctx.reply(
"Не удалось определить вашего пользователя. Попробуйте позже.",
);
return;
}
const userUuid = ctx.userDoc.user_uuid;
if (!userUuid) {
await ctx.reply(
"У вашего профиля отсутствует UUID. Обратитесь в поддержку.",
);
return;
}
// 1. Выбор типа объекта (placement)
await ctx.reply("Выберите объект, для которого будет создан QR-код:", {
reply_markup: {
inline_keyboard: buildPlacementKeyboard(qrCodePlacements),
},
});
const placementChoice = await conversation.waitFor("callback_query:data");
const placement = placementChoice.update.callback_query?.data;
// Проверяем, что выбранное значение входит в допустимые типы
if (!qrCodePlacements.some((p) => p.type === placement)) {
await ctx.reply("Неверный выбор. Попробуйте снова /new");
return;
}
// Преобразуем `placement` в строго типизированное значение
const typedPlacement = placement as QRCodeDocument["placement"];
// Подтверждаем выбор
await placementChoice.answerCallbackQuery({ text: "Объект выбран!" });
// 2. Ввод названия QR-кода
await ctx.reply(
"Введите название для вашего QR-кода (например: 'Моя машина'):",
);
const nameMsg = await conversation.waitFor("message:text");
const name = nameMsg.message.text.trim();
if (name.length < 2) {
await ctx.reply(
"Название должно содержать минимум 2 символа. Попробуйте снова /new.",
);
return;
}
// 3. Выбор действий, доступных при сканировании
await ctx.reply(
"Выберите одно или несколько действий, которые будут доступны при сканировании этого QR-кода:",
{
reply_markup: {
inline_keyboard: buildActionsKeyboard([
{ action: "sendMessage", label: "Отправить сообщение" },
{ action: "viewContactInfo", label: "Посмотреть контактные данные" },
]),
},
},
);
const actionsMsg = await conversation.waitFor("callback_query:data");
const chosenAction = actionsMsg.update.callback_query?.data;
if (!chosenAction) {
await ctx.reply("Вы не выбрали действие. Попробуйте снова /new.");
return;
}
// Подтверждаем выбор
await actionsMsg.answerCallbackQuery({ text: "Действие выбрано!" });
// Пока для MVP можно выбрать только одно действие, в будущем можно расширить
const chosenActions = [chosenAction];
// 4. Создание документа в БД
const { url, uri } = await createQRCode({
userUuid,
name,
placement: typedPlacement,
actions: chosenActions,
});
// 5. Генерация QR-кода
const pngBuffer = await generateQRCodeImage(url, { format: "png" });
// 6. Отправляем пользователю QR-код
await ctx.reply("Ваш QR-код готов! Вот он:");
await ctx.replyWithPhoto(
new InputFile(new Uint8Array(pngBuffer.buffer), "qr.png"),
);
await ctx.reply(
`Разместите этот код на вашем объекте. При сканировании по адресу ${url} посетители смогут взаимодействовать с вами.`,
);
// Завершаем разговор
}