feat(tradein/ui): admin links to audit + analytics in UserMenu
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 7s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m1s
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-14 00:13:05 +03:00
parent c61ed5a96e
commit 76070cea83

View file

@ -19,8 +19,10 @@
* покажется заново.
*/
import type { CSSProperties } from "react";
import { useEffect, useRef, useState } from "react";
import { API_BASE_URL } from "@/lib/api";
import { logout } from "@/lib/logout";
import { useMe } from "@/lib/useMe";
@ -46,6 +48,69 @@ function LogOutIcon() {
);
}
/** Inline Shield icon (lucide-react `Shield` SVG path, stroke 1.5) для
admin-ссылки «Аудит доступа». Та же inline-SVG конвенция, что LogOutIcon
(tradein-mvp не тянет lucide-react в deps). */
function ShieldIcon() {
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="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" />
</svg>
);
}
/** Inline BarChart icon (lucide-react `BarChart3` SVG path, stroke 1.5)
для admin-ссылки «Активность». */
function BarChartIcon() {
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="M3 3v16a2 2 0 0 0 2 2h16" />
<path d="M18 17V9" />
<path d="M13 17V5" />
<path d="M8 17v-3" />
</svg>
);
}
/** Общий inline-стиль для admin-nav-пунктов дропдауна (Аудит/Активность)
тот же паттерн, что «Выйти», но нейтральный цвет вместо var(--danger). */
const adminMenuItemStyle: CSSProperties = {
display: "flex",
alignItems: "center",
gap: 8,
width: "100%",
background: "none",
border: "none",
padding: "4px 0",
cursor: "pointer",
color: "var(--fg-primary)",
fontWeight: 500,
fontSize: 14,
textAlign: "left",
fontFamily: "inherit",
textDecoration: "none",
};
export function UserMenu() {
const { data, isLoading, error } = useMe();
const [open, setOpen] = useState(false);
@ -159,6 +224,35 @@ export function UserMenu() {
>
{roleLabel}
</div>
{data.role === "admin" && (
<>
<hr
style={{
margin: "12px 0",
border: "none",
borderTop: "1px solid var(--border-soft)",
}}
/>
<a
role="menuitem"
href={`${API_BASE_URL}/admin/audit`}
onClick={() => setOpen(false)}
style={adminMenuItemStyle}
>
<ShieldIcon />
Аудит доступа
</a>
<a
role="menuitem"
href={`${API_BASE_URL}/admin/analytics`}
onClick={() => setOpen(false)}
style={{ ...adminMenuItemStyle, marginTop: 4 }}
>
<BarChartIcon />
Активность
</a>
</>
)}
<hr
style={{
margin: "12px 0",