mirror of
https://github.com/documenso/documenso.git
synced 2025-11-14 08:42:12 +10:00
chore: wip
This commit is contained in:
@ -15,10 +15,14 @@ import { Input } from '@documenso/ui/primitives/input';
|
|||||||
|
|
||||||
export type SigningVolume = {
|
export type SigningVolume = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string | null;
|
name: string;
|
||||||
|
email: string;
|
||||||
signingVolume: number;
|
signingVolume: number;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
planId: string;
|
planId: string;
|
||||||
|
userId?: number | null;
|
||||||
|
teamId?: number | null;
|
||||||
|
isTeam: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type LeaderboardTableProps = {
|
type LeaderboardTableProps = {
|
||||||
|
|||||||
@ -1,17 +1,7 @@
|
|||||||
import { Prisma } from '@prisma/client';
|
|
||||||
|
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
import { DocumentStatus, SubscriptionStatus } from '@documenso/prisma/client';
|
import { DocumentStatus, SubscriptionStatus } from '@documenso/prisma/client';
|
||||||
|
|
||||||
export type SigningVolume = {
|
type GetSigningVolumeOptions = {
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
signingVolume: number;
|
|
||||||
createdAt: Date;
|
|
||||||
planId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type GetSigningVolumeOptions = {
|
|
||||||
search?: string;
|
search?: string;
|
||||||
page?: number;
|
page?: number;
|
||||||
perPage?: number;
|
perPage?: number;
|
||||||
@ -19,133 +9,160 @@ export type GetSigningVolumeOptions = {
|
|||||||
sortOrder?: 'asc' | 'desc';
|
sortOrder?: 'asc' | 'desc';
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getSigningVolume({
|
export const getSigningVolume = async ({
|
||||||
search = '',
|
search = '',
|
||||||
page = 1,
|
page = 1,
|
||||||
perPage = 10,
|
perPage = 10,
|
||||||
sortBy = 'signingVolume',
|
sortBy = 'signingVolume',
|
||||||
sortOrder = 'desc',
|
sortOrder = 'desc',
|
||||||
}: GetSigningVolumeOptions) {
|
}: GetSigningVolumeOptions) => {
|
||||||
const skip = (page - 1) * perPage;
|
const validPage = Math.max(1, page);
|
||||||
|
const validPerPage = Math.max(1, perPage);
|
||||||
|
const skip = (validPage - 1) * validPerPage;
|
||||||
|
|
||||||
// Find all unique customerIds from both personal and team subscriptions
|
const activeSubscriptions = await prisma.subscription.findMany({
|
||||||
const activeCustomerIds = await prisma.$queryRaw<{ customerId: string }[]>`
|
where: {
|
||||||
SELECT DISTINCT "customerId"
|
status: SubscriptionStatus.ACTIVE,
|
||||||
FROM (
|
},
|
||||||
-- Get customerIds from users with active subscriptions
|
select: {
|
||||||
SELECT u."customerId"
|
id: true,
|
||||||
FROM "User" u
|
planId: true,
|
||||||
JOIN "Subscription" s ON u.id = s."userId"
|
userId: true,
|
||||||
WHERE s.status = 'ACTIVE' AND u."customerId" IS NOT NULL
|
teamId: true,
|
||||||
|
createdAt: true,
|
||||||
UNION
|
user: {
|
||||||
|
|
||||||
-- Get customerIds from teams with active subscriptions
|
|
||||||
SELECT t."customerId"
|
|
||||||
FROM "Team" t
|
|
||||||
JOIN "Subscription" s ON t.id = s."teamId"
|
|
||||||
WHERE s.status = 'ACTIVE' AND t."customerId" IS NOT NULL
|
|
||||||
) AS active_customers
|
|
||||||
${search ? Prisma.sql`WHERE "customerId" LIKE ${`%${search}%`}` : Prisma.empty}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const totalCustomerCount = activeCustomerIds.length;
|
|
||||||
|
|
||||||
const paginatedCustomerIds = activeCustomerIds.slice(skip, skip + perPage);
|
|
||||||
|
|
||||||
const customerData = await Promise.all(
|
|
||||||
paginatedCustomerIds.map(async ({ customerId }) => {
|
|
||||||
const users = await prisma.user.findMany({
|
|
||||||
where: { customerId },
|
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
name: true,
|
name: true,
|
||||||
email: true,
|
email: true,
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
team: {
|
||||||
const teams = await prisma.team.findMany({
|
|
||||||
where: { customerId },
|
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
name: true,
|
name: true,
|
||||||
|
teamEmail: {
|
||||||
|
select: {
|
||||||
|
email: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const userDocumentCount = await prisma.document.count({
|
const subscriptionData = activeSubscriptions.map((subscription) => {
|
||||||
|
const isTeam = !!subscription.teamId;
|
||||||
|
return {
|
||||||
|
id: subscription.id,
|
||||||
|
planId: subscription.planId,
|
||||||
|
userId: subscription.userId,
|
||||||
|
teamId: subscription.teamId,
|
||||||
|
name: isTeam ? subscription.team?.name : subscription.user?.name || '',
|
||||||
|
email: isTeam
|
||||||
|
? subscription.team?.teamEmail?.email || `Team ${subscription.team?.id}`
|
||||||
|
: subscription.user?.email || '',
|
||||||
|
createdAt: isTeam ? subscription.team?.createdAt : subscription.user?.createdAt,
|
||||||
|
isTeam,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const filteredSubscriptions = search
|
||||||
|
? subscriptionData.filter((sub) => {
|
||||||
|
const searchLower = search.toLowerCase();
|
||||||
|
return (
|
||||||
|
sub.name?.toLowerCase().includes(searchLower) ||
|
||||||
|
sub.email?.toLowerCase().includes(searchLower)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: subscriptionData;
|
||||||
|
|
||||||
|
const leaderboardWithVolume = await Promise.all(
|
||||||
|
filteredSubscriptions.map(async (subscription) => {
|
||||||
|
let signingVolume = 0;
|
||||||
|
|
||||||
|
if (subscription.userId) {
|
||||||
|
const personalCount = await prisma.document.count({
|
||||||
where: {
|
where: {
|
||||||
userId: { in: users.map((user) => user.id) },
|
userId: subscription.userId,
|
||||||
status: DocumentStatus.COMPLETED,
|
status: DocumentStatus.COMPLETED,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const teamDocumentCount = await prisma.document.count({
|
signingVolume += personalCount;
|
||||||
where: {
|
|
||||||
teamId: { in: teams.map((team) => team.id) },
|
|
||||||
status: DocumentStatus.COMPLETED,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const subscription = await prisma.subscription.findFirst({
|
const userTeams = await prisma.teamMember.findMany({
|
||||||
where: {
|
where: {
|
||||||
OR: [{ user: { customerId } }, { team: { customerId } }],
|
userId: subscription.userId,
|
||||||
status: SubscriptionStatus.ACTIVE,
|
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
planId: true,
|
teamId: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const displayName = users[0]?.name || teams[0]?.name || customerId;
|
if (userTeams.length > 0) {
|
||||||
|
const teamIds = userTeams.map((team) => team.teamId);
|
||||||
|
const teamCount = await prisma.document.count({
|
||||||
|
where: {
|
||||||
|
teamId: {
|
||||||
|
in: teamIds,
|
||||||
|
},
|
||||||
|
status: DocumentStatus.COMPLETED,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const creationDates = [
|
signingVolume += teamCount;
|
||||||
...users.map((user) => user.createdAt),
|
}
|
||||||
...teams.map((team) => team.createdAt),
|
}
|
||||||
].filter(Boolean);
|
|
||||||
|
|
||||||
const createdAt =
|
if (subscription.teamId) {
|
||||||
creationDates.length > 0
|
const teamCount = await prisma.document.count({
|
||||||
? new Date(Math.min(...creationDates.map((date) => date.getTime())))
|
where: {
|
||||||
: new Date();
|
teamId: subscription.teamId,
|
||||||
|
status: DocumentStatus.COMPLETED,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
signingVolume += teamCount;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: users[0]?.id || teams[0]?.id || 0,
|
...subscription,
|
||||||
customerId,
|
signingVolume,
|
||||||
name: displayName,
|
|
||||||
signingVolume: userDocumentCount + teamDocumentCount,
|
|
||||||
createdAt,
|
|
||||||
planId: subscription?.planId || '',
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Sort the results by the requested sort criteria
|
// Sort the results
|
||||||
const sortedResults = [...customerData];
|
const sortedResults = [...leaderboardWithVolume].sort((a, b) => {
|
||||||
|
|
||||||
if (sortBy === 'name') {
|
if (sortBy === 'name') {
|
||||||
sortedResults.sort((a, b) => {
|
return sortOrder === 'asc'
|
||||||
return sortOrder === 'desc'
|
? (a.name || '').localeCompare(b.name || '')
|
||||||
? (b.name || '').localeCompare(a.name || '')
|
: (b.name || '').localeCompare(a.name || '');
|
||||||
: (a.name || '').localeCompare(b.name || '');
|
|
||||||
});
|
|
||||||
} else if (sortBy === 'createdAt') {
|
|
||||||
sortedResults.sort((a, b) => {
|
|
||||||
return sortOrder === 'desc'
|
|
||||||
? b.createdAt.getTime() - a.createdAt.getTime()
|
|
||||||
: a.createdAt.getTime() - b.createdAt.getTime();
|
|
||||||
});
|
|
||||||
} else if (sortBy === 'signingVolume') {
|
|
||||||
sortedResults.sort((a, b) => {
|
|
||||||
return sortOrder === 'desc'
|
|
||||||
? b.signingVolume - a.signingVolume
|
|
||||||
: a.signingVolume - b.signingVolume;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sortBy === 'createdAt') {
|
||||||
|
const dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
||||||
|
const dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
||||||
|
return sortOrder === 'asc' ? dateA - dateB : dateB - dateA;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default: sort by signingVolume
|
||||||
|
return sortOrder === 'asc'
|
||||||
|
? a.signingVolume - b.signingVolume
|
||||||
|
: b.signingVolume - a.signingVolume;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply pagination
|
||||||
|
const paginatedResults = sortedResults.slice(skip, skip + validPerPage);
|
||||||
|
|
||||||
|
// Calculate total pages
|
||||||
|
const totalPages = Math.ceil(sortedResults.length / validPerPage);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
leaderboard: sortedResults,
|
leaderboard: paginatedResults,
|
||||||
totalPages: Math.ceil(totalCustomerCount / perPage),
|
totalPages,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user