import { ChartBarIcon, CloudIcon, GlobeIcon, LayoutDashboardIcon, ServerIcon, type LucideIcon, } from "lucide-react" import { formatAppVersionLabel, getAppVersion } from "@/lib/app-version" export const CURRENT_APP_ID = "mm" export type AppSwitcherIconName = | "server" | "cloud" | "globe" | "dashboard" | "chart" export type AppSwitcherEntry = { id: string name: string subtitle?: string url: string icon: AppSwitcherIconName shortcut?: string enabled?: boolean } export type AppSwitcherConfig = { menuLabel: string apps: AppSwitcherEntry[] } export const APP_SWITCHER_ICONS: Record = { server: ServerIcon, cloud: CloudIcon, globe: GlobeIcon, dashboard: LayoutDashboardIcon, chart: ChartBarIcon, } function localAppUrl(): string { if (typeof window !== "undefined") return window.location.origin return process.env.NEXT_PUBLIC_APP_URL?.replace(/\/$/, "") || "http://localhost:3000" } export function localMikrotikEntry(): AppSwitcherEntry { return { id: CURRENT_APP_ID, name: "MikrotikManager", subtitle: formatAppVersionLabel(getAppVersion()), url: localAppUrl(), icon: "dashboard", enabled: true, } } /** Offline fallback when auth-portal is unreachable. */ export const DEFAULT_APP_SWITCHER_CONFIG: AppSwitcherConfig = { menuLabel: "Приложения", apps: [ localMikrotikEntry(), { id: "cfdm", name: "CF Domain Manager", subtitle: "Управление доменами", url: "https://cfdm.shnt.top", icon: "cloud", }, { id: "vps", name: "VPS Tracker", subtitle: "Учёт виртуальных серверов", url: "https://vps.shnt.top", icon: "server", }, { id: "bgp", name: "EvoBGP", subtitle: "BGP маршрутизация", url: "https://bgp.shnt.top", icon: "globe", }, { id: "fw", name: "EvoFirewall", subtitle: "Firewall controller", url: "https://fw.shnt.top", icon: "server", }, { id: "dns", name: "Technitium DNS", subtitle: "DNS-сервер", url: "https://dns.shnt.top", icon: "globe", }, ], } const ICON_NAMES = new Set([ "server", "cloud", "globe", "dashboard", "chart", ]) function asIcon(value: unknown): AppSwitcherIconName { return ICON_NAMES.has(value as AppSwitcherIconName) ? (value as AppSwitcherIconName) : "server" } export function parseAppSwitcherConfig(raw: unknown): AppSwitcherConfig | null { if (!raw || typeof raw !== "object") return null const data = raw as { menuLabel?: unknown; apps?: unknown } if (!Array.isArray(data.apps) || data.apps.length === 0) return null const apps: AppSwitcherEntry[] = [] for (const item of data.apps) { if (!item || typeof item !== "object") continue const row = item as Record if (typeof row.id !== "string" || typeof row.name !== "string" || typeof row.url !== "string") { continue } if (row.enabled === false) continue apps.push({ id: row.id, name: row.name, subtitle: typeof row.subtitle === "string" ? row.subtitle : undefined, url: row.url, icon: asIcon(row.icon), shortcut: typeof row.shortcut === "string" ? row.shortcut : undefined, enabled: true, }) } if (apps.length === 0) return null return { menuLabel: typeof data.menuLabel === "string" && data.menuLabel ? data.menuLabel : "Приложения", apps, } } export function mergeWithLocalApp(config: AppSwitcherConfig): AppSwitcherConfig { const local = localMikrotikEntry() const rest = config.apps.filter((app) => app.id !== CURRENT_APP_ID) return { ...config, apps: [local, ...rest] } } export function authPortalBaseUrl(): string | null { const raw = process.env.NEXT_PUBLIC_AUTH_PORTAL_URL?.trim() if (!raw) return null return raw.replace(/\/$/, "") } export function getCurrentApp( config: AppSwitcherConfig = DEFAULT_APP_SWITCHER_CONFIG, ): AppSwitcherEntry { return config.apps.find((app) => app.id === CURRENT_APP_ID) ?? localMikrotikEntry() }