Add admin dashboard data loading & package dependencies
Removed 'admin-header.tsx' and 'admin-sidebar.tsx' components and added 'admin-dashboard.loader.ts' to handle loading data for the admin dashboard. Updated 'admin-dashboard.tsx' and 'page.tsx' to use this loader. Package dependencies were also updated in 'pnpm-lock.yaml' and 'package.json' files of relevant packages. This commit prioritizes loading dashboard data effectively and managing package dependencies.
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
"./components": "./src/components/index.ts"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@hookform/resolvers": "3.3.4",
|
||||
"@kit/billing": "0.1.0",
|
||||
"@kit/shared": "^0.1.0",
|
||||
"@kit/stripe": "0.1.0",
|
||||
@@ -24,6 +25,7 @@
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hookform/resolvers": "^3.3.4",
|
||||
"@kit/billing": "workspace:^",
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
"@kit/lemon-squeezy": "workspace:^",
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
},
|
||||
"prettier": "@kit/prettier-config",
|
||||
"peerDependencies": {
|
||||
"@kit/ui": "0.1.0"
|
||||
"@kit/ui": "0.1.0",
|
||||
"@makerkit/data-loader-supabase-core": "0.0.5",
|
||||
"@makerkit/data-loader-supabase-nextjs": "^0.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
@@ -19,6 +21,8 @@
|
||||
"@kit/tailwind-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:^",
|
||||
"@makerkit/data-loader-supabase-core": "0.0.5",
|
||||
"@makerkit/data-loader-supabase-nextjs": "^0.0.7",
|
||||
"@supabase/supabase-js": "^2.42.0",
|
||||
"lucide-react": "^0.363.0"
|
||||
},
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@kit/ui/card';
|
||||
|
||||
interface Data {
|
||||
usersCount: number;
|
||||
organizationsCount: number;
|
||||
activeSubscriptions: number;
|
||||
trialSubscriptions: number;
|
||||
}
|
||||
import { loadAdminDashboard } from '../lib/server/loaders/admin-dashboard.loader';
|
||||
|
||||
export async function AdminDashboard() {
|
||||
const data = await loadAdminDashboard();
|
||||
|
||||
export function AdminDashboard({
|
||||
data,
|
||||
}: React.PropsWithChildren<{
|
||||
data: Data;
|
||||
}>) {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
@@ -22,23 +21,31 @@ export function AdminDashboard({
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Users</CardTitle>
|
||||
|
||||
<CardDescription>
|
||||
The number of personal accounts that have been created.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<div className={'flex justify-between'}>
|
||||
<Figure>{data.usersCount}</Figure>
|
||||
<Figure>{data.accounts}</Figure>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Organizations</CardTitle>
|
||||
<CardTitle>Team Accounts</CardTitle>
|
||||
|
||||
<CardDescription>
|
||||
The number of team accounts that have been created.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<div className={'flex justify-between'}>
|
||||
<Figure>{data.organizationsCount}</Figure>
|
||||
<Figure>{data.teamAccounts}</Figure>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -46,11 +53,14 @@ export function AdminDashboard({
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Paying Customers</CardTitle>
|
||||
<CardDescription>
|
||||
The number of paying customers with active subscriptions.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<div className={'flex justify-between'}>
|
||||
<Figure>{data.activeSubscriptions}</Figure>
|
||||
<Figure>{data.subscriptions}</Figure>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -58,11 +68,15 @@ export function AdminDashboard({
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Trials</CardTitle>
|
||||
|
||||
<CardDescription>
|
||||
Th number of trial subscriptions currently active.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<div className={'flex justify-between'}>
|
||||
<Figure>{data.trialSubscriptions}</Figure>
|
||||
<Figure>{data.trials}</Figure>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { PageHeader } from '@kit/ui/page';
|
||||
|
||||
export function AdminHeader({
|
||||
children,
|
||||
paths,
|
||||
}: React.PropsWithChildren<{
|
||||
paths: {
|
||||
appHome: string;
|
||||
};
|
||||
}>) {
|
||||
return (
|
||||
<PageHeader
|
||||
title={children}
|
||||
description={`Manage your app from the admin dashboard.`}
|
||||
>
|
||||
<Link href={paths.appHome}>
|
||||
<Button variant={'link'}>
|
||||
<ArrowLeft className={'h-4'} />
|
||||
<span>Back to App</span>
|
||||
</Button>
|
||||
</Link>
|
||||
</PageHeader>
|
||||
);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Home, User, Users } from 'lucide-react';
|
||||
|
||||
import { Sidebar, SidebarContent, SidebarItem } from '@kit/ui/sidebar';
|
||||
|
||||
export function AdminSidebar(props: { Logo: React.ReactNode }) {
|
||||
return (
|
||||
<Sidebar>
|
||||
<SidebarContent className={'mb-6 mt-4 pt-2'}>{props.Logo}</SidebarContent>
|
||||
|
||||
<SidebarContent>
|
||||
<SidebarItem end path={'/admin'} Icon={<Home className={'h-4'} />}>
|
||||
Admin
|
||||
</SidebarItem>
|
||||
|
||||
<SidebarItem path={'/admin/users'} Icon={<User className={'h-4'} />}>
|
||||
Users
|
||||
</SidebarItem>
|
||||
|
||||
<SidebarItem
|
||||
path={'/admin/organizations'}
|
||||
Icon={<Users className={'h-4'} />}
|
||||
>
|
||||
Organizations
|
||||
</SidebarItem>
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
);
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
export * from './lib/is-super-admin';
|
||||
export * from './lib/server/is-super-admin';
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||
|
||||
export async function loadAdminDashboard(params?: {
|
||||
count: 'exact' | 'estimated' | 'planned';
|
||||
}) {
|
||||
const count = params?.count ?? 'estimated';
|
||||
const client = getSupabaseServerComponentClient({ admin: true });
|
||||
|
||||
const selectParams = {
|
||||
count,
|
||||
head: true,
|
||||
};
|
||||
|
||||
const subscriptionsPromise = client
|
||||
.from('subscriptions')
|
||||
.select('*', selectParams)
|
||||
.eq('status', 'active')
|
||||
.then((response) => response.count);
|
||||
|
||||
const trialsPromise = client
|
||||
.from('subscriptions')
|
||||
.select('*', selectParams)
|
||||
.eq('status', 'trialing')
|
||||
.then((response) => response.count);
|
||||
|
||||
const accountsPromise = client
|
||||
.from('accounts')
|
||||
.select('*', selectParams)
|
||||
.eq('is_personal_account', true)
|
||||
.then((response) => response.count);
|
||||
|
||||
const teamAccountsPromise = client
|
||||
.from('accounts')
|
||||
.select('*', selectParams)
|
||||
.eq('is_personal_account', false)
|
||||
.then((response) => response.count);
|
||||
|
||||
const [subscriptions, trials, accounts, teamAccounts] = await Promise.all([
|
||||
subscriptionsPromise,
|
||||
trialsPromise,
|
||||
accountsPromise,
|
||||
teamAccountsPromise,
|
||||
]);
|
||||
|
||||
return {
|
||||
subscriptions,
|
||||
trials,
|
||||
accounts,
|
||||
teamAccounts,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user