From 6510ccafb5f5a510df07f3232025a26b8e3587e0 Mon Sep 17 00:00:00 2001 From: nns Date: Mon, 12 Oct 2026 22:10:20 +0500 Subject: [PATCH] =?UTF-8?q?fix(=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F):=20=D0=B2=D1=81=D1=82=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=82=D0=B5=D0=BB=D0=B5=D1=84=D0=BE=D0=BD=D0=B0?= =?UTF-8?q?=20+=203=20=D0=BC=D0=B5=D0=BB=D0=BE=D1=87=D0=B8=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=20?= =?UTF-8?q?(12.10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Маска телефона: onBeforeInput больше не блокирует ВСТАВКУ. Раньше он отменял любой ввод с не-цифрами в data, из-за чего вставка «+7 701…» / «8 (701) 000-00-00» через CDP insertText блокировалась целиком и номер пропадал («+7 »). Теперь блокируется только одиночный набранный не-цифровой символ; вставку нормализует handleChange. Обе копии (public + admin). Проверено в реальном Chromium (Playwright): посимвольный ввод (delay 0 и 20), все варианты вставки и Backspace посреди номера → «+7 701 000 00 00». 1. Мастер «Первые шаги», шаг каталога: число товаров с разделителем разрядов и склонением («30 951 товар»); текст исправлен — закупочная и себестоимость приходят из реестра вместе с товаром, оставлено «Проверьте продажные цены — они взяты из реестра». 2. Прибыль на главной: убрана фраза про «переход на FIFO» (внутренняя кухня); оставлено «Прибыль приблизительная — по текущей себестоимости из карточек». Co-Authored-By: Claude Opus 4.8 --- .../src/components/PhoneInput.tsx | 11 ++++++++++- src/food-market.web/src/components/PhoneInput.tsx | 9 ++++++++- .../src/components/ProfitHomeBlock.tsx | 2 +- src/food-market.web/src/pages/OnboardingPage.tsx | 14 ++++++++++++-- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/food-market.public/src/components/PhoneInput.tsx b/src/food-market.public/src/components/PhoneInput.tsx index eedadc0..6031b3f 100644 --- a/src/food-market.public/src/components/PhoneInput.tsx +++ b/src/food-market.public/src/components/PhoneInput.tsx @@ -72,7 +72,16 @@ export function PhoneInput({ value, onChange, className, disabled, ...rest }: Ph const handleBeforeInput = (e: FormEvent) => { const native = e.nativeEvent as InputEvent - if (native.data && /\D/.test(native.data)) e.preventDefault() + // Блокируем ТОЛЬКО одиночный набранный не-цифровой символ (буква/знак при + // печати). Вставку (insertFromPaste, либо insertText с многосимвольной + // строкой) НЕ трогаем — её очистит и нормализует handleChange, иначе + // вставка «+7 701…» / «8 (701)…» блокировалась целиком и номер пропадал. + if (native.inputType === 'insertText' + && typeof native.data === 'string' + && native.data.length === 1 + && /\D/.test(native.data)) { + e.preventDefault() + } } const handleChange = (e: React.ChangeEvent) => { diff --git a/src/food-market.web/src/components/PhoneInput.tsx b/src/food-market.web/src/components/PhoneInput.tsx index e2a2e59..9933041 100644 --- a/src/food-market.web/src/components/PhoneInput.tsx +++ b/src/food-market.web/src/components/PhoneInput.tsx @@ -99,7 +99,14 @@ export function PhoneInput({ value, onChange, className, disabled, ...rest }: Ph // deleteContentBackward и т.п. — там не вмешиваемся, пусть браузер удаляет. const handleBeforeInput = (e: FormEvent) => { const native = e.nativeEvent as InputEvent - if (native.data && /\D/.test(native.data)) { + // Блокируем ТОЛЬКО одиночный набранный не-цифровой символ. Вставку + // (insertFromPaste или insertText с многосимвольной строкой) пропускаем — + // её нормализует handleChange, иначе вставка «+7 701…» / «8 (701)…» + // блокировалась целиком и номер пропадал. + if (native.inputType === 'insertText' + && typeof native.data === 'string' + && native.data.length === 1 + && /\D/.test(native.data)) { e.preventDefault() } } diff --git a/src/food-market.web/src/components/ProfitHomeBlock.tsx b/src/food-market.web/src/components/ProfitHomeBlock.tsx index 8bae62a..0ae7166 100644 --- a/src/food-market.web/src/components/ProfitHomeBlock.tsx +++ b/src/food-market.web/src/components/ProfitHomeBlock.tsx @@ -46,7 +46,7 @@ export function ProfitHomeBlock() {

- Прибыль приблизительная (по текущей себестоимости из карточек). Точной станет после перехода на FIFO. + Прибыль приблизительная — считается по текущей себестоимости из карточек товаров.

) diff --git a/src/food-market.web/src/pages/OnboardingPage.tsx b/src/food-market.web/src/pages/OnboardingPage.tsx index 24333a0..bbac961 100644 --- a/src/food-market.web/src/pages/OnboardingPage.tsx +++ b/src/food-market.web/src/pages/OnboardingPage.tsx @@ -4,6 +4,16 @@ import { PageHeader } from '@/components/PageHeader' import { useOnboardingProgress } from '@/lib/useOnboardingProgress' import { isOnboardingHidden, setOnboardingHidden } from '@/lib/onboardingPrefs' +/** Русское склонение «товар»: 1 товар, 2–4 товара, 5+ товаров (с учётом 11–14). */ +function pluralProduct(n: number): string { + const mod100 = n % 100 + const mod10 = n % 10 + if (mod100 >= 11 && mod100 <= 14) return 'товаров' + if (mod10 === 1) return 'товар' + if (mod10 >= 2 && mod10 <= 4) return 'товара' + return 'товаров' +} + interface StepCard { done: boolean badge: string @@ -44,8 +54,8 @@ export function OnboardingPage() { ? { done: true, badge: 'Каталог', - title: `Каталог готов: ${p.productCount} товаров из реестра ALL MARKET`, - description: 'Товары скопированы из реестра ALL MARKET. Проверьте продажные цены — закупочные и себестоимость появятся после первой приёмки.', + title: `Каталог готов: ${p.productCount.toLocaleString('ru-RU')} ${pluralProduct(p.productCount)} из реестра ALL MARKET`, + description: 'Товары скопированы из реестра ALL MARKET вместе с закупочной ценой и себестоимостью. Проверьте продажные цены — они взяты из реестра.', ctaLabel: 'Проверить продажные цены', ctaTo: '/catalog/products', icon: Package,