feat(tradein/ui): Telegram feedback button in Topbar (env-gated)
All checks were successful
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m8s
CI / changes (pull_request) Successful in 8s
CI Trade-In / changes (pull_request) Successful in 9s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped

This commit is contained in:
bot-backend 2026-07-13 22:34:01 +03:00
parent 987dce11bc
commit 104681eabd

View file

@ -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 (
<svg
width={16}
height={16}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={1.5}
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="m22 2-7 20-4-9-9-4Z" />
<path d="M22 2 11 13" />
</svg>
);
}
/**
* Кнопка обратной связи в 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 (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className="top-cta"
aria-label="Обратная связь в Telegram"
>
<TelegramIcon />
Обратная связь
</a>
);
}
/** «Мера» mark буква М над размерной линией («мера» = измерение).
Глиф в currentColor; тёмный фон даёт CSS-бейдж .brand-mark. */
function MeraMark() {
@ -156,6 +208,10 @@ export function Topbar({ active }: TopbarProps) {
{/* UserMenu личный кабинет справа от nav. В dev (401) или до /me
UserMenu сам рендерит null. */}
<UserMenu />
{/* FeedbackButton вне items.map/RBAC: видна всем авторизованным
пользователям независимо от allowed_paths. Сама себя прячет,
пока NEXT_PUBLIC_FEEDBACK_TG_URL не задан. */}
<FeedbackButton />
</nav>
</div>
</header>