/** * Shared HTML builder for contact links (phone, Telegram) used by day detail, * current duty, and duty list. */ import { t } from "./i18n.js"; import { escapeHtml } from "./utils.js"; /** Phone icon SVG for block layout (inline, same style as dutyList). */ const ICON_PHONE = ''; /** Telegram / send icon SVG for block layout. */ const ICON_TELEGRAM = ''; /** * Format Russian phone number for display: 79146522209 -> +7 914 652-22-09. * Accepts 10 digits (9XXXXXXXXX), 11 digits (79XXXXXXXXX or 89XXXXXXXXX). * Other lengths are returned as-is (digits only). * * @param {string} phone - Raw phone string (digits, optional leading 7/8) * @returns {string} Formatted display string, e.g. "+7 914 652-22-09" */ export function formatPhoneDisplay(phone) { if (phone == null || String(phone).trim() === "") return ""; const digits = String(phone).replace(/\D/g, ""); if (digits.length === 10) { return "+7 " + digits.slice(0, 3) + " " + digits.slice(3, 6) + "-" + digits.slice(6, 8) + "-" + digits.slice(8); } if (digits.length === 11 && (digits[0] === "7" || digits[0] === "8")) { const rest = digits.slice(1); return "+7 " + rest.slice(0, 3) + " " + rest.slice(3, 6) + "-" + rest.slice(6, 8) + "-" + rest.slice(8); } return digits; } /** * Build HTML for contact links (phone, Telegram username). * Validates phone/username, builds tel: and t.me hrefs, wraps in spans/links. * * @param {'ru'|'en'} lang - UI language for labels (when showLabels is true) * @param {string|null|undefined} phone - Phone number * @param {string|null|undefined} username - Telegram username with or without leading @ * @param {object} options - Rendering options * @param {string} options.classPrefix - CSS class prefix (e.g. "day-detail-contact", "duty-contact") * @param {boolean} [options.showLabels=true] - Whether to show "Phone:" / "Telegram:" labels (ignored when layout is "block") * @param {string} [options.separator=' '] - Separator between contact parts (e.g. " ", " ยท ") * @param {'inline'|'block'} [options.layout='inline'] - "block" = full-width button blocks with SVG icons (for current duty card) * @returns {string} HTML string or "" if no valid contact */ export function buildContactLinksHtml(lang, phone, username, options) { const { classPrefix, showLabels = true, separator = " ", layout = "inline" } = options || {}; const parts = []; if (phone && String(phone).trim()) { const p = String(phone).trim(); const safeHref = "tel:" + p.replace(/&/g, "&").replace(/"/g, """).replace(/' + ICON_PHONE + "" + escapeHtml(displayPhone) + "" ); } else { const linkHtml = '' + escapeHtml(displayPhone) + ""; if (showLabels) { const label = t(lang, "contact.phone"); parts.push( '' + escapeHtml(label) + ": " + linkHtml + "" ); } else { parts.push(linkHtml); } } } if (username && String(username).trim()) { const u = String(username).trim().replace(/^@+/, ""); if (u) { const display = "@" + u; const href = "https://t.me/" + encodeURIComponent(u); if (layout === "block") { const blockClass = classPrefix + "-block " + classPrefix + "-block--telegram"; parts.push( '' + ICON_TELEGRAM + "" + escapeHtml(display) + "" ); } else { const linkHtml = '' + escapeHtml(display) + ""; if (showLabels) { const label = t(lang, "contact.telegram"); parts.push( '' + escapeHtml(label) + ": " + linkHtml + "" ); } else { parts.push(linkHtml); } } } } if (parts.length === 0) return ""; const rowClass = classPrefix + "-row" + (layout === "block" ? " " + classPrefix + "-row--blocks" : ""); const inner = layout === "block" ? parts.join("") : parts.join(separator); return '
' + inner + "
"; }