diff --git a/src/food-market.api/Controllers/AuthSignupController.cs b/src/food-market.api/Controllers/AuthSignupController.cs index b9880e6..4a0f67e 100644 --- a/src/food-market.api/Controllers/AuthSignupController.cs +++ b/src/food-market.api/Controllers/AuthSignupController.cs @@ -28,9 +28,22 @@ public AuthSignupController(AppDbContext db, UserManager userMgr) _db = db; _userMgr = userMgr; } - public record SignupInput(string Email, string Password, string OrganizationName, string? Phone, string? Plan); + public record SignupInput(string Email, string Password, string OrganizationName, string Phone, string? Plan); public record SignupResult(Guid OrganizationId, string Email); + /// Нормализация и проверка телефона Казахстана. Принимаем любое + /// форматирование (пробелы, скобки, +, дефисы), оставляем только цифры, + /// ведущая «8» переписывается в «7». Валидно: ровно 11 цифр, начинается + /// с «77» — мобильный код KZ. «79…» (РФ) и прочие отвергаем. + private static string? NormalizeKzPhone(string? raw) + { + if (string.IsNullOrWhiteSpace(raw)) return null; + var digits = new string(raw.Where(char.IsDigit).ToArray()); + if (digits.Length == 11 && digits[0] == '8') digits = "7" + digits[1..]; + if (digits.Length != 11 || !digits.StartsWith("77")) return null; + return "+" + digits; + } + [HttpPost("signup")] public async Task> Signup([FromBody] SignupInput input, CancellationToken ct) { @@ -39,6 +52,9 @@ public async Task> Signup([FromBody] SignupInput inpu return BadRequest(new { error = "Email, пароль и название обязательны." }); if (input.Password.Length < 8) return BadRequest(new { error = "Пароль минимум 8 символов." }); + var normalizedPhone = NormalizeKzPhone(input.Phone); + if (normalizedPhone is null) + return BadRequest(new { error = "Введите корректный номер Казахстана. Пример: +7 700 123 45 67" }); var existing = await _userMgr.FindByEmailAsync(input.Email); if (existing is not null) @@ -63,7 +79,7 @@ public async Task> Signup([FromBody] SignupInput inpu Name = input.OrganizationName.Trim(), CountryCode = "KZ", DefaultCurrencyId = kzt?.Id, - Phone = string.IsNullOrWhiteSpace(input.Phone) ? null : input.Phone.Trim(), + Phone = normalizedPhone, Email = input.Email.Trim(), }; _db.Organizations.Add(org); diff --git a/src/food-market.public/src/components/SignupForm.tsx b/src/food-market.public/src/components/SignupForm.tsx index c7c6104..610c5e0 100644 --- a/src/food-market.public/src/components/SignupForm.tsx +++ b/src/food-market.public/src/components/SignupForm.tsx @@ -92,8 +92,9 @@ export default function SignupForm({ defaultPlan = 'start' }: Props) { setOrgName(e.target.value)} placeholder="Наименование организации" className={inputCls(!!fieldErrors.orgName)} /> - + setPhone(e.target.value)} + required autoComplete="tel" inputMode="tel" placeholder="+7 700 123 45 67" className={inputCls(!!fieldErrors.phone)} />
diff --git a/src/food-market.public/src/lib/validation.ts b/src/food-market.public/src/lib/validation.ts index c243a7d..25bd8d8 100644 --- a/src/food-market.public/src/lib/validation.ts +++ b/src/food-market.public/src/lib/validation.ts @@ -30,10 +30,13 @@ export function validatePassword(value: string): string | null { } export function validatePhone(value: string): string | null { - if (!value) return null // optional - // +7 700 123 45 67 в любом форматировании, либо 8… - const digits = value.replace(/\D/g, '') - if (!/^[78]\d{10}$/.test(digits)) return 'Введите корректный телефон. Пример: +7 700 123 45 67' + if (!value || value.trim() === '') return 'Телефон обязателен для заполнения' + // Казахстан: +7 7XX XXX XX XX (мобильные коды KZ начинаются с 77, + // 79 — это РФ, исключаем). Принимаем любое форматирование (пробелы, + // скобки, дефисы), нормализуем к 11 цифрам, ведущая «8» = «7». + let digits = value.replace(/\D/g, '') + if (digits.length === 11 && digits.startsWith('8')) digits = '7' + digits.slice(1) + if (!/^77\d{9}$/.test(digits)) return 'Введите корректный номер Казахстана. Пример: +7 700 123 45 67' return null }