+
-
+
);
}
diff --git a/src/landing/i18n/locales/en.json b/src/landing/i18n/locales/en.json
index 1e3e85f..823a2a0 100644
--- a/src/landing/i18n/locales/en.json
+++ b/src/landing/i18n/locales/en.json
@@ -63,10 +63,13 @@
"consentBefore": "*By submitting, you give",
"consentLinkData": "consent to personal data processing",
"consentMiddle": "and accept the",
- "consentLinkPolicy": "policy terms"
+ "consentLinkPolicy": "policy terms",
+ "phonePlaceholder": "+XXXXXXXXXXXXXXX",
+ "phoneRequired": "Enter your phone number",
+ "phoneInvalid": "Enter a valid phone number"
},
"questionModal": {
- "phonePlaceholder": "+X (XXX) XXX - XX - XX"
+ "phonePlaceholder": "+XXXXXXXXXXXXXXX"
},
"feedbackModal": {
"successRich": "We’ve received your request
and we’ll contact you
soon!",
diff --git a/src/landing/i18n/locales/ru.json b/src/landing/i18n/locales/ru.json
index 7aa62b3..e78c4e0 100644
--- a/src/landing/i18n/locales/ru.json
+++ b/src/landing/i18n/locales/ru.json
@@ -63,10 +63,13 @@
"consentBefore": "*Нажимая кнопку отправить, вы даете",
"consentLinkData": "согласие на обработку персональных данных",
"consentMiddle": "и принимаете",
- "consentLinkPolicy": "условия политики"
+ "consentLinkPolicy": "условия политики",
+ "phonePlaceholder": "+7 (XXX) XXX-XX-XX",
+ "phoneRequired": "Укажите номер телефона",
+ "phoneInvalid": "Введите корректный номер телефона"
},
"questionModal": {
- "phonePlaceholder": "+X (XXX) XXX - XX - XX"
+ "phonePlaceholder": "+7 (XXX) XXX-XX-XX"
},
"feedbackModal": {
"successRich": "Мы получили заявку
и скоро свяжемся
с вами!",
diff --git a/src/landing/lib/phoneIntl.ts b/src/landing/lib/phoneIntl.ts
new file mode 100644
index 0000000..9d5cbbd
--- /dev/null
+++ b/src/landing/lib/phoneIntl.ts
@@ -0,0 +1,24 @@
+/** Максимум значащих цифр в международном номере (E.164). */
+export const INTL_PHONE_MAX_DIGITS = 15;
+
+/** Нормализация: «+» и только цифры после него (до 15), без пробелов и прочего. */
+export function normalizeIntlPhoneFromInput(rawNoSpaces: string): string {
+ if (!rawNoSpaces) return "";
+ const v = rawNoSpaces.trim();
+ const plusIdx = v.indexOf("+");
+ if (plusIdx === -1) {
+ const digitsOnly = v.replace(/\D/g, "").slice(0, INTL_PHONE_MAX_DIGITS);
+ return digitsOnly ? `+${digitsOnly}` : "";
+ }
+ const afterPlus = v
+ .slice(plusIdx + 1)
+ .replace(/\D/g, "")
+ .slice(0, INTL_PHONE_MAX_DIGITS);
+ if (!afterPlus) return "+";
+ return `+${afterPlus}`;
+}
+
+/** Отображение: «+» и цифры подряд, без пробелов. */
+export function formatIntlPhoneDisplay(stored: string): string {
+ return normalizeIntlPhoneFromInput(stored.replace(/\s/g, ""));
+}
diff --git a/src/landing/ui/PhoneInputIntl.tsx b/src/landing/ui/PhoneInputIntl.tsx
new file mode 100644
index 0000000..6b55b3d
--- /dev/null
+++ b/src/landing/ui/PhoneInputIntl.tsx
@@ -0,0 +1,45 @@
+import { type Ref } from "react";
+import {
+ formatIntlPhoneDisplay,
+ normalizeIntlPhoneFromInput,
+} from "@/landing/lib/phoneIntl";
+
+const inputClassName =
+ "placeholder:btnl placeholder:font-medium placeholder:select-none peer btnl w-full h-full bg-transparent rounded-none transition-all outline-none";
+
+interface PhoneInputIntlProps {
+ value: string;
+ onChange: (value: string) => void;
+ onBlur?: () => void;
+ inputRef?: Ref
;
+ id?: string;
+ placeholder?: string;
+}
+
+export function PhoneInputIntl({
+ value,
+ onChange,
+ onBlur,
+ inputRef,
+ id = "tel",
+ placeholder = "+123456789012345",
+}: PhoneInputIntlProps) {
+ return (
+ {
+ if (!e.nativeEvent.type.startsWith("input")) return;
+ const cleanValue = e.target.value.replace(/\s/g, "");
+ onChange(normalizeIntlPhoneFromInput(cleanValue));
+ }}
+ />
+ );
+}