mirror of
https://github.com/documenso/documenso.git
synced 2025-11-16 01:32:06 +10:00
fix: documents and users count in the table
This commit is contained in:
@ -59,12 +59,12 @@ export const OrganisationInsightsTable = ({
|
|||||||
{
|
{
|
||||||
header: _(msg`Members`),
|
header: _(msg`Members`),
|
||||||
accessorKey: 'memberCount',
|
accessorKey: 'memberCount',
|
||||||
cell: ({ row }) => row.getValue('memberCount'),
|
cell: ({ row }) => Number(row.getValue('memberCount')),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: _(msg`Documents`),
|
header: _(msg`Documents`),
|
||||||
accessorKey: 'documentCount',
|
accessorKey: 'documentCount',
|
||||||
cell: ({ row }) => row.getValue('documentCount'),
|
cell: ({ row }) => Number(row.getValue('documentCount')),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: _(msg`Created`),
|
header: _(msg`Created`),
|
||||||
@ -87,12 +87,12 @@ export const OrganisationInsightsTable = ({
|
|||||||
{
|
{
|
||||||
header: _(msg`Documents Created`),
|
header: _(msg`Documents Created`),
|
||||||
accessorKey: 'documentCount',
|
accessorKey: 'documentCount',
|
||||||
cell: ({ row }) => row.getValue('documentCount'),
|
cell: ({ row }) => Number(row.getValue('documentCount')),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: _(msg`Documents Signed`),
|
header: _(msg`Documents Signed`),
|
||||||
accessorKey: 'signedDocumentCount',
|
accessorKey: 'signedDocumentCount',
|
||||||
cell: ({ row }) => row.getValue('signedDocumentCount'),
|
cell: ({ row }) => Number(row.getValue('signedDocumentCount')),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: _(msg`Joined`),
|
header: _(msg`Joined`),
|
||||||
@ -170,14 +170,12 @@ export const OrganisationInsightsTable = ({
|
|||||||
value: number;
|
value: number;
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
}) => (
|
}) => (
|
||||||
<div className="bg-card rounded-lg border p-4">
|
<div className="bg-card flex items-start gap-x-2 rounded-lg border px-4 py-3">
|
||||||
<div className="flex items-center space-x-2">
|
<Icon className="text-muted-foreground h-4 w-4 items-start" />
|
||||||
<Icon className="text-muted-foreground h-5 w-5" />
|
<div className="-mt-0.5 space-y-1">
|
||||||
<div className="flex-1">
|
<p className="text-muted-foreground text-sm font-medium">{title}</p>
|
||||||
<p className="text-muted-foreground text-sm font-medium">{title}</p>
|
<p className="text-2xl font-bold">{value}</p>
|
||||||
<p className="text-2xl font-bold">{value}</p>
|
{subtitle && <p className="text-muted-foreground text-xs">{subtitle}</p>}
|
||||||
{subtitle && <p className="text-muted-foreground text-xs">{subtitle}</p>}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
|
|
||||||
import { getOrganisationDetailedInsights } from '@documenso/lib/server-only/admin/get-organisation-detailed-insights';
|
import { getOrganisationDetailedInsights } from '@documenso/lib/server-only/admin/get-organisation-detailed-insights';
|
||||||
|
import { getAdminOrganisation } from '@documenso/trpc/server/admin-router/get-admin-organisation';
|
||||||
|
|
||||||
import { OrganisationInsightsTable } from '~/components/tables/organisation-insights-table';
|
import { OrganisationInsightsTable } from '~/components/tables/organisation-insights-table';
|
||||||
|
|
||||||
@ -19,16 +20,20 @@ export async function loader({ params, request }: Route.LoaderArgs) {
|
|||||||
| 'allTime';
|
| 'allTime';
|
||||||
const view = (url.searchParams.get('view') || 'teams') as 'teams' | 'users' | 'documents';
|
const view = (url.searchParams.get('view') || 'teams') as 'teams' | 'users' | 'documents';
|
||||||
|
|
||||||
const insights = await getOrganisationDetailedInsights({
|
const [insights, organisation] = await Promise.all([
|
||||||
organisationId: id,
|
getOrganisationDetailedInsights({
|
||||||
page,
|
organisationId: id,
|
||||||
perPage,
|
page,
|
||||||
dateRange,
|
perPage,
|
||||||
view,
|
dateRange,
|
||||||
});
|
view,
|
||||||
|
}),
|
||||||
|
getAdminOrganisation({ organisationId: id }),
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
organisationId: id,
|
organisationId: id,
|
||||||
|
organisationName: organisation.name,
|
||||||
insights,
|
insights,
|
||||||
page,
|
page,
|
||||||
perPage,
|
perPage,
|
||||||
@ -38,13 +43,13 @@ export async function loader({ params, request }: Route.LoaderArgs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function OrganisationInsights({ loaderData }: Route.ComponentProps) {
|
export default function OrganisationInsights({ loaderData }: Route.ComponentProps) {
|
||||||
const { organisationId, insights, page, perPage, dateRange, view } = loaderData;
|
const { insights, page, perPage, dateRange, view, organisationName } = loaderData;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-4xl font-semibold">
|
<h2 className="text-4xl font-semibold">
|
||||||
<Trans>Organisation Insights</Trans>
|
<Trans>{organisationName}</Trans>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
|
|||||||
@ -122,12 +122,16 @@ async function getTeamInsights(
|
|||||||
.leftJoin('Document as d', (join) =>
|
.leftJoin('Document as d', (join) =>
|
||||||
join.onRef('t.id', '=', 'd.teamId').on('d.deletedAt', 'is', null),
|
join.onRef('t.id', '=', 'd.teamId').on('d.deletedAt', 'is', null),
|
||||||
)
|
)
|
||||||
|
.leftJoin('TeamGroup as tg', 'tg.teamId', 't.id')
|
||||||
|
.leftJoin('OrganisationGroup as og', 'og.id', 'tg.organisationGroupId')
|
||||||
|
.leftJoin('OrganisationGroupMember as ogm', 'ogm.groupId', 'og.id')
|
||||||
|
.leftJoin('OrganisationMember as om', 'om.id', 'ogm.organisationMemberId')
|
||||||
.where('t.organisationId', '=', organisationId)
|
.where('t.organisationId', '=', organisationId)
|
||||||
.select([
|
.select([
|
||||||
't.id as id',
|
't.id as id',
|
||||||
't.name as name',
|
't.name as name',
|
||||||
't.createdAt as createdAt',
|
't.createdAt as createdAt',
|
||||||
sql<number>`0`.as('memberCount'),
|
sql<number>`COUNT(DISTINCT om."userId")`.as('memberCount'),
|
||||||
sql<number>`COUNT(DISTINCT CASE WHEN d.id IS NOT NULL ${dateFilter} THEN d.id END)`.as(
|
sql<number>`COUNT(DISTINCT CASE WHEN d.id IS NOT NULL ${dateFilter} THEN d.id END)`.as(
|
||||||
'documentCount',
|
'documentCount',
|
||||||
),
|
),
|
||||||
@ -163,14 +167,20 @@ async function getUserInsights(
|
|||||||
const usersQuery = kyselyPrisma.$kysely
|
const usersQuery = kyselyPrisma.$kysely
|
||||||
.selectFrom('OrganisationMember as om')
|
.selectFrom('OrganisationMember as om')
|
||||||
.innerJoin('User as u', 'u.id', 'om.userId')
|
.innerJoin('User as u', 'u.id', 'om.userId')
|
||||||
|
.leftJoin('Document as d', (join) =>
|
||||||
|
join.onRef('d.userId', '=', 'u.id').on('d.deletedAt', 'is', null),
|
||||||
|
)
|
||||||
|
.leftJoin('Recipient as r', (join) =>
|
||||||
|
join.onRef('r.email', '=', 'u.email').on('r.signedAt', 'is not', null),
|
||||||
|
)
|
||||||
.where('om.organisationId', '=', organisationId)
|
.where('om.organisationId', '=', organisationId)
|
||||||
.select([
|
.select([
|
||||||
'u.id as id',
|
'u.id as id',
|
||||||
'u.name as name',
|
'u.name as name',
|
||||||
'u.email as email',
|
'u.email as email',
|
||||||
'u.createdAt as createdAt',
|
'u.createdAt as createdAt',
|
||||||
sql<number>`0`.as('documentCount'),
|
sql<number>`COUNT(DISTINCT d.id)`.as('documentCount'),
|
||||||
sql<number>`0`.as('signedDocumentCount'),
|
sql<number>`COUNT(DISTINCT r.id)`.as('signedDocumentCount'),
|
||||||
])
|
])
|
||||||
.groupBy(['u.id', 'u.name', 'u.email', 'u.createdAt'])
|
.groupBy(['u.id', 'u.name', 'u.email', 'u.createdAt'])
|
||||||
.orderBy('u.createdAt', 'desc')
|
.orderBy('u.createdAt', 'desc')
|
||||||
|
|||||||
Reference in New Issue
Block a user