Implemented new API functions to fetch and update agent node profiles, enhancing the management capabilities for agent data. This addition improves the overall functionality of the admin agents console, allowing for better user interaction with agent profiles. Updated related types for improved type safety and clarity in the codebase.
111 lines
3.0 KiB
TypeScript
111 lines
3.0 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import { useMemo } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import { adminHasAnyPermission } from "@/lib/admin-permissions";
|
|
import {
|
|
PRD_AGENT_LINE_PROVISION_ACCESS_ANY,
|
|
PRD_AGENT_SITES_ACCESS_ANY,
|
|
PRD_AGENTS_ACCESS_ANY,
|
|
PRD_SETTLEMENT_AGENT_ACCESS_ANY,
|
|
} from "@/lib/admin-prd";
|
|
import { cn } from "@/lib/utils";
|
|
import { useAdminProfile } from "@/stores/admin-session";
|
|
|
|
const tabs: {
|
|
href: string;
|
|
labelKey: string;
|
|
matchPrefix: string;
|
|
requiredAny: readonly string[];
|
|
}[] = [
|
|
{
|
|
href: "/admin/agents",
|
|
labelKey: "subnav.operations",
|
|
matchPrefix: "/admin/agents",
|
|
requiredAny: PRD_AGENTS_ACCESS_ANY,
|
|
},
|
|
{
|
|
href: "/admin/agents/provision",
|
|
labelKey: "subnav.provision",
|
|
matchPrefix: "/admin/agents/provision",
|
|
requiredAny: PRD_AGENT_LINE_PROVISION_ACCESS_ANY,
|
|
},
|
|
{
|
|
href: "/admin/agents/sites",
|
|
labelKey: "subnav.sites",
|
|
matchPrefix: "/admin/agents/sites",
|
|
requiredAny: PRD_AGENT_SITES_ACCESS_ANY,
|
|
},
|
|
{
|
|
href: "/admin/agents/settlement-bills",
|
|
labelKey: "subnav.settlementBills",
|
|
matchPrefix: "/admin/agents/settlement",
|
|
requiredAny: PRD_SETTLEMENT_AGENT_ACCESS_ANY,
|
|
},
|
|
];
|
|
|
|
function isTabActive(pathname: string, href: string, matchPrefix: string): boolean {
|
|
if (href === "/admin/agents") {
|
|
return (
|
|
pathname === "/admin/agents" ||
|
|
pathname === "/admin/agents/list" ||
|
|
(pathname.startsWith("/admin/agents/") &&
|
|
!pathname.startsWith("/admin/agents/provision") &&
|
|
!pathname.startsWith("/admin/agents/sites") &&
|
|
!pathname.startsWith("/admin/agents/settlement"))
|
|
);
|
|
}
|
|
|
|
return pathname === href || pathname.startsWith(`${matchPrefix}/`) || pathname === matchPrefix;
|
|
}
|
|
|
|
export function AgentsSubnav(): React.ReactElement {
|
|
const { t } = useTranslation("agents");
|
|
const pathname = usePathname();
|
|
const profile = useAdminProfile();
|
|
const perms = profile?.permissions;
|
|
|
|
const visibleTabs = useMemo(
|
|
() =>
|
|
tabs.filter(
|
|
(tab) =>
|
|
profile?.is_super_admin === true ||
|
|
adminHasAnyPermission(perms, [...tab.requiredAny]),
|
|
),
|
|
[perms, profile?.is_super_admin],
|
|
);
|
|
|
|
if (visibleTabs.length === 0) {
|
|
return <></>;
|
|
}
|
|
|
|
return (
|
|
<nav
|
|
aria-label={t("subnav.label", { defaultValue: "代理线路导航" })}
|
|
className="flex w-full flex-wrap items-end gap-1 border-b border-border/60 px-1"
|
|
>
|
|
{visibleTabs.map((tab) => {
|
|
const active = isTabActive(pathname, tab.href, tab.matchPrefix);
|
|
|
|
return (
|
|
<Link
|
|
key={tab.href}
|
|
href={tab.href}
|
|
className={cn(
|
|
"border-b-2 px-4 py-3 text-sm font-medium transition-colors",
|
|
active
|
|
? "border-primary text-primary"
|
|
: "border-transparent text-muted-foreground hover:border-border/80 hover:text-foreground",
|
|
)}
|
|
>
|
|
{t(tab.labelKey)}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
);
|
|
}
|