mirror of
https://github.com/wasrusgen/zov-tech.git
synced 2026-06-03 17:44:48 +00:00
miniapp: phone validation on intro — blocks transition with bad number
- New isValidPhone(raw): checks 11-digit Russian after normalization (8/7/+7/9-prefix) - Intro 'Начать' button now custom click handler instead of data-go - Validates name (non-empty) and phone (Russian format) - Inline .field-error red message under invalid field - .field-hint shows format help under phone input - Haptic 'warning' feedback on invalid submit - Phone is auto-normalized to '+7 900 123-45-67' before transition
This commit is contained in:
parent
0f2635d5f8
commit
5ceffa4f69
@ -148,6 +148,27 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ----- Form errors / hints ----- */
|
||||
.field-error {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.02em;
|
||||
color: #8A3E2A;
|
||||
min-height: 14px;
|
||||
margin-top: 4px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.field-error:empty { display: none; }
|
||||
|
||||
.field-hint {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.04em;
|
||||
color: var(--muted);
|
||||
margin-top: 4px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
/* ----- Form basics ----- */
|
||||
.field {
|
||||
display: flex;
|
||||
|
||||
@ -178,22 +178,74 @@ const Podbor = (function () {
|
||||
<label class="field">
|
||||
<span class="field-label">Клиент</span>
|
||||
<input type="text" data-bind="client_name" value="${state.client_name || ""}" placeholder="Например: А. Пестова">
|
||||
<span class="field-error" id="nameError"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label class="field">
|
||||
<span class="field-label">Телефон</span>
|
||||
<input type="tel" data-bind="client_phone" value="${state.client_phone || ""}" placeholder="+7 ...">
|
||||
<input type="tel" data-bind="client_phone" value="${state.client_phone || ""}" placeholder="+7 900 123-45-67">
|
||||
<span class="field-hint">Формат: +7, 8, или 10 цифр начиная с 9</span>
|
||||
<span class="field-error" id="phoneError"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="podbor-cta-row">
|
||||
<button class="btn-primary" data-go="categories">Начать</button>
|
||||
<button class="btn-primary" id="introNext">Начать</button>
|
||||
</div>
|
||||
</section>
|
||||
`);
|
||||
bindInputs(node);
|
||||
bindNav(node);
|
||||
|
||||
const phoneInput = node.querySelector("input[data-bind='client_phone']");
|
||||
const phoneError = node.querySelector("#phoneError");
|
||||
const nameInput = node.querySelector("input[data-bind='client_name']");
|
||||
const nameError = node.querySelector("#nameError");
|
||||
|
||||
// Валидация на blur — мягкие подсказки
|
||||
phoneInput.addEventListener("blur", () => {
|
||||
const v = phoneInput.value.trim();
|
||||
if (v && !isValidPhone(v)) {
|
||||
phoneError.textContent = "Похоже на неполный номер. Нужно 11 цифр (или 10 с цифры 9)";
|
||||
} else {
|
||||
phoneError.textContent = "";
|
||||
}
|
||||
});
|
||||
|
||||
node.querySelector("#introNext").addEventListener("click", () => {
|
||||
// Имя
|
||||
const name = (state.client_name || "").trim();
|
||||
if (!name) {
|
||||
nameError.textContent = "Укажите имя клиента";
|
||||
nameInput.focus();
|
||||
haptic && haptic("warning");
|
||||
return;
|
||||
} else {
|
||||
nameError.textContent = "";
|
||||
}
|
||||
|
||||
// Телефон
|
||||
const phone = (state.client_phone || "").trim();
|
||||
if (!phone) {
|
||||
phoneError.textContent = "Укажите телефон клиента";
|
||||
phoneInput.focus();
|
||||
haptic && haptic("warning");
|
||||
return;
|
||||
}
|
||||
if (!isValidPhone(phone)) {
|
||||
phoneError.textContent = "Неверный формат. Пример: +7 900 123-45-67 или 89001234567";
|
||||
phoneInput.focus();
|
||||
haptic && haptic("warning");
|
||||
return;
|
||||
}
|
||||
// Нормализуем перед переходом
|
||||
const normalized = normalizePhone(phone);
|
||||
if (normalized !== phone) {
|
||||
update({ client_phone: normalized });
|
||||
}
|
||||
go("categories");
|
||||
});
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -1539,6 +1591,15 @@ const Podbor = (function () {
|
||||
return `+7 ${d.slice(1, 4)} ${d.slice(4, 7)}-${d.slice(7, 9)}-${d.slice(9, 11)}`;
|
||||
}
|
||||
|
||||
/* Проверка: получится ли валидный РФ-номер из введённого. */
|
||||
function isValidPhone(raw) {
|
||||
if (!raw) return false;
|
||||
let d = raw.replace(/\D/g, "");
|
||||
if (d.length === 11 && d.startsWith("8")) d = "7" + d.slice(1);
|
||||
if (d.length === 10 && d.startsWith("9")) d = "7" + d;
|
||||
return d.length === 11 && d.startsWith("7");
|
||||
}
|
||||
|
||||
function bindNav(node) {
|
||||
node.querySelectorAll("[data-go]").forEach(b => {
|
||||
b.addEventListener("click", () => go(b.dataset.go));
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Geist:wght@400;500;600&family=Newsreader:ital,wght@0,400..600;1,400..600&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&display=swap">
|
||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||
<link rel="stylesheet" href="assets/styles.css?v=20260511i">
|
||||
<link rel="stylesheet" href="assets/podbor.css?v=20260511i">
|
||||
<link rel="stylesheet" href="assets/styles.css?v=20260511j">
|
||||
<link rel="stylesheet" href="assets/podbor.css?v=20260511j">
|
||||
</head>
|
||||
<body>
|
||||
<main id="app">
|
||||
@ -21,10 +21,10 @@
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</main>
|
||||
<script src="assets/icons.js?v=20260511i"></script>
|
||||
<script src="assets/podbor.config.js?v=20260511i"></script>
|
||||
<script src="assets/podbor.picts.js?v=20260511i"></script>
|
||||
<script src="assets/podbor.js?v=20260511i"></script>
|
||||
<script src="assets/app.js?v=20260511i"></script>
|
||||
<script src="assets/icons.js?v=20260511j"></script>
|
||||
<script src="assets/podbor.config.js?v=20260511j"></script>
|
||||
<script src="assets/podbor.picts.js?v=20260511j"></script>
|
||||
<script src="assets/podbor.js?v=20260511j"></script>
|
||||
<script src="assets/app.js?v=20260511j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user