mirror of
https://github.com/documenso/documenso.git
synced 2025-11-14 00:32:43 +10:00
feat: open page api (#1419)
This commit is contained in:
@ -0,0 +1,43 @@
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { kyselyPrisma, sql } from '@documenso/prisma';
|
||||
import { DocumentStatus } from '@documenso/prisma/client';
|
||||
|
||||
export const getCompletedDocumentsMonthly = async (type: 'count' | 'cumulative' = 'count') => {
|
||||
const qb = kyselyPrisma.$kysely
|
||||
.selectFrom('Document')
|
||||
.select(({ fn }) => [
|
||||
fn<Date>('DATE_TRUNC', [sql.lit('MONTH'), 'Document.updatedAt']).as('month'),
|
||||
fn.count('id').as('count'),
|
||||
fn
|
||||
.sum(fn.count('id'))
|
||||
// Feels like a bug in the Kysely extension but I just can not do this orderBy in a type-safe manner
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
|
||||
.over((ob) => ob.orderBy(fn('DATE_TRUNC', [sql.lit('MONTH'), 'Document.updatedAt']) as any))
|
||||
.as('cume_count'),
|
||||
])
|
||||
.where(() => sql`"Document"."status" = ${DocumentStatus.COMPLETED}::"DocumentStatus"`)
|
||||
.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' ? 'Completed Documents per Month' : 'Total Completed Documents',
|
||||
data: result
|
||||
.map((row) => (type === 'count' ? Number(row.count) : Number(row.cume_count)))
|
||||
.reverse(),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return transformedData;
|
||||
};
|
||||
|
||||
export type GetCompletedDocumentsMonthlyResult = Awaited<
|
||||
ReturnType<typeof getCompletedDocumentsMonthly>
|
||||
>;
|
||||
42
apps/openpage-api/lib/growth/get-signer-conversion.ts
Normal file
42
apps/openpage-api/lib/growth/get-signer-conversion.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { kyselyPrisma, sql } from '@documenso/prisma';
|
||||
|
||||
export const getSignerConversionMonthly = async (type: 'count' | 'cumulative' = 'count') => {
|
||||
const qb = kyselyPrisma.$kysely
|
||||
.selectFrom('Recipient')
|
||||
.innerJoin('User', 'Recipient.email', 'User.email')
|
||||
.select(({ fn }) => [
|
||||
fn<Date>('DATE_TRUNC', [sql.lit('MONTH'), 'User.createdAt']).as('month'),
|
||||
fn.count('Recipient.email').distinct().as('count'),
|
||||
fn
|
||||
.sum(fn.count('Recipient.email').distinct())
|
||||
// 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'),
|
||||
])
|
||||
.where('Recipient.signedAt', 'is not', null)
|
||||
.where('Recipient.signedAt', '<', (eb) => eb.ref('User.createdAt'))
|
||||
.groupBy(({ fn }) => fn('DATE_TRUNC', [sql.lit('MONTH'), 'User.createdAt']))
|
||||
.orderBy('month', 'desc');
|
||||
|
||||
const result = await qb.execute();
|
||||
|
||||
const transformedData = {
|
||||
labels: result.map((row) => DateTime.fromJSDate(row.month).toFormat('MMM yyyy')).reverse(),
|
||||
datasets: [
|
||||
{
|
||||
label: type === 'count' ? 'Signers That Signed Up' : 'Total Signers That Signed Up',
|
||||
data: result
|
||||
.map((row) => (type === 'count' ? Number(row.count) : Number(row.cume_count)))
|
||||
.reverse(),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return transformedData;
|
||||
};
|
||||
|
||||
export type GetSignerConversionMonthlyResult = Awaited<
|
||||
ReturnType<typeof getSignerConversionMonthly>
|
||||
>;
|
||||
38
apps/openpage-api/lib/growth/get-user-monthly-growth.ts
Normal file
38
apps/openpage-api/lib/growth/get-user-monthly-growth.ts
Normal 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>>;
|
||||
Reference in New Issue
Block a user