diff --git a/apps/bot/locales/ru.ftl b/apps/bot/locales/ru.ftl index 1c93b98..ff99952 100644 --- a/apps/bot/locales/ru.ftl +++ b/apps/bot/locales/ru.ftl @@ -25,7 +25,7 @@ description = start = .description = Запуск бота addcontact = - .description = Добавить контакт пользователя + .description = Добавить контакт sharebot = .description = Поделиться ботом subscribe = @@ -36,7 +36,7 @@ help = .description = Список команд и поддержка commands-list = 📋 Доступные команды: - • /addcontact — добавить контакт пользователя + • /addcontact — добавить контакт • /sharebot — поделиться ботом • /subscribe — приобрести Pro доступ • /pro — информация о вашем Pro доступе diff --git a/apps/bot/package.json b/apps/bot/package.json index 1f0a814..d57e975 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -29,6 +29,7 @@ "dayjs": "catalog:", "grammy": "^1.38.1", "ioredis": "^5.7.0", + "libphonenumber-js": "^1.12.24", "pino": "^9.9.0", "pino-pretty": "^13.1.1", "radashi": "catalog:", diff --git a/apps/bot/src/bot/conversations/add-contact.ts b/apps/bot/src/bot/conversations/add-contact.ts index 708d348..ac48f29 100644 --- a/apps/bot/src/bot/conversations/add-contact.ts +++ b/apps/bot/src/bot/conversations/add-contact.ts @@ -5,10 +5,10 @@ import { env } from '@/config/env'; import { KEYBOARD_SHARE_BOT, KEYBOARD_SHARE_PHONE } from '@/config/keyboards'; import { parseContact } from '@/utils/contact'; import { combine } from '@/utils/messages'; -import { isValidPhoneNumber, normalizePhoneNumber } from '@/utils/phone'; import { type Conversation } from '@grammyjs/conversations'; import { CustomersService } from '@repo/graphql/api/customers'; import { RegistrationService } from '@repo/graphql/api/registration'; +import parsePhoneNumber from 'libphonenumber-js'; export async function addContact(conversation: Conversation, ctx: Context) { // Все пользователи могут добавлять контакты @@ -60,23 +60,36 @@ export async function addContact(conversation: Conversation, c let phone = ''; if (firstCtx.message?.contact) { + /** + * Отправлен контакт + */ const { contact } = firstCtx.message; const parsedContact = parseContact(contact); + const parsedPhone = parsePhoneNumber(contact.phone_number, 'RU'); + name = parsedContact.name; surname = parsedContact.surname; - phone = normalizePhoneNumber(parsedContact.phone); + + if (!parsedPhone?.isValid() || !parsedPhone.number) { + return ctx.reply(await conversation.external(({ t }) => t('msg-invalid-phone'))); + } + + phone = parsedPhone.number; } else if (firstCtx.message?.text) { - const typedPhone = normalizePhoneNumber(firstCtx.message.text); - if (!isValidPhoneNumber(typedPhone)) { + /** + * Номер в тексте сообщения + */ + const parsedPhone = parsePhoneNumber(firstCtx.message.text, 'RU'); + if (!parsedPhone?.isValid() || !parsedPhone.number) { return ctx.reply(await conversation.external(({ t }) => t('msg-invalid-phone'))); } // Нельзя добавлять свой собственный номер телефона - if (customer.phone && normalizePhoneNumber(customer.phone) === typedPhone) { + if (customer.phone && customer.phone === parsedPhone.number) { return ctx.reply(await conversation.external(({ t }) => t('err-cannot-add-self'))); } - phone = typedPhone; + phone = parsedPhone.number; // Просим ввести имя клиента await ctx.reply(await conversation.external(({ t }) => t('msg-send-client-name'))); @@ -101,11 +114,6 @@ export async function addContact(conversation: Conversation, c return ctx.reply(await conversation.external(({ t }) => t('msg-send-client-contact-or-phone'))); } - // Проверяем валидность номера телефона - if (!isValidPhoneNumber(phone)) { - return ctx.reply(await conversation.external(({ t }) => t('msg-invalid-phone'))); - } - try { // Проверяем, есть ли клиент с таким номером const { customer: existingCustomer } = await registrationService._NOCACHE_GetCustomer({ diff --git a/apps/bot/src/bot/features/registration.ts b/apps/bot/src/bot/features/registration.ts index cc21209..211681b 100644 --- a/apps/bot/src/bot/features/registration.ts +++ b/apps/bot/src/bot/features/registration.ts @@ -2,9 +2,9 @@ import { type Context } from '@/bot/context'; import { logHandle } from '@/bot/helpers/logging'; import { KEYBOARD_REMOVE, mainMenu } from '@/config/keyboards'; import { parseContact } from '@/utils/contact'; -import { isValidPhoneNumber, normalizePhoneNumber } from '@/utils/phone'; import { RegistrationService } from '@repo/graphql/api/registration'; import { Composer } from 'grammy'; +import parsePhoneNumber from 'libphonenumber-js'; const composer = new Composer(); @@ -35,13 +35,15 @@ feature.on(':contact', logHandle('contact-registration'), async (ctx) => { } // Нормализация и валидация номера - const phone = normalizePhoneNumber(contact.phone_number); - if (!isValidPhoneNumber(phone)) { + const parsedPhone = parsePhoneNumber(contact.phone_number, 'RU'); + if (!parsedPhone?.isValid() || !parsedPhone?.number) { return ctx.reply(ctx.t('msg-invalid-phone')); } try { - const { customer } = await registrationService._NOCACHE_GetCustomer({ phone }); + const { customer } = await registrationService._NOCACHE_GetCustomer({ + phone: parsedPhone.number, + }); if (customer && !customer.telegramId) { // Пользователь добавлен ранее мастером — обновляем данные @@ -57,7 +59,7 @@ feature.on(':contact', logHandle('contact-registration'), async (ctx) => { // Новый пользователь — создаём и активируем const response = await registrationService.createCustomer({ - data: { name, phone, surname, telegramId }, + data: { name, phone: parsedPhone.number, surname, telegramId }, }); const documentId = response?.createCustomer?.documentId; diff --git a/apps/bot/src/utils/phone.ts b/apps/bot/src/utils/phone.ts deleted file mode 100644 index eac63f2..0000000 --- a/apps/bot/src/utils/phone.ts +++ /dev/null @@ -1,9 +0,0 @@ -export function isValidPhoneNumber(phone: string) { - return /^\+7\d{10}$/u.test(phone); -} - -export function normalizePhoneNumber(phone: string): string { - const digitsOnly = phone.replaceAll(/\D/gu, ''); - - return `+${digitsOnly}`; -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eb36b57..e387522 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -153,6 +153,9 @@ importers: ioredis: specifier: ^5.7.0 version: 5.7.0 + libphonenumber-js: + specifier: ^1.12.24 + version: 1.12.24 pino: specifier: ^9.9.0 version: 9.9.0 @@ -6094,6 +6097,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + libphonenumber-js@1.12.24: + resolution: {integrity: sha512-l5IlyL9AONj4voSd7q9xkuQOL4u8Ty44puTic7J88CmdXkxfGsRfoVLXHCxppwehgpb/Chdb80FFehHqjN3ItQ==} + light-my-request@5.14.0: resolution: {integrity: sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==} @@ -15291,6 +15297,8 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + libphonenumber-js@1.12.24: {} + light-my-request@5.14.0: dependencies: cookie: 0.7.2