nothingworry's picture
feat: implement role-based access control UI - hide/show features based on user role (viewer/editor/admin/owner)
dc11950
raw
history blame
3.38 kB
"use client";
import Link from "next/link";
import { AdminRulesPanel } from "@/components/admin-rules-panel";
import { AnalyticsPanel } from "@/components/analytics-panel";
import { ChatPanel } from "@/components/chat-panel";
import { FeatureGrid } from "@/components/feature-grid";
import { Footer } from "@/components/footer";
import { Hero } from "@/components/hero";
import { KnowledgeBasePanel } from "@/components/knowledge-base-panel";
import { TenantSelector } from "@/components/tenant-selector";
import { useTenant } from "@/contexts/TenantContext";
import {
canManageRules,
canViewAnalytics,
canIngestDocuments,
} from "@/lib/permissions";
function Navigation() {
const { role } = useTenant();
const navItems = [
{
label: "Data Ingestion",
href: "/ingestion",
visible: canIngestDocuments(role),
},
{ label: "Chat Bot", href: "/chat", visible: true }, // Chat is available to all
{
label: "Analytics",
href: "/analytics",
visible: canViewAnalytics(role),
},
{
label: "Admin Rule Ingestion",
href: "/admin-rules",
visible: canManageRules(role),
},
];
const visibleNavItems = navItems.filter((item) => item.visible);
return (
<nav className="flex flex-wrap gap-2">
{visibleNavItems.map((item) => (
<Link
key={item.href}
href={item.href}
className="rounded-full border border-white/15 px-4 py-2 text-xs font-semibold uppercase tracking-[0.2em] text-slate-200 transition hover:border-cyan-400 hover:text-white"
>
{item.label}
</Link>
))}
</nav>
);
}
export default function Home() {
const { role } = useTenant();
return (
<main className="mx-auto flex min-h-screen max-w-6xl flex-col gap-10 px-4 pb-16 pt-12 sm:px-6 lg:px-8">
<header className="flex flex-col gap-6 rounded-2xl border border-white/10 bg-white/5 px-6 py-6 text-slate-100 shadow-lg shadow-slate-950/40">
<div className="flex flex-wrap items-center justify-between gap-3 text-sm">
<div className="flex items-center gap-3 text-base font-semibold">
<span className="inline-flex h-10 w-10 items-center justify-center rounded-2xl bg-gradient-to-br from-sky-400 to-cyan-500 text-slate-950">
IC
</span>
IntegraChat Operator Console
</div>
<div className="flex flex-wrap items-center gap-3 text-xs uppercase tracking-[0.4em] text-slate-400">
FastAPI 路 MCP Servers 路 Celery 路 Next.js
</div>
</div>
<div className="flex flex-wrap items-center justify-between gap-4">
<Navigation />
<TenantSelector />
</div>
</header>
<Hero />
<FeatureGrid />
{canIngestDocuments(role) && (
<section id="data-ingestion" className="scroll-mt-28">
<KnowledgeBasePanel />
</section>
)}
<section id="chat-bot" className="scroll-mt-28">
<ChatPanel />
</section>
{canViewAnalytics(role) && (
<section id="analytics" className="scroll-mt-28">
<AnalyticsPanel />
</section>
)}
{canManageRules(role) && (
<section id="admin-rules" className="scroll-mt-28">
<AdminRulesPanel />
</section>
)}
<Footer />
</main>
);
}