Skip to content

Commit

Permalink
feat(saas): Admin dynamic users analytics data
Browse files Browse the repository at this point in the history
  • Loading branch information
alifarooq9 committed May 1, 2024
1 parent c6d989e commit f6c27cf
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
"use client";

import { LineChart } from "@/components/charts";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { formatDate, thousandToK } from "@/lib/utils";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { thousandToK } from "@/lib/utils";

type UsersChartProps = {
data: unknown[];
data: {
Date: string;
Users: number;
}[];
};

export function UsersChart({ data }: UsersChartProps) {
return (
<Card>
<CardHeader>
<CardTitle>Users Analytics</CardTitle>
<CardDescription>
Count of users joined each month for last 6 months
</CardDescription>
</CardHeader>
<CardContent>
<LineChart
data={data}
xAxisDataKey="Date"
yAxisDataKey="Users"
lineDataKeys={["Users", "Active Users"]}
lineDataKeys={["Users"]}
lineProps={[
{ stroke: "hsl(var(--primary))" },
{ stroke: "green" },
Expand All @@ -33,9 +45,6 @@ export function UsersChart({ data }: UsersChartProps) {
}
},
}}
xAxisProps={{
tickFormatter: formatDate,
}}
/>
</CardContent>
</Card>
Expand Down
39 changes: 13 additions & 26 deletions starterkits/saas/src/app/(app)/admin/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,15 @@ import { adminDashConfig } from "@/app/(app)/admin/dashboard/_constants/page-con
import { buttonVariants } from "@/components/ui/button";
import { siteUrls } from "@/config/urls";
import { cn } from "@/lib/utils";
import { formatDate } from "@/lib/utils";
import { getUsersCount } from "@/server/actions/user/queries";
import { DollarSignIcon, Users2Icon } from "lucide-react";
import Link from "next/link";

const data = [
{ Date: formatDate("2023-01-01"), Users: 1000, "Active Users": 100 },
{ Date: formatDate("2023-02-01"), Users: 1040, "Active Users": 120 },
{ Date: formatDate("2023-03-01"), Users: 1190, "Active Users": 140 },
{ Date: formatDate("2023-04-01"), Users: 1340, "Active Users": 160 },
{ Date: formatDate("2023-05-01"), Users: 1390, "Active Users": 180 },
{ Date: formatDate("2023-06-01"), Users: 1440, "Active Users": 200 },
{ Date: formatDate("2023-07-01"), Users: 1490, "Active Users": 220 },
{ Date: formatDate("2023-08-01"), Users: 1540, "Active Users": 240 },
{ Date: formatDate("2023-09-01"), Users: 1890, "Active Users": 260 },
{ Date: formatDate("2023-10-01"), Users: 2040, "Active Users": 280 },
{ Date: formatDate("2023-11-01"), Users: 4000, "Active Users": 300 },
{ Date: formatDate("2023-12-01"), Users: 10040, "Active Users": 320 },
{ Date: formatDate("2024-01-01"), Users: 19090, "Active Users": 340 },
{ Date: formatDate("2024-02-01"), Users: 25040, "Active Users": 360 },
];

export default async function AdminDashPage() {
const usersCountData = await getUsersCount();

const usersChartData = usersCountData.usersCountByMonth;

return (
<AppPageShell
title={adminDashConfig.title}
Expand All @@ -52,29 +39,29 @@ export default async function AdminDashPage() {

<div className="grid grid-cols-3 gap-4">
<StatsCard
title="Total Users"
value="1000"
title="Users"
value={String(usersCountData.totalCount)}
Icon={Users2Icon}
subText="+20.1% from last month"
subText="Total users joined"
/>

<StatsCard
title="Total Revenue"
title="Revenue"
value="$10,000"
Icon={DollarSignIcon}
subText="+20.1% from last month"
subText="Total revenue generated"
/>

<StatsCard
title="Total Subscriptions"
title="Subscriptions"
value="100"
Icon={DollarSignIcon}
subText="+20.1% from last month"
subText="Total subscriptions made"
/>
</div>

<div className="grid grid-cols-2 gap-4">
<UsersChart data={data} />
<UsersChart data={usersChartData} />
</div>
</div>
</AppPageShell>
Expand Down
2 changes: 1 addition & 1 deletion starterkits/saas/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ export function thousandToK(value: number) {
return value / 1000;
}

export function formatDate(date: string) {
export function formatDate(date: string | number | Date) {
return format(new Date(date), "PP");
}
45 changes: 43 additions & 2 deletions starterkits/saas/src/server/actions/user/queries.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"use server";
import "server-only";

import { db } from "@/server/db";
import { users } from "@/server/db/schema";
import { adminProcedure } from "@/server/procedures";
import { asc, count, desc, ilike, inArray, or } from "drizzle-orm";
import { asc, count, desc, gt, ilike, inArray, or } from "drizzle-orm";
import { unstable_noStore as noStore } from "next/cache";
import { z } from "zod";
import { eachMonthOfInterval, format, startOfMonth, subMonths } from "date-fns";

/**
* Get paginated users
Expand Down Expand Up @@ -94,3 +95,43 @@ export async function getPaginatedUsersQuery(

return { data, pageCount, total };
}

export async function getUsersCount() {
await adminProcedure();

const dateBeforeMonths = subMonths(new Date(), 6);

const startDateOfTheMonth = startOfMonth(dateBeforeMonths);

const { total, data } = await db.transaction(async (tx) => {
const data = await db.query.users.findMany({
where: gt(users.createdAt, startDateOfTheMonth),
});

const total = await tx
.select({ count: count() })
.from(users)
.execute()
.then((res) => res[0]?.count ?? 0);

return { total, data };
});

const months = eachMonthOfInterval({
start: startDateOfTheMonth,
end: new Date(),
});

const usersCountByMonth = months.map((month) => {
const monthStr = format(month, "MMM-yyy");
const count = data.filter(
(user) => format(new Date(user.createdAt), "MMM-yyy") === monthStr,
).length;
return { Date: monthStr, Users: count };
});

return {
usersCountByMonth,
totalCount: total,
};
}

0 comments on commit f6c27cf

Please sign in to comment.