admin dashbaord; started member managment ui

This commit is contained in:
2025-03-07 20:18:00 +01:00
parent 4a1397651f
commit 5c09688f1a
24 changed files with 1466 additions and 29 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
import { hasPermission, Role } from "@/lib/validation/has-permission";
import { hasPermission, Role } from "@/lib/validation/permissions";
import { auth } from "@/server/auth";
import { api } from "@/trpc/server";
import { notFound } from "next/navigation";
+1 -1
View File
@@ -1,5 +1,5 @@
import { Button } from "@/components/ui/button";
import { hasPermission, Role } from "@/lib/validation/has-permission";
import { hasPermission, Role } from "@/lib/validation/permissions";
import { auth } from "@/server/auth";
import { api } from "@/trpc/server";
import { Edit, Edit2Icon, Edit3, MoreVertical, Trash } from "lucide-react";
@@ -0,0 +1,15 @@
import { Button } from "@/components/ui/button";
import { auth } from "@/server/auth";
import Link from "next/link";
import React from "react";
async function AdminNavbar() {
const session = await auth();
return (
<div className="flex h-14 w-full items-center justify-between gap-4 border-b bg-sidebar px-4">
<span>Admin Dashboard</span>
</div>
);
}
export default AdminNavbar;
@@ -0,0 +1,76 @@
import * as React from "react";
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
} from "@/components/ui/sidebar";
import Link from "next/link";
import SidebarLink from "@/components/layout/sidebar-link";
import { Button } from "@/components/ui/button";
import { LogOutIcon } from "lucide-react";
import { appConfig } from "@/app.config";
const data = {
navMain: [
{
title: "Benutzer",
url: "/admin",
items: [
{
title: "Team Mitglieder",
url: "/admin/team",
},
{
title: "Alle Benutzer",
url: "/admin/benutzer",
},
],
},
],
};
export function AdminSidebar({
...props
}: React.ComponentProps<typeof Sidebar>) {
return (
<Sidebar {...props}>
<SidebarHeader className="flex h-14 items-center justify-center border-b">
<Link href={"/admin"}>
<span className="text-2xl font-bold">{appConfig.name}</span>
</Link>
</SidebarHeader>
<SidebarContent>
{/* We create a SidebarGroup for each parent. */}
{data.navMain.map((item) => (
<SidebarGroup key={item.title}>
<SidebarGroupLabel>{item.title}</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{item.items.map((item) => (
<SidebarLink key={item.title} {...item} />
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
))}
</SidebarContent>
<SidebarFooter>
<Button
asChild
variant={"destructive"}
className="border-2 bg-sidebar text-foreground hover:text-destructive-foreground"
>
<Link href={"/"}>
<LogOutIcon className="size-4 rotate-180" /> Verlassen
</Link>
</Button>
</SidebarFooter>
</Sidebar>
);
}
+26
View File
@@ -0,0 +1,26 @@
import { hasPermission, Role } from "@/lib/validation/permissions";
import { auth } from "@/server/auth";
import { notFound } from "next/navigation";
import React from "react";
import AdminNavbar from "./_components/admin-navbar";
import { SidebarProvider } from "@/components/ui/sidebar";
import { AdminSidebar } from "./_components/admin-sidebar";
async function Layout({ children }: { children: React.ReactNode }) {
const session = await auth();
const isAdmin = session?.user
? hasPermission(session.user.role, Role.ADMIN)
: false;
if (!isAdmin) return notFound();
return (
<SidebarProvider>
<AdminSidebar />
<div className="w-full">
{/* <AdminNavbar /> */}
<main className="space-y-4 p-4"> {children}</main>
</div>
</SidebarProvider>
);
}
export default Layout;
+8
View File
@@ -0,0 +1,8 @@
import { api } from "@/trpc/server";
import React from "react";
async function Page() {
return <div>Admin Dashboard</div>;
}
export default Page;
+50
View File
@@ -0,0 +1,50 @@
"use client";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { getUserPermissions } from "@/lib/validation/permissions";
import { ColumnDef } from "@tanstack/react-table";
import { Plus } from "lucide-react";
import { User } from "next-auth";
export const columns: ColumnDef<User>[] = [
{
accessorKey: "name",
header: "Name",
},
{
accessorKey: "email",
header: "Email",
},
{
accessorKey: "role",
header: "Rollen",
cell: ({ row }) => {
const roles = getUserPermissions(Number(row.getValue("role")));
return (
<div className="flex items-center gap-2">
{roles
.filter(({ name }) => name !== "User")
.map((role) => (
<Badge
key={role.name}
variant={"outline"}
className={`${Object.values(role.color).join(" ")}`}
>
{role.name}
</Badge>
))}
<Button
size={"icon"}
variant={"outline"}
className="size-max gap-1 bg-muted p-px text-muted-foreground"
>
<Plus className="size-3" />
</Button>
</div>
);
},
},
];
+22
View File
@@ -0,0 +1,22 @@
import { api } from "@/trpc/server";
import React from "react";
import { DataTable } from "@/components/data-table";
import { columns } from "./columns";
import { Button } from "@/components/ui/button";
async function Page() {
const users = await api.users.getAll();
return (
<>
<div className="flex w-full items-center justify-between">
<h1 className="text-2xl font-bold">Team Mitglieder</h1>
<Button variant={"outline"}>Mitglied einladen</Button>
</div>
<DataTable columns={columns} data={users} />
</>
);
}
export default Page;