feat(tradein/ui): Telegram feedback button in Topbar (env-gated) (#2514)
All checks were successful
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / build-frontend (push) Successful in 2m1s
Deploy Trade-In / deploy (push) Successful in 47s
All checks were successful
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / build-frontend (push) Successful in 2m1s
Deploy Trade-In / deploy (push) Successful in 47s
Env-gated Telegram feedback button next to UserMenu; renders only when NEXT_PUBLIC_FEEDBACK_TG_URL is set. safeUrl() sanitized, outside RBAC nav.
This commit is contained in:
parent
987dce11bc
commit
749c96cd0c
1 changed files with 56 additions and 0 deletions
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue