feat(bot): add phone number validation and error handling for contact messages

set active: true after full registration
This commit is contained in:
vchikalkin 2025-07-03 21:30:17 +03:00
parent ac897a77f8
commit d9b054df14
3 changed files with 54 additions and 21 deletions

View File

@ -7,6 +7,7 @@ import {
KEYBOARD_SHARE_BOT,
KEYBOARD_SHARE_PHONE,
MESSAGE_CANCEL,
MESSAGE_INVALID_PHONE,
MESSAGE_NOT_MASTER,
MESSAGE_SHARE_BOT,
MSG_ALREADY_MASTER,
@ -21,7 +22,7 @@ import {
MSG_WELCOME_BACK,
} from './message';
import { isCustomerMaster } from './utils/customer';
import { normalizePhoneNumber } from './utils/phone';
import { isValidPhoneNumber, normalizePhoneNumber } from './utils/phone';
import { CustomersService } from '@repo/graphql/api/customers';
import { RegistrationService } from '@repo/graphql/api/registration';
import { Enum_Customer_Role } from '@repo/graphql/types';
@ -181,34 +182,60 @@ 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 phone = normalizePhoneNumber(contact.phone_number);
const registrationService = new RegistrationService();
const { customer } = await registrationService.getCustomer({ phone });
if (customer && !customer.telegramId) {
// Значит пользователя добавили через отправку контакта
await registrationService.updateCustomer({
data: { active: true, name, telegramId },
documentId: customer.documentId,
});
return context.reply(MSG_PHONE_SAVED + commandsList, {
...KEYBOARD_REMOVE,
parse_mode: 'HTML',
});
// Проверка наличия номера
if (!contact.phone_number) {
return context.reply(MESSAGE_INVALID_PHONE, { parse_mode: 'HTML' });
}
const response = await registrationService
.createCustomer({ name, phone, telegramId })
.catch((error) => {
context.reply(MSG_ERROR(error), { parse_mode: 'HTML' });
const phone = normalizePhoneNumber(contact.phone_number);
// Валидация номера
if (!isValidPhoneNumber(phone)) {
return context.reply(MESSAGE_INVALID_PHONE, { parse_mode: 'HTML' });
}
const registrationService = new RegistrationService();
try {
const { customer } = await registrationService.getCustomer({ phone });
if (customer && !customer.telegramId) {
// Пользователь был добавлен ранее мастером — обновляем
await registrationService.updateCustomer({
data: {
active: true,
name,
telegramId,
},
documentId: customer.documentId,
});
return context.reply(MSG_PHONE_SAVED + commandsList, {
...KEYBOARD_REMOVE,
parse_mode: 'HTML',
});
}
// Иначе — новый пользователь, создаём и активируем
const response = await registrationService.createCustomer({ name, phone, telegramId });
const documentId = response?.createCustomer?.documentId;
if (!documentId) {
throw new Error('Не удалось создать клиента: отсутствует documentId');
}
await registrationService.updateCustomer({
data: { active: true },
documentId,
});
if (response) {
return context.reply(MSG_PHONE_SAVED + commandsList, {
...KEYBOARD_REMOVE,
parse_mode: 'HTML',
});
} catch (error) {
return context.reply(MSG_ERROR(error), { parse_mode: 'HTML' });
}
});

View File

@ -79,3 +79,5 @@ export const MESSAGE_SHARE_BOT =
'📅 <b>Воспользуйтесь этим ботом для записи к вашему мастеру!</b>\nНажмите кнопку ниже, чтобы начать';
export const MESSAGE_CANCEL = '<b>❌ Отменена операции</b>';
export const MESSAGE_INVALID_PHONE = '❌ <b>Некорректный номер телефона</b>';

View File

@ -1,3 +1,7 @@
export function isValidPhoneNumber(phone: string) {
return /^\+7\d{10}$/u.test(phone);
}
export function normalizePhoneNumber(phone: string): string {
const digitsOnly = phone.replaceAll(/\D/gu, '');