Cleanup
This commit is contained in:
77
packages/features/admin/src/components/AdminDashboard.tsx
Normal file
77
packages/features/admin/src/components/AdminDashboard.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
|
||||
|
||||
interface Data {
|
||||
usersCount: number;
|
||||
organizationsCount: number;
|
||||
activeSubscriptions: number;
|
||||
trialSubscriptions: number;
|
||||
}
|
||||
|
||||
function AdminDashboard({
|
||||
data,
|
||||
}: React.PropsWithChildren<{
|
||||
data: Data;
|
||||
}>) {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3' +
|
||||
' xl:grid-cols-4'
|
||||
}
|
||||
>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Users</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<div className={'flex justify-between'}>
|
||||
<Figure>{data.usersCount}</Figure>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Organizations</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<div className={'flex justify-between'}>
|
||||
<Figure>{data.organizationsCount}</Figure>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Paying Customers</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<div className={'flex justify-between'}>
|
||||
<Figure>{data.activeSubscriptions}</Figure>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Trials</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<div className={'flex justify-between'}>
|
||||
<Figure>{data.trialSubscriptions}</Figure>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AdminDashboard;
|
||||
|
||||
function Figure(props: React.PropsWithChildren) {
|
||||
return <div className={'text-3xl font-bold'}>{props.children}</div>;
|
||||
}
|
||||
22
packages/features/admin/src/components/AdminGuard.tsx
Normal file
22
packages/features/admin/src/components/AdminGuard.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
import isUserSuperAdmin from '../../../app/admin/utils/is-user-super-admin';
|
||||
|
||||
type LayoutOrPageComponent<Params> = React.ComponentType<Params>;
|
||||
|
||||
function AdminGuard<Params extends object>(
|
||||
Component: LayoutOrPageComponent<Params>,
|
||||
) {
|
||||
return async function AdminGuardServerComponentWrapper(params: Params) {
|
||||
const isAdmin = await isUserSuperAdmin();
|
||||
|
||||
// if the user is not a super-admin, we redirect to a 404
|
||||
if (!isAdmin) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return <Component {...params} />;
|
||||
};
|
||||
}
|
||||
|
||||
export default AdminGuard;
|
||||
27
packages/features/admin/src/components/AdminHeader.tsx
Normal file
27
packages/features/admin/src/components/AdminHeader.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
import { ArrowLeftIcon } from 'lucide-react';
|
||||
|
||||
import { Button } from '@kit/ui/button';
|
||||
|
||||
import pathsConfig from '@/config/paths.config';
|
||||
|
||||
import { PageHeader } from '@/components/app/Page';
|
||||
|
||||
function AdminHeader({ children }: React.PropsWithChildren) {
|
||||
return (
|
||||
<PageHeader
|
||||
title={children}
|
||||
description={`Manage your app from the admin dashboard.`}
|
||||
>
|
||||
<Link href={pathsConfig.appHome}>
|
||||
<Button variant={'link'}>
|
||||
<ArrowLeftIcon className={'h-4'} />
|
||||
<span>Back to App</span>
|
||||
</Button>
|
||||
</Link>
|
||||
</PageHeader>
|
||||
);
|
||||
}
|
||||
|
||||
export default AdminHeader;
|
||||
38
packages/features/admin/src/components/AdminSidebar.tsx
Normal file
38
packages/features/admin/src/components/AdminSidebar.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
'use client';
|
||||
|
||||
import { HomeIcon, UserIcon, UsersIcon } from 'lucide-react';
|
||||
|
||||
import Logo from '@/components/app/Logo';
|
||||
import { Sidebar, SidebarContent, SidebarItem } from '@/components/app/Sidebar';
|
||||
|
||||
function AdminSidebar() {
|
||||
return (
|
||||
<Sidebar>
|
||||
<SidebarContent className={'mb-6 mt-4 pt-2'}>
|
||||
<Logo href={'/admin'} />
|
||||
</SidebarContent>
|
||||
|
||||
<SidebarContent>
|
||||
<SidebarItem end path={'/admin'} Icon={<HomeIcon className={'h-4'} />}>
|
||||
Admin
|
||||
</SidebarItem>
|
||||
|
||||
<SidebarItem
|
||||
path={'/admin/users'}
|
||||
Icon={<UserIcon className={'h-4'} />}
|
||||
>
|
||||
Users
|
||||
</SidebarItem>
|
||||
|
||||
<SidebarItem
|
||||
path={'/admin/organizations'}
|
||||
Icon={<UsersIcon className={'h-4'} />}
|
||||
>
|
||||
Organizations
|
||||
</SidebarItem>
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
);
|
||||
}
|
||||
|
||||
export default AdminSidebar;
|
||||
Reference in New Issue
Block a user