This commit is contained in:
giancarlo
2024-03-24 02:23:22 +08:00
parent 648d77b430
commit bce3479368
589 changed files with 37067 additions and 9596 deletions

View 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>;
}

View 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;

View 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;

View 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;