refactor(bot): add comments
This commit is contained in:
parent
d9b054df14
commit
1c295a4b41
@ -35,42 +35,54 @@ import {
|
||||
type WizardSessionData,
|
||||
} from 'telegraf/typings/scenes';
|
||||
|
||||
// Расширяем контекст бота для работы с сценами и сессиями
|
||||
type BotContext = TelegrafContext & {
|
||||
scene: SceneContextScene<BotContext, WizardSessionData>;
|
||||
session: SceneSession<WizardSessionData>;
|
||||
wizard: WizardContextWizard<BotContext>;
|
||||
};
|
||||
|
||||
// Создаём экземпляр бота с токеном
|
||||
const bot = new Telegraf<BotContext>(environment.BOT_TOKEN);
|
||||
|
||||
// Создаём менеджер сцен и подключаем сессию
|
||||
const stage = new Scenes.Stage<BotContext>();
|
||||
bot.use(session({ defaultSession: () => ({ __scenes: { cursor: 0, state: {} } }) }));
|
||||
bot.use(stage.middleware());
|
||||
|
||||
// Сцена добавления контакта клиента мастером
|
||||
const addContactScene = new Scenes.WizardScene<BotContext>(
|
||||
'add-contact',
|
||||
|
||||
// Шаг 1: Просим отправить контакт клиента
|
||||
async (context) => {
|
||||
await context.reply(MSG_SEND_CLIENT_CONTACT, { parse_mode: 'HTML' });
|
||||
return context.wizard.next();
|
||||
},
|
||||
|
||||
// Шаг 2: Обрабатываем полученный контакт
|
||||
async (context) => {
|
||||
if (!context.from) {
|
||||
await context.reply('Ошибка: не удалось определить пользователя');
|
||||
return context.scene.leave();
|
||||
}
|
||||
|
||||
// Команда отмены — выход из сцены
|
||||
if (context.message && 'text' in context.message && context.message.text === '/cancel') {
|
||||
await context.reply(MESSAGE_CANCEL + commandsList, { parse_mode: 'HTML' });
|
||||
return context.scene.leave();
|
||||
}
|
||||
|
||||
if (!('message' in context && context.message && 'contact' in context.message)) {
|
||||
// Проверяем, что отправлен контакт (через кнопку Telegram)
|
||||
if (!context.message || !('contact' in context.message)) {
|
||||
await context.reply('Пожалуйста, отправьте контакт клиента через кнопку Telegram');
|
||||
return;
|
||||
return; // остаёмся в сцене, ждем корректный контакт
|
||||
}
|
||||
|
||||
const telegramId = context.from.id;
|
||||
const customerService = new CustomersService({ telegramId });
|
||||
|
||||
// Проверяем, что текущий пользователь — мастер
|
||||
const { customer } = await customerService.getCustomer({ telegramId });
|
||||
if (!customer || !isCustomerMaster(customer)) {
|
||||
await context.reply(MESSAGE_NOT_MASTER, { parse_mode: 'HTML' });
|
||||
@ -78,23 +90,34 @@ const addContactScene = new Scenes.WizardScene<BotContext>(
|
||||
}
|
||||
|
||||
const { contact } = context.message;
|
||||
const name = (contact.first_name || '') + ' ' + (contact.last_name || '').trim();
|
||||
const name = `${contact.first_name || ''} ${contact.last_name || ''}`.trim();
|
||||
const phone = normalizePhoneNumber(contact.phone_number);
|
||||
|
||||
try {
|
||||
const { customer: existingCustomer } = await customerService.getCustomer({ phone });
|
||||
// Проверяем валидность номера телефона
|
||||
if (!isValidPhoneNumber(phone)) {
|
||||
await context.reply(MESSAGE_INVALID_PHONE, { parse_mode: 'HTML' });
|
||||
return; // остаёмся в сцене, ждем правильный номер
|
||||
}
|
||||
|
||||
try {
|
||||
// Проверяем, есть ли клиент с таким номером
|
||||
const { customer: existingCustomer } = await customerService.getCustomer({ phone });
|
||||
let documentId = existingCustomer?.documentId;
|
||||
|
||||
// Если клиента нет, создаём нового
|
||||
if (!documentId) {
|
||||
const registrationService = new RegistrationService();
|
||||
const createCustomerResult = await registrationService.createCustomer({ name, phone });
|
||||
|
||||
documentId = createCustomerResult?.createCustomer?.documentId;
|
||||
if (!documentId) throw new Error('Customer not created');
|
||||
if (!documentId) throw new Error('Клиент не создан');
|
||||
}
|
||||
|
||||
// Добавляем текущего мастера к клиенту
|
||||
const masters = [customer.documentId];
|
||||
await customerService.addMasters({ data: { masters }, documentId });
|
||||
|
||||
// Отправляем подтверждения и инструкции
|
||||
await context.reply(MSG_CONTACT_ADDED(name), { parse_mode: 'HTML' });
|
||||
await context.reply(MSG_CONTACT_FORWARD, { parse_mode: 'HTML' });
|
||||
await context.reply(MESSAGE_SHARE_BOT, { ...KEYBOARD_SHARE_BOT, parse_mode: 'HTML' });
|
||||
@ -107,8 +130,10 @@ const addContactScene = new Scenes.WizardScene<BotContext>(
|
||||
},
|
||||
);
|
||||
|
||||
// Регистрируем сцену
|
||||
stage.register(addContactScene);
|
||||
|
||||
// Команда /start — приветствие и запрос номера, если пользователь новый
|
||||
bot.start(async (context) => {
|
||||
const telegramId = context.from.id;
|
||||
|
||||
@ -116,37 +141,45 @@ bot.start(async (context) => {
|
||||
const { customer } = await customerService.getCustomer({ telegramId });
|
||||
|
||||
if (customer) {
|
||||
// Пользователь уже зарегистрирован — приветствуем
|
||||
return context.reply(MSG_WELCOME_BACK(customer.name) + commandsList, {
|
||||
...KEYBOARD_REMOVE,
|
||||
parse_mode: 'HTML',
|
||||
});
|
||||
}
|
||||
|
||||
// Новый пользователь — просим поделиться номером
|
||||
return context.reply(MSG_WELCOME, { ...KEYBOARD_SHARE_PHONE, parse_mode: 'HTML' });
|
||||
});
|
||||
|
||||
// Команда /help — список команд
|
||||
bot.command('help', async (context) => {
|
||||
return context.reply(commandsList, { ...KEYBOARD_REMOVE, parse_mode: 'HTML' });
|
||||
});
|
||||
|
||||
// Команда /addcontact — начать сцену добавления контакта
|
||||
bot.command('addcontact', async (context) => {
|
||||
const telegramId = context.from.id;
|
||||
const customerService = new CustomersService({ telegramId });
|
||||
const { customer } = await customerService.getCustomer({ telegramId });
|
||||
|
||||
if (!customer) {
|
||||
// Нет номера — просим поделиться
|
||||
return context.reply(MSG_NEED_PHONE, { ...KEYBOARD_SHARE_PHONE, parse_mode: 'HTML' });
|
||||
}
|
||||
|
||||
if (!isCustomerMaster(customer)) {
|
||||
// Нет прав мастера
|
||||
return context.reply(MESSAGE_NOT_MASTER, { parse_mode: 'HTML' });
|
||||
}
|
||||
|
||||
// Входим в сцену
|
||||
return context.scene.enter('add-contact');
|
||||
});
|
||||
|
||||
// Команда /becomemaster — запрос статуса мастера
|
||||
bot.command('becomemaster', async (context) => {
|
||||
const telegramId = context.from.id;
|
||||
|
||||
const customerService = new CustomersService({ telegramId });
|
||||
const { customer } = await customerService.getCustomer({ telegramId });
|
||||
|
||||
@ -158,11 +191,10 @@ bot.command('becomemaster', async (context) => {
|
||||
return context.reply(MSG_ALREADY_MASTER, { parse_mode: 'HTML' });
|
||||
}
|
||||
|
||||
// Обновляем роль клиента на мастер
|
||||
const response = await customerService
|
||||
.updateCustomer({
|
||||
data: {
|
||||
role: Enum_Customer_Role.Master,
|
||||
},
|
||||
data: { role: Enum_Customer_Role.Master },
|
||||
})
|
||||
.catch((error) => {
|
||||
context.reply(MSG_ERROR(error), { parse_mode: 'HTML' });
|
||||
@ -173,24 +205,25 @@ bot.command('becomemaster', async (context) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Команда /sharebot — прислать ссылку на бота
|
||||
bot.command('sharebot', async (context) => {
|
||||
await context.reply(MSG_CONTACT_FORWARD, { parse_mode: 'HTML' });
|
||||
await context.reply(MESSAGE_SHARE_BOT, { ...KEYBOARD_SHARE_BOT, parse_mode: 'HTML' });
|
||||
});
|
||||
|
||||
// Обработка получения контакта от пользователя (регистрация или обновление)
|
||||
bot.on(message('contact'), async (context) => {
|
||||
const telegramId = context.from.id;
|
||||
const { contact } = context.message;
|
||||
const name = (contact.first_name || '') + ' ' + (contact.last_name || '').trim();
|
||||
const name = `${contact.first_name || ''} ${contact.last_name || ''}`.trim();
|
||||
|
||||
// Проверка наличия номера
|
||||
// Проверка наличия номера телефона
|
||||
if (!contact.phone_number) {
|
||||
return context.reply(MESSAGE_INVALID_PHONE, { parse_mode: 'HTML' });
|
||||
}
|
||||
|
||||
// Нормализация и валидация номера
|
||||
const phone = normalizePhoneNumber(contact.phone_number);
|
||||
|
||||
// Валидация номера
|
||||
if (!isValidPhoneNumber(phone)) {
|
||||
return context.reply(MESSAGE_INVALID_PHONE, { parse_mode: 'HTML' });
|
||||
}
|
||||
@ -201,13 +234,9 @@ bot.on(message('contact'), async (context) => {
|
||||
const { customer } = await registrationService.getCustomer({ phone });
|
||||
|
||||
if (customer && !customer.telegramId) {
|
||||
// Пользователь был добавлен ранее мастером — обновляем
|
||||
// Пользователь добавлен ранее мастером — обновляем данные
|
||||
await registrationService.updateCustomer({
|
||||
data: {
|
||||
active: true,
|
||||
name,
|
||||
telegramId,
|
||||
},
|
||||
data: { active: true, name, telegramId },
|
||||
documentId: customer.documentId,
|
||||
});
|
||||
|
||||
@ -217,7 +246,7 @@ bot.on(message('contact'), async (context) => {
|
||||
});
|
||||
}
|
||||
|
||||
// Иначе — новый пользователь, создаём и активируем
|
||||
// Новый пользователь — создаём и активируем
|
||||
const response = await registrationService.createCustomer({ name, phone, telegramId });
|
||||
|
||||
const documentId = response?.createCustomer?.documentId;
|
||||
@ -239,8 +268,9 @@ bot.on(message('contact'), async (context) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Запуск бота
|
||||
bot.launch();
|
||||
|
||||
// Enable graceful stop
|
||||
// Корректное завершение работы
|
||||
process.once('SIGINT', () => bot.stop('SIGINT'));
|
||||
process.once('SIGTERM', () => bot.stop('SIGTERM'));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user