feat: add new and total users data route

This commit is contained in:
Ephraim Atta-Duncan
2024-10-24 12:05:20 +00:00
parent 25d4f1e101
commit bc5e819207
7 changed files with 133 additions and 3 deletions

View File

@@ -0,0 +1,25 @@
import cors from '@/lib/cors';
import { getUserMonthlyGrowth } from '@/lib/growth/get-user-monthly-growth';
export async function GET(request: Request) {
const monthlyUsers = await getUserMonthlyGrowth();
return cors(
request,
new Response(JSON.stringify(monthlyUsers), {
status: 200,
headers: {
'content-type': 'application/json',
},
}),
);
}
export function OPTIONS(request: Request) {
return cors(
request,
new Response(null, {
status: 204,
}),
);
}

View File

@@ -0,0 +1,37 @@
import type { NextRequest } from 'next/server';
import cors from '@/lib/cors';
const paths = [
{ path: '/total-customers', description: 'Total Customers' },
{ path: '/total-users', description: 'Total Users' },
{ path: '/new-users', description: 'New Users' },
{ path: '/completed-documents', description: 'Completed Documents per Month' },
{ path: '/total-completed-documents', description: 'Total Completed Documents' },
];
export function GET(request: NextRequest) {
const url = request.nextUrl.toString();
const apis = paths.map(({ path, description }) => {
return { path: url + path, description };
});
return cors(
request,
new Response(JSON.stringify(apis), {
status: 200,
headers: {
'content-type': 'application/json',
},
}),
);
}
export function OPTIONS(request: Request) {
return cors(
request,
new Response(null, {
status: 204,
}),
);
}

View File

@@ -0,0 +1,25 @@
import cors from '@/lib/cors';
import { getUserMonthlyGrowth } from '@/lib/growth/get-user-monthly-growth';
export async function GET(request: Request) {
const totalUsers = await getUserMonthlyGrowth();
return cors(
request,
new Response(JSON.stringify(totalUsers), {
status: 200,
headers: {
'content-type': 'application/json',
},
}),
);
}
export function OPTIONS(request: Request) {
return cors(
request,
new Response(null, {
status: 204,
}),
);
}

View File

@@ -5,6 +5,7 @@ import cors from '@/lib/cors';
const paths = [
{ path: 'github', description: 'GitHub Data' },
{ path: 'community', description: 'Community Data' },
{ path: 'growth', description: 'Growth Data' },
];
export function GET(request: NextRequest) {

View File

@@ -0,0 +1,38 @@
import { DateTime } from 'luxon';
import { kyselyPrisma, sql } from '@documenso/prisma';
export const getUserMonthlyGrowth = async (type: 'count' | 'cumulative' = 'count') => {
const qb = kyselyPrisma.$kysely
.selectFrom('User')
.select(({ fn }) => [
fn<Date>('DATE_TRUNC', [sql.lit('MONTH'), 'User.createdAt']).as('month'),
fn.count('id').as('count'),
fn
.sum(fn.count('id'))
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
.over((ob) => ob.orderBy(fn('DATE_TRUNC', [sql.lit('MONTH'), 'User.createdAt']) as any))
.as('cume_count'),
])
.groupBy('month')
.orderBy('month', 'desc')
.limit(12);
const result = await qb.execute();
const transformedData = {
labels: result.map((row) => DateTime.fromJSDate(row.month).toFormat('MMM yyyy')).reverse(),
datasets: [
{
label: type === 'count' ? 'New Users' : 'Total Users',
data: result
.map((row) => (type === 'count' ? Number(row.count) : Number(row.cume_count)))
.reverse(),
},
],
};
return transformedData;
};
export type GetUserMonthlyGrowthResult = Awaited<ReturnType<typeof getUserMonthlyGrowth>>;

8
package-lock.json generated
View File

@@ -13,8 +13,10 @@
],
"dependencies": {
"@documenso/pdf-sign": "^0.1.0",
"@documenso/prisma": "^0.0.0",
"@lingui/core": "^4.11.3",
"inngest-cli": "^0.29.1",
"luxon": "^3.5.0",
"next-runtime-env": "^3.2.0",
"react": "^18"
},
@@ -22279,9 +22281,9 @@
}
},
"node_modules/luxon": {
"version": "3.4.4",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz",
"integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==",
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz",
"integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==",
"engines": {
"node": ">=12"
}

View File

@@ -64,8 +64,10 @@
],
"dependencies": {
"@documenso/pdf-sign": "^0.1.0",
"@documenso/prisma": "^0.0.0",
"@lingui/core": "^4.11.3",
"inngest-cli": "^0.29.1",
"luxon": "^3.5.0",
"next-runtime-env": "^3.2.0",
"react": "^18"
},