import { Inbox, X } from "lucide-react"; import { useMemo, useState } from "react"; import { createPortal } from "react-dom"; import type { Client } from "../../entities/client/types"; import { PUBLIC_POOL_CLIENT, isPublicPoolClientId } from "../../entities/public-pool/constants"; import type { MeResponse, ProfileOption } from "../../shared/api/mockApi"; import { initials } from "../../shared/lib/format"; import { NodeDcProfileMenu, NodeDcSelect } from "../../shared/nodedc-ui"; export type LauncherAdminMode = "admin" | "platform"; export type LauncherNotificationKind = "nodedc" | "operational-core" | "engine"; export type LauncherNotificationStatus = "new" | "approved" | "rejected" | "cancelled"; export interface LauncherNotificationItem { id: string; kind: LauncherNotificationKind; title: string; description: string; meta?: string; status: LauncherNotificationStatus; createdAt: string; } export function TopBar({ me, clients, profileOptions, activeProfileId, activeClientId, adminOpen, adminMode, onProfileChange, onClientChange, onOpenAdmin, onOpenPlatform, onOpenShowcase, onOpenProfileSettings, onLogout, brandLinkUrl = "/", notifications = [], }: { me: MeResponse; clients: Client[]; profileOptions: ProfileOption[]; activeProfileId: string; activeClientId: string; adminOpen: boolean; adminMode: LauncherAdminMode; onProfileChange: (userId: string) => void; onClientChange: (clientId: string) => void; onOpenAdmin: () => void; onOpenPlatform: () => void; onOpenShowcase: () => void; onOpenProfileSettings: () => void; onLogout?: () => void; brandLinkUrl?: string; notifications?: LauncherNotificationItem[]; }) { const [notificationsOpen, setNotificationsOpen] = useState(false); const [notificationFilter, setNotificationFilter] = useState("all"); const availableClientIds = new Set(me.memberships.map((membership) => membership.clientId)); const clientsWithPublicPool = [ ...clients, availableClientIds.has(PUBLIC_POOL_CLIENT.id) && !clients.some((client) => isPublicPoolClientId(client.id)) ? PUBLIC_POOL_CLIENT : null, ].filter((client): client is Client => Boolean(client)); const availableClients = clientsWithPublicPool.filter((client) => availableClientIds.has(client.id)); const activeClient = availableClients.find((client) => client.id === activeClientId); const clientOptions = availableClients.map((client) => ({ value: client.id, label: client.name, description: client.legalName ?? undefined, })); const canOpenPlatform = me.launcherRole === "root_admin"; const showLauncherNavigation = me.permissions.canOpenAdmin || canOpenPlatform; const unreadCount = notifications.filter((notification) => notification.status === "new").length; const visibleNotifications = useMemo( () => notifications.filter((notification) => notificationFilter === "all" || notification.kind === notificationFilter), [notificationFilter, notifications] ); const notificationsModal = notificationsOpen && typeof document !== "undefined" ? createPortal(
setNotificationsOpen(false)}>
event.stopPropagation()}>

Уведомления

NODE DC
setNotificationFilter("all")}> Все setNotificationFilter("nodedc")}> NODE.DC setNotificationFilter("operational-core")}> Operational Core setNotificationFilter("engine")}> Engine
{visibleNotifications.length === 0 ? (
Новых входящих нет Заявки NODE.DC, Operational Core и Engine появятся здесь.
) : ( visibleNotifications.map((notification) => (
{notificationKindLabel(notification.kind)}
{notification.title}
{notification.description}
{notificationStatusLabel(notification.status)} {notification.meta ? {notification.meta} : null}
)) )}
, document.body ) : null; return (
NODE DC
{showLauncherNavigation ? ( <> onClientChange(clientId)} trigger={({ open, toggle, setTriggerRef }) => ( )} /> ) : null}
(
{ if (event.key === "Enter" || event.key === " ") { event.preventDefault(); toggle(); } }} > Профиль
)} />
{notificationsModal}
); } function NotificationFilterButton({ active, children, onClick, }: { active: boolean; children: string; onClick: () => void; }) { return ( ); } function notificationKindLabel(kind: LauncherNotificationKind): string { const labels: Record = { nodedc: "NODE.DC", "operational-core": "Operational Core", engine: "NODE.DC Engine", }; return labels[kind]; } function notificationStatusLabel(status: LauncherNotificationStatus): string { const labels: Record = { new: "Входящее", approved: "Подтверждено", rejected: "Отклонено", cancelled: "Отменено", }; return labels[status]; }