export const ROSREESTR_REQUEST_URL = "https://rosreestr.gov.ru/eservices/request_info_from_egrn/"; const ROMAN_QUARTER = ["I", "II", "III", "IV"] as const; /** * #2846: «по I кв. 2026» — до какого момента доходят ПОКАЗАННЫЕ ДКП-сделки. * * Гранулярность — квартал, и это не округление ради красоты: Росреестр * публикует ДКП пачками, deal_date = первый день квартала (бэкенд помечает это * `date_precision: "quarter"`, #1995). Прод-замер 2026-08-12: 96 974 сделки, * 9 различных deal_date, day-of-month = 1 у 100%, месяцы ровно {01,04,07,10}. * Поэтому «223 дня назад» было бы ложной точностью в сторону состаривания: * сделка из пачки «2026-01-01» могла случиться и 31 марта. «по I кв. 2026» — * ровно то, что известно, и ни бита сверх. * * «по» (а не «за») намеренно: выборка обычно накрывает несколько кварталов, * и подпись называет ВЕРХНЮЮ границу свежести, а не период целиком. * * @param iso ISO-дата свежайшей сделки ВЫБОРКИ (не всей таблицы). * @param precision 'day' у источника с настоящей датой; иначе квартал. * @returns null, если датировать нечего — подпись тогда не рисуется вовсе. */ export function dealsAsOfLabel( iso: string | null | undefined, precision?: "day" | "quarter" | null, ): string | null { if (!iso) return null; const d = new Date(iso); if (Number.isNaN(d.getTime())) return null; // ISO date-only ("2026-01-01") парсится как UTC-полночь — читаем UTC-поля, // иначе в отрицательных зонах квартал уезжает на предыдущий. if (precision === "day") { return `по ${String(d.getUTCMonth() + 1).padStart(2, "0")}.${d.getUTCFullYear()}`; } return `по ${ROMAN_QUARTER[Math.floor(d.getUTCMonth() / 3)]} кв. ${d.getUTCFullYear()}`; } export async function openRosreestrWithAddress(address: string): Promise { try { await navigator.clipboard.writeText(address); } catch { // clipboard may be unavailable — open form anyway } window.open(ROSREESTR_REQUEST_URL, "_blank", "noopener,noreferrer"); }