From 749c96cd0c13bc536b0e04468d2dcaba7229058c Mon Sep 17 00:00:00 2001 From: lekss361 Date: Mon, 13 Jul 2026 19:44:00 +0000 Subject: [PATCH] feat(tradein/ui): Telegram feedback button in Topbar (env-gated) (#2514) Env-gated Telegram feedback button next to UserMenu; renders only when NEXT_PUBLIC_FEEDBACK_TG_URL is set. safeUrl() sanitized, outside RBAC nav. --- .../src/components/trade-in/Topbar.tsx | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tradein-mvp/frontend/src/components/trade-in/Topbar.tsx b/tradein-mvp/frontend/src/components/trade-in/Topbar.tsx index 3c716ef7..d1e9628d 100644 --- a/tradein-mvp/frontend/src/components/trade-in/Topbar.tsx +++ b/tradein-mvp/frontend/src/components/trade-in/Topbar.tsx @@ -9,6 +9,58 @@ import { safeUrl } from "@/lib/safeUrl"; import { useBrand } from "@/lib/useBrand"; import { useMe } from "@/lib/useMe"; +/** Telegram-канал обратной связи для пилота. Build-time env — пусто до тех + пор, пока devops не настроит реальную ссылку (см. FeedbackButton ниже). */ +const FEEDBACK_TG_URL = process.env.NEXT_PUBLIC_FEEDBACK_TG_URL ?? ""; + +/** Inline Send icon (lucide-react `Send` SVG path, stroke 1.5) — та же + конвенция, что и LogOutIcon в UserMenu.tsx: tradein-mvp не тянет + lucide-react в deps, поэтому иконка — inline SVG. */ +function TelegramIcon() { + return ( + + ); +} + +/** + * Кнопка обратной связи в Telegram — рендерится для ВСЕХ авторизованных + * пользователей (не зависит от RBAC allowed_paths, в отличие от NAV_ITEMS). + * + * Env-gated: пока `NEXT_PUBLIC_FEEDBACK_TG_URL` не задан на билде, кнопка не + * рендерится вообще — безопасно шипить до появления реальной Telegram-ссылки. + * safeUrl() дополнительно блокирует не-http(s) схемы (#766-class XSS). + */ +function FeedbackButton() { + const href = safeUrl(FEEDBACK_TG_URL); + if (!href) return null; + + return ( + + + Обратная связь + + ); +} + /** «Мера» mark — буква М над размерной линией («мера» = измерение). Глиф в currentColor; тёмный фон даёт CSS-бейдж .brand-mark. */ function MeraMark() { @@ -156,6 +208,10 @@ export function Topbar({ active }: TopbarProps) { {/* UserMenu — личный кабинет справа от nav. В dev (401) или до /me UserMenu сам рендерит null. */} + {/* FeedbackButton — вне items.map/RBAC: видна всем авторизованным + пользователям независимо от allowed_paths. Сама себя прячет, + пока NEXT_PUBLIC_FEEDBACK_TG_URL не задан. */} +