From 2cbe14572b427137a2293d145002be74f6825358 Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Wed, 19 Feb 2025 16:49:46 +0000 Subject: [PATCH] chore: wip --- .../leaderboard/data-table-leaderboard.tsx | 3 +- .../server-only/admin/get-signing-volume.ts | 184 ++++++++++-------- 2 files changed, 107 insertions(+), 80 deletions(-) diff --git a/apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx b/apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx index 3fff9e870..28221707d 100644 --- a/apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx +++ b/apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx @@ -15,11 +15,10 @@ import { Input } from '@documenso/ui/primitives/input'; export type SigningVolume = { id: number; - name: string; + name: string | null; signingVolume: number; createdAt: Date; planId: string; - customerId: string; }; type LeaderboardTableProps = { diff --git a/packages/lib/server-only/admin/get-signing-volume.ts b/packages/lib/server-only/admin/get-signing-volume.ts index a71fb07f5..a86ccdf82 100644 --- a/packages/lib/server-only/admin/get-signing-volume.ts +++ b/packages/lib/server-only/admin/get-signing-volume.ts @@ -1,4 +1,6 @@ -import { kyselyPrisma, sql } from '@documenso/prisma'; +import { Prisma } from '@prisma/client'; + +import { prisma } from '@documenso/prisma'; import { DocumentStatus, SubscriptionStatus } from '@documenso/prisma/client'; export type SigningVolume = { @@ -7,7 +9,6 @@ export type SigningVolume = { signingVolume: number; createdAt: Date; planId: string; - customerId: string; }; export type GetSigningVolumeOptions = { @@ -25,86 +26,113 @@ export async function getSigningVolume({ sortBy = 'signingVolume', sortOrder = 'desc', }: GetSigningVolumeOptions) { - const offset = Math.max(page - 1, 0) * perPage; + const skip = (page - 1) * perPage; - let findQuery = kyselyPrisma.$kysely - .selectFrom('Subscription as s') - .leftJoin('User as u', 's.userId', 'u.id') - .leftJoin('Team as t', 's.teamId', 't.id') - .leftJoin('Document as d', (join) => - join - .on((eb) => - eb.or([ - eb.and([eb('d.userId', '=', eb.ref('u.id')), eb('d.teamId', 'is', null)]), - eb('d.teamId', '=', eb.ref('t.id')), - ]), - ) - .on('d.status', '=', sql.lit(DocumentStatus.COMPLETED)) - .on('d.deletedAt', 'is', null), - ) - // @ts-expect-error - Raw SQL enum casting not properly typed by Kysely - .where(sql`s.status = ${SubscriptionStatus.ACTIVE}::"SubscriptionStatus"`) - .where((eb) => - eb.or([ - eb('u.name', 'ilike', `%${search}%`), - eb('u.email', 'ilike', `%${search}%`), - eb('t.name', 'ilike', `%${search}%`), - ]), - ) - .select([ - 's.id as id', - 's.planId as planId', - 's.createdAt as createdAt', - sql`COALESCE(u."customerId", t."customerId")`.as('customerId'), - sql`COALESCE(u.name, t.name, u.email, 'Unknown')`.as('name'), - sql`COUNT(DISTINCT d.id)`.as('signingVolume'), - ]) - .groupBy([ - 's.id', - 's.planId', - 's.createdAt', - 'u.customerId', - 't.customerId', - 'u.name', - 't.name', - 'u.email', - ]); + const baseUserQuery = { + OR: [ + { + subscriptions: { + some: { + status: SubscriptionStatus.ACTIVE, + }, + }, + }, + { + teamMembers: { + some: { + team: { + subscription: { + status: SubscriptionStatus.ACTIVE, + }, + }, + }, + }, + }, + ], + ...(search + ? { + OR: [ + { name: { contains: search, mode: Prisma.QueryMode.insensitive } }, + { email: { contains: search, mode: Prisma.QueryMode.insensitive } }, + ], + } + : {}), + }; - switch (sortBy) { - case 'name': - findQuery = findQuery.orderBy('name', sortOrder); - break; - case 'createdAt': - findQuery = findQuery.orderBy('createdAt', sortOrder); - break; - case 'signingVolume': - findQuery = findQuery.orderBy('signingVolume', sortOrder); - break; - default: - findQuery = findQuery.orderBy('signingVolume', 'desc'); + const results = await prisma.user.findMany({ + where: baseUserQuery, + select: { + id: true, + name: true, + email: true, + createdAt: true, + _count: { + select: { + documents: { + where: { + status: DocumentStatus.COMPLETED, + }, + }, + }, + }, + teamMembers: { + select: { + team: { + select: { + documents: { + where: { + status: DocumentStatus.COMPLETED, + }, + }, + }, + }, + }, + }, + }, + skip, + take: perPage, + orderBy: [ + ...(sortBy === 'name' + ? [{ name: sortOrder }] + : sortBy === 'createdAt' + ? [{ createdAt: sortOrder }] + : []), + ], + }); + + const count = await prisma.user.count({ + where: baseUserQuery, + }); + + const transformedResults = results.map((user) => { + const personalDocuments = user._count.documents; + + const teamDocuments = user.teamMembers.reduce( + (acc, member) => acc + member.team.documents.length, + 0, + ); + + const signingVolume = personalDocuments + teamDocuments; + + return { + id: user.id, + name: user.name, + signingVolume, + createdAt: user.createdAt, + planId: '', + }; + }); + + if (sortBy === 'signingVolume') { + transformedResults.sort((a, b) => { + return sortOrder === 'desc' + ? b.signingVolume - a.signingVolume + : a.signingVolume - b.signingVolume; + }); } - findQuery = findQuery.limit(perPage).offset(offset); - - const countQuery = kyselyPrisma.$kysely - .selectFrom('Subscription as s') - .leftJoin('User as u', 's.userId', 'u.id') - .leftJoin('Team as t', 's.teamId', 't.id') - // @ts-expect-error - Raw SQL enum casting not properly typed by Kysely - .where(sql`s.status = ${SubscriptionStatus.ACTIVE}::"SubscriptionStatus"`) - .where((eb) => - eb.or([ - eb('u.name', 'ilike', `%${search}%`), - eb('u.email', 'ilike', `%${search}%`), - eb('t.name', 'ilike', `%${search}%`), - ]), - ) - .select(({ fn }) => [fn.countAll().as('count')]); - - const [results, [{ count }]] = await Promise.all([findQuery.execute(), countQuery.execute()]); - return { - leaderboard: results, - totalPages: Math.ceil(Number(count) / perPage), + leaderboard: transformedResults, + totalPages: Math.ceil(count / perPage), }; }