diff --git a/apps/marketing/src/app/(marketing)/open/monthly-completed-documents-chart copy.tsx b/apps/marketing/src/app/(marketing)/open/monthly-completed-documents-chart copy.tsx
new file mode 100644
index 000000000..ce438145b
--- /dev/null
+++ b/apps/marketing/src/app/(marketing)/open/monthly-completed-documents-chart copy.tsx
@@ -0,0 +1,57 @@
+'use client';
+
+import { DateTime } from 'luxon';
+import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
+
+import type { GetUserMonthlyGrowthResult } from '@documenso/lib/server-only/user/get-user-monthly-growth';
+import { cn } from '@documenso/ui/lib/utils';
+
+export type MonthlyCompletedDocumentsChartProps = {
+ className?: string;
+ data: GetUserMonthlyGrowthResult;
+};
+
+export const MonthlyCompletedDocumentsChart = ({
+ className,
+ data,
+}: MonthlyCompletedDocumentsChartProps) => {
+ const formattedData = [...data].reverse().map(({ month, cume_count: count }) => {
+ return {
+ month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLLL'),
+ count: Number(count),
+ };
+ });
+
+ return (
+
+
+
Completed Documents per Month
+
+
+
+
+
+
+
+
+ [Number(value).toLocaleString('en-US'), 'Total Users']}
+ cursor={{ fill: 'hsl(var(--primary) / 10%)' }}
+ />
+
+
+
+
+
+
+ );
+};
diff --git a/apps/marketing/src/app/(marketing)/open/page.tsx b/apps/marketing/src/app/(marketing)/open/page.tsx
index 10ab71aa7..4f2b0d857 100644
--- a/apps/marketing/src/app/(marketing)/open/page.tsx
+++ b/apps/marketing/src/app/(marketing)/open/page.tsx
@@ -2,6 +2,7 @@ import type { Metadata } from 'next';
import { z } from 'zod';
+import { getCompletedDocumentsMonthly } from '@documenso/lib/server-only/user/get-monthly-completed-document';
import { getUserMonthlyGrowth } from '@documenso/lib/server-only/user/get-user-monthly-growth';
import { FUNDING_RAISED } from '~/app/(marketing)/open/data';
@@ -12,6 +13,7 @@ import { CallToAction } from '~/components/(marketing)/call-to-action';
import { BarMetric } from './bar-metrics';
import { CapTable } from './cap-table';
import { FundingRaised } from './funding-raised';
+import { MonthlyCompletedDocumentsChart } from './monthly-completed-documents-chart copy';
import { MonthlyNewUsersChart } from './monthly-new-users-chart';
import { MonthlyTotalUsersChart } from './monthly-total-users-chart';
import { TeamMembers } from './team-members';
@@ -140,6 +142,7 @@ export default async function OpenPage() {
]);
const MONTHLY_USERS = await getUserMonthlyGrowth();
+ const MONTHLY_COMPLETED_DOCUMENTS = await getCompletedDocumentsMonthly();
return (
@@ -161,7 +164,7 @@ export default async function OpenPage() {
-
+
+
+
Finances
+
+
-
- data={EARLY_ADOPTERS_DATA}
- metricKey="earlyAdopters"
- title="Early Adopters"
- label="Early Adopters"
- className="col-span-12 lg:col-span-6"
- extraInfo={}
- />
-
+ Community
+
data={STARGAZERS_DATA}
metricKey="stars"
@@ -237,22 +237,39 @@ export default async function OpenPage() {
className="col-span-12 lg:col-span-6"
/>
+
+
+
+ Growth
+
+
+ data={EARLY_ADOPTERS_DATA}
+ metricKey="earlyAdopters"
+ title="Early Adopters"
+ label="Early Adopters"
+ className="col-span-12 lg:col-span-6"
+ extraInfo={}
+ />
+
-
-
-
-
Where's the rest?
-
-
- We're still working on getting all our metrics together. We'll update this page as
- soon as we have more to share.
-
-
+
+
+
Is there more?
+
+
+ This page is evolving as we learn what makes a great signing company. We'll update it when
+ we have more to share.
+
+
+
);
diff --git a/apps/marketing/src/app/(marketing)/open/team-members.tsx b/apps/marketing/src/app/(marketing)/open/team-members.tsx
index a79fcd182..288d48a0b 100644
--- a/apps/marketing/src/app/(marketing)/open/team-members.tsx
+++ b/apps/marketing/src/app/(marketing)/open/team-members.tsx
@@ -1,4 +1,4 @@
-import { HTMLAttributes } from 'react';
+import type { HTMLAttributes } from 'react';
import { cn } from '@documenso/ui/lib/utils';
import {
diff --git a/packages/lib/server-only/user/get-monthly-completed-document.ts b/packages/lib/server-only/user/get-monthly-completed-document.ts
new file mode 100644
index 000000000..ef1bcd4b9
--- /dev/null
+++ b/packages/lib/server-only/user/get-monthly-completed-document.ts
@@ -0,0 +1,35 @@
+import { DateTime } from 'luxon';
+
+import { prisma } from '@documenso/prisma';
+
+export type GetCompletedDocumentsMonthlyResult = Array<{
+ month: string;
+ count: number;
+ cume_count: number;
+}>;
+
+type GetCompletedDocumentsMonthlyQueryResult = Array<{
+ month: Date;
+ count: bigint;
+ cume_count: bigint;
+}>;
+
+export const getCompletedDocumentsMonthly = async () => {
+ const result = await prisma.$queryRaw`
+ SELECT
+ DATE_TRUNC('month', "completedAt") AS "month",
+ COUNT("id") as "count",
+ SUM(COUNT("id")) OVER (ORDER BY DATE_TRUNC('month', "completedAt")) as "cume_count"
+ FROM "Document"
+ WHERE "status" = 'COMPLETED'
+ GROUP BY "month"
+ ORDER BY "month" DESC
+ LIMIT 12
+ `;
+
+ return result.map((row) => ({
+ month: DateTime.fromJSDate(row.month).toFormat('yyyy-MM'),
+ count: Number(row.count),
+ cume_count: Number(row.cume_count),
+ }));
+};
diff --git a/packages/prisma/seed/pr-711-deletion-of-documents.ts b/packages/prisma/seed/pr-711-deletion-of-documents.ts
index 5365ecf47..d2706b734 100644
--- a/packages/prisma/seed/pr-711-deletion-of-documents.ts
+++ b/packages/prisma/seed/pr-711-deletion-of-documents.ts
@@ -182,6 +182,7 @@ const createCompletedDocument = async (sender: User, recipients: User[]) => {
title: `[${PULL_REQUEST_NUMBER}] Document 1 - Completed`,
status: DocumentStatus.COMPLETED,
documentDataId: documentData.id,
+ completedAt: new Date(),
userId: sender.id,
},
});