Files
portal/app/resources/js/utils/leadDate.ts
T
Дмитрий 929bf9f45b fix интерфейс: время везде показывается по Москве, а не по часам браузера
Считать портал уже научился по московским суткам. Показывал он вразнобой:
часть страниц просила браузер явно про Москву, двадцать мест оставляли пояс
на его усмотрение. Человек за пределами Москвы видел у заявки не тот день,
что в отчёте, — при том что фильтры и отчёты считают московские сутки.

Двадцать мест поправлены: заявки, счета, проводки, сессии и смена пароля,
происшествия, запросы субъектов ПДн, ступени цен, интеграция с поставщиком,
проекты поставщика, система, посетители, вход под клиентом, кампании,
поле автоподбора, СМС и прогрев у отдела продаж, карточка клиента.

Одно место оставлено гринвичским НАМЕРЕННО и с объяснением рядом:
firstLeadDate собирает дату из уже московских чисел через Date.UTC, и
повторный перевод сдвинул бы день назад.

Сторож tools/storozh-moskovskogo-vremeni.mjs держит правило дальше: любая
печать времени обязана НАЗВАТЬ пояс. Он отличает время от денег - тот же
вызов toLocaleString печатает и суммы, им пояс не нужен. Приёмка вырезанием
в обе стороны: до правки сторож нашёл ровно 20 мест, после - ноль при 303
проверенных файлах; на пустой папке честно говорит "датчик сломан", а не "чисто".
Своих проверок у сторожа десять, написаны до него.

Прогон интерфейса: 232 файла проверок, 1743 зелёных, 0 падений.
Проверка типов и разметка: 7 замечаний, все были ДО правки и не в моих файлах
(проверено прятанием своих правок и повторным прогоном).

Заодно выметен мусор в корне: файлы с именами 1', 140, 2771, 3042, 3404,
out.txt и app/toArray-скобки - обрывки чужих незакавыченных перенаправлений.

Заодно убрана мёртвая функция dirLabel в экране автоподбора: её никто не звал,
она была там до этой правки, и линтер из-за неё не пропускал весь файл.
Решение владельца. Прогон экрана: 15 файлов проверок, 84 зелёных.
2026-08-02 11:09:51 +03:00

30 lines
1.9 KiB
TypeScript

/**
* Форматирование дат для UI блокировки источника и баннера нового проекта.
* Спека: docs/superpowers/specs/2026-06-22-project-source-edit-lock-ux-design.md.
*/
/** ISO-строку → «23 июня» (ru). Пусто/невалид → ''. */
export function formatLeadDate(iso: string | null | undefined): string {
if (!iso) return '';
const d = new Date(iso);
if (Number.isNaN(d.getTime())) return '';
// По Москве, а не по часам браузера: у заявки, пришедшей в 00:30 МСК,
// человек из другого пояса иначе увидит вчерашнее число.
return new Intl.DateTimeFormat('ru-RU', { day: 'numeric', month: 'long', timeZone: 'Europe/Moscow' }).format(d);
}
/**
* Дата старта лидов нового проекта по правилу слепка 18:00 МСК:
* создал до 18:00 МСК → лиды с завтра; после 18:00 → с послезавтра.
* РФ круглый год UTC+3 (без перехода на летнее время).
*/
export function firstLeadDate(now: Date = new Date()): string {
const msk = new Date(now.getTime() + 3 * 3600 * 1000);
const addDays = msk.getUTCHours() >= 18 ? 2 : 1;
const target = new Date(Date.UTC(msk.getUTCFullYear(), msk.getUTCMonth(), msk.getUTCDate() + addDays));
// Здесь Гринвич выбран осознанно, а не забыт: `target` собран из готовых
// московских чисел через Date.UTC — это уже календарная дата, и переводить
// её ещё раз в Москву значило бы сдвинуть день назад.
return new Intl.DateTimeFormat('ru-RU', { day: 'numeric', month: 'long', timeZone: 'UTC' }).format(target);
}