From 7615c9d2fa8e064e005c904c6a65e2020ec9f5af Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Fri, 5 Apr 2024 17:49:32 +0000 Subject: [PATCH 01/14] feat: add chat to admin dashboard --- .../src/app/(dashboard)/admin/stats/page.tsx | 59 +++++++++++++-- .../stats/user-with-document-cummulative.tsx | 69 +++++++++++++++++ .../admin/stats/user-with-document.tsx | 64 ++++++++++++++++ .../lib/server-only/admin/get-users-stats.ts | 74 ++++++++++++++++++- packages/ui/styles/theme.css | 4 + 5 files changed, 264 insertions(+), 6 deletions(-) create mode 100644 apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx create mode 100644 apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx diff --git a/apps/web/src/app/(dashboard)/admin/stats/page.tsx b/apps/web/src/app/(dashboard)/admin/stats/page.tsx index 43fe4be01..204461f03 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/page.tsx @@ -14,18 +14,35 @@ import { import { getDocumentStats } from '@documenso/lib/server-only/admin/get-documents-stats'; import { getRecipientsStats } from '@documenso/lib/server-only/admin/get-recipients-stats'; import { + getUserWithAtLeastOneDocumentPerMonth, + getUserWithAtLeastOneDocumentSignedPerMonth, + getUserWithSignedDocumentMonthlyGrowth, getUsersCount, getUsersWithSubscriptionsCount, } from '@documenso/lib/server-only/admin/get-users-stats'; import { CardMetric } from '~/components/(dashboard)/metric-card/metric-card'; +import { UserWithDocumentChart } from './user-with-document'; +import { UserWithDocumentCummulativeChart } from './user-with-document-cummulative'; + export default async function AdminStatsPage() { - const [usersCount, usersWithSubscriptionsCount, docStats, recipientStats] = await Promise.all([ + const [ + usersCount, + usersWithSubscriptionsCount, + docStats, + recipientStats, + userWithAtLeastOneDocumentPerMonth, + userWithAtLeastOneDocumentSignedPerMonth, + MONTHLY_USERS_SIGNED, + ] = await Promise.all([ getUsersCount(), getUsersWithSubscriptionsCount(), getDocumentStats(), getRecipientsStats(), + getUserWithAtLeastOneDocumentPerMonth(), + getUserWithAtLeastOneDocumentSignedPerMonth(), + getUserWithSignedDocumentMonthlyGrowth(), ]); return ( @@ -43,12 +60,30 @@ export default async function AdminStatsPage() { -
+ {/* TODO: remove grid and see something */} +
+
+

User metrics

+ +
+ + +
+
+

Document metrics

-
- +
+ {/* */} @@ -58,7 +93,7 @@ export default async function AdminStatsPage() {

Recipients metrics

-
+
+ +
+

User Charts

+ + + + +
); } diff --git a/apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx b/apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx new file mode 100644 index 000000000..a9c2c7038 --- /dev/null +++ b/apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx @@ -0,0 +1,69 @@ +'use client'; + +import { DateTime } from 'luxon'; +import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'; + +import type { GetUserWithDocumentMonthlyGrowth } from '@documenso/lib/server-only/admin/get-users-stats'; + +export type UserWithDocumentCummulativeChartProps = { + className?: string; + data: GetUserWithDocumentMonthlyGrowth; +}; + +export const UserWithDocumentCummulativeChart = ({ + className, + data, +}: UserWithDocumentCummulativeChartProps) => { + const formattedData = [...data] + .reverse() + .map(({ month, cume_count: count, cume_signed_count: signed_count }) => { + return { + month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLLL'), + count: Number(count), + signed_count: Number(signed_count), + }; + }); + + return ( +
+
+
+

Total Activity

+
+ + + + + + + [ + Number(value).toLocaleString('en-US'), + name === 'count' ? 'User with document' : 'Users with signed document', + ]} + cursor={{ fill: 'hsl(var(--primary) / 10%)' }} + /> + + + + + +
+
+ ); +}; diff --git a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx new file mode 100644 index 000000000..98858a386 --- /dev/null +++ b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx @@ -0,0 +1,64 @@ +'use client'; + +import { DateTime } from 'luxon'; +import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'; + +import type { GetUserWithDocumentMonthlyGrowth } from '@documenso/lib/server-only/admin/get-users-stats'; + +export type UserWithDocumentChartProps = { + className?: string; + data: GetUserWithDocumentMonthlyGrowth; +}; + +export const UserWithDocumentChart = ({ className, data }: UserWithDocumentChartProps) => { + const formattedData = [...data].reverse().map(({ month, count, signed_count }) => { + return { + month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLLL'), + count: Number(count), + signed_count: Number(signed_count), + }; + }); + + return ( +
+
+
+

Total Activity

+
+ + + + + + + [ + Number(value).toLocaleString('en-US'), + name === 'count' ? 'User with document' : 'Users with signed document', + ]} + cursor={{ fill: 'hsl(var(--primary) / 10%)' }} + /> + + + + + +
+
+ ); +}; diff --git a/packages/lib/server-only/admin/get-users-stats.ts b/packages/lib/server-only/admin/get-users-stats.ts index 09892171a..cf4d0b540 100644 --- a/packages/lib/server-only/admin/get-users-stats.ts +++ b/packages/lib/server-only/admin/get-users-stats.ts @@ -1,5 +1,7 @@ +import { DateTime } from 'luxon'; + import { prisma } from '@documenso/prisma'; -import { SubscriptionStatus } from '@documenso/prisma/client'; +import { DocumentStatus, SubscriptionStatus } from '@documenso/prisma/client'; export const getUsersCount = async () => { return await prisma.user.count(); @@ -16,3 +18,73 @@ export const getUsersWithSubscriptionsCount = async () => { }, }); }; + +export const getUserWithAtLeastOneDocumentPerMonth = async () => { + return await prisma.user.count({ + where: { + Document: { + some: { + createdAt: { + gte: new Date(new Date().setMonth(new Date().getMonth() - 1)), + }, + }, + }, + }, + }); +}; + +export const getUserWithAtLeastOneDocumentSignedPerMonth = async () => { + return await prisma.user.count({ + where: { + Document: { + some: { + status: { + equals: DocumentStatus.COMPLETED, + }, + createdAt: { + gte: new Date(new Date().setMonth(new Date().getMonth() - 1)), + }, + }, + }, + }, + }); +}; + +export type GetUserWithDocumentMonthlyGrowth = Array<{ + month: string; + count: number; + cume_count: number; + signed_count: number; + cume_signed_count: number; +}>; + +type GetUserWithDocumentMonthlyGrowthQueryResult = Array<{ + month: Date; + count: bigint; + cume_count: bigint; + signed_count: bigint; + cume_signed_count: bigint; +}>; + +export const getUserWithSignedDocumentMonthlyGrowth = async () => { + const result = await prisma.$queryRaw` + SELECT + DATE_TRUNC('month', "Document"."createdAt") AS "month", + COUNT(DISTINCT "Document"."userId") as "count", + SUM(COUNT(DISTINCT "Document"."userId")) OVER (ORDER BY DATE_TRUNC('month', "Document"."createdAt")) as "cume_count", + COUNT(DISTINCT CASE WHEN "Document"."status" = 'COMPLETED' THEN "Document"."userId" END) as "signed_count", + SUM(COUNT(DISTINCT CASE WHEN "Document"."status" = 'COMPLETED' THEN "Document"."userId" END)) OVER (ORDER BY DATE_TRUNC('month', "Document"."createdAt")) as "cume_signed_count" + FROM "Document" + 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), + signed_count: Number(row.signed_count), + cume_signed_count: Number(row.cume_signed_count), + })); +}; diff --git a/packages/ui/styles/theme.css b/packages/ui/styles/theme.css index cb2d9d5c5..1271159d5 100644 --- a/packages/ui/styles/theme.css +++ b/packages/ui/styles/theme.css @@ -44,6 +44,8 @@ --radius: 0.5rem; --warning: 54 96% 45%; + + --gold: 47.9 95.8% 53.1%; } .dark { @@ -83,6 +85,8 @@ --radius: 0.5rem; --warning: 54 96% 45%; + + --gold: 47.9 95.8% 53.1%; } } From fdf4d03c1411ac3c9f3741a4dcb7204482c8085d Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Fri, 5 Apr 2024 17:54:36 +0000 Subject: [PATCH 02/14] fix: grid on mobile --- apps/web/src/app/(dashboard)/admin/stats/page.tsx | 6 +++--- .../admin/stats/user-with-document-cummulative.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/src/app/(dashboard)/admin/stats/page.tsx b/apps/web/src/app/(dashboard)/admin/stats/page.tsx index 204461f03..eb17a405f 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/page.tsx @@ -65,7 +65,7 @@ export default async function AdminStatsPage() {

User metrics

-
+

Document metrics

-
+
{/* */} @@ -93,7 +93,7 @@ export default async function AdminStatsPage() {

Recipients metrics

-
+
-

Total Activity

+

Total Activity (Cummulative)

From 32348dd6f1dd753127388fef957065f3921edd69 Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Mon, 8 Apr 2024 17:26:25 +0000 Subject: [PATCH 03/14] fix: pr review changes --- .../web/src/app/(dashboard)/admin/stats/page.tsx | 16 ++++------------ .../stats/user-with-document-cummulative.tsx | 2 +- .../admin/stats/user-with-document.tsx | 2 +- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/apps/web/src/app/(dashboard)/admin/stats/page.tsx b/apps/web/src/app/(dashboard)/admin/stats/page.tsx index eb17a405f..cb2ead970 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/page.tsx @@ -60,7 +60,6 @@ export default async function AdminStatsPage() {
- {/* TODO: remove grid and see something */}

User metrics

@@ -68,12 +67,12 @@ export default async function AdminStatsPage() {
@@ -83,7 +82,6 @@ export default async function AdminStatsPage() {

Document metrics

- {/* */} @@ -109,15 +107,9 @@ export default async function AdminStatsPage() {

User Charts

- + - +
); diff --git a/apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx b/apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx index cfb94e1f7..96d2fa775 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx @@ -18,7 +18,7 @@ export const UserWithDocumentCummulativeChart = ({ .reverse() .map(({ month, cume_count: count, cume_signed_count: signed_count }) => { return { - month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLLL'), + month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLL'), count: Number(count), signed_count: Number(signed_count), }; diff --git a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx index 98858a386..5ecb934f1 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx @@ -13,7 +13,7 @@ export type UserWithDocumentChartProps = { export const UserWithDocumentChart = ({ className, data }: UserWithDocumentChartProps) => { const formattedData = [...data].reverse().map(({ month, count, signed_count }) => { return { - month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLLL'), + month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLL'), count: Number(count), signed_count: Number(signed_count), }; From 50b57d5aa50eac0100d221bd03e1616c7d652b92 Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Tue, 7 May 2024 09:35:59 +0000 Subject: [PATCH 04/14] fix: minor changes based on review --- apps/web/src/app/(dashboard)/admin/stats/page.tsx | 2 +- .../src/app/(dashboard)/admin/stats/user-with-document.tsx | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/(dashboard)/admin/stats/page.tsx b/apps/web/src/app/(dashboard)/admin/stats/page.tsx index cb2ead970..04fa9c0ca 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/page.tsx @@ -72,7 +72,7 @@ export default async function AdminStatsPage() { />
diff --git a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx index 5ecb934f1..1afc55908 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx @@ -37,7 +37,10 @@ export const UserWithDocumentChart = ({ className, data }: UserWithDocumentChart }} formatter={(value, name) => [ Number(value).toLocaleString('en-US'), - name === 'count' ? 'User with document' : 'Users with signed document', + { + count: 'User with document', + signed_count: 'Users with signed document', + }[name], ]} cursor={{ fill: 'hsl(var(--primary) / 10%)' }} /> From 95a94d4fc1f0264ded805b6317d9b0dab328aa1d Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Tue, 21 May 2024 09:28:23 +0000 Subject: [PATCH 05/14] chore: use single chart graphs --- .../src/app/(dashboard)/admin/stats/page.tsx | 33 ++++++--- .../stats/user-with-document-cummulative.tsx | 69 ------------------- .../admin/stats/user-with-document.tsx | 63 +++++++++-------- .../lib/server-only/admin/get-users-stats.ts | 2 +- 4 files changed, 62 insertions(+), 105 deletions(-) delete mode 100644 apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx diff --git a/apps/web/src/app/(dashboard)/admin/stats/page.tsx b/apps/web/src/app/(dashboard)/admin/stats/page.tsx index 04fa9c0ca..dd246d02e 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/page.tsx @@ -24,7 +24,6 @@ import { import { CardMetric } from '~/components/(dashboard)/metric-card/metric-card'; import { UserWithDocumentChart } from './user-with-document'; -import { UserWithDocumentCummulativeChart } from './user-with-document-cummulative'; export default async function AdminStatsPage() { const [ @@ -67,12 +66,12 @@ export default async function AdminStatsPage() {
@@ -105,11 +104,29 @@ export default async function AdminStatsPage() {
-

User Charts

- - - - +

Charts

+
+ + + + +
); diff --git a/apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx b/apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx deleted file mode 100644 index 96d2fa775..000000000 --- a/apps/web/src/app/(dashboard)/admin/stats/user-with-document-cummulative.tsx +++ /dev/null @@ -1,69 +0,0 @@ -'use client'; - -import { DateTime } from 'luxon'; -import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'; - -import type { GetUserWithDocumentMonthlyGrowth } from '@documenso/lib/server-only/admin/get-users-stats'; - -export type UserWithDocumentCummulativeChartProps = { - className?: string; - data: GetUserWithDocumentMonthlyGrowth; -}; - -export const UserWithDocumentCummulativeChart = ({ - className, - data, -}: UserWithDocumentCummulativeChartProps) => { - const formattedData = [...data] - .reverse() - .map(({ month, cume_count: count, cume_signed_count: signed_count }) => { - return { - month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLL'), - count: Number(count), - signed_count: Number(signed_count), - }; - }); - - return ( -
-
-
-

Total Activity (Cummulative)

-
- - - - - - - [ - Number(value).toLocaleString('en-US'), - name === 'count' ? 'User with document' : 'Users with signed document', - ]} - cursor={{ fill: 'hsl(var(--primary) / 10%)' }} - /> - - - - - -
-
- ); -}; diff --git a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx index 1afc55908..8ffc9db8c 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx @@ -7,27 +7,49 @@ import type { GetUserWithDocumentMonthlyGrowth } from '@documenso/lib/server-onl export type UserWithDocumentChartProps = { className?: string; + title: string; data: GetUserWithDocumentMonthlyGrowth; + cummulative?: boolean; + completed?: boolean; }; -export const UserWithDocumentChart = ({ className, data }: UserWithDocumentChartProps) => { - const formattedData = [...data].reverse().map(({ month, count, signed_count }) => { - return { - month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLL'), - count: Number(count), - signed_count: Number(signed_count), - }; - }); +export const UserWithDocumentChart = ({ + className, + data, + title, + cummulative = false, + completed = false, +}: UserWithDocumentChartProps) => { + const formattedData = (data: GetUserWithDocumentMonthlyGrowth, completed: boolean) => { + return [...data] + .reverse() + .map(({ month, count, cume_count, signed_count, cume_signed_count }) => { + const formattedMonth = DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLL'); + if (completed) { + return { + month: formattedMonth, + count: Number(signed_count), + cummulative: Number(cume_signed_count), + }; + } else { + return { + month: formattedMonth, + count: Number(count), + cummulative: Number(cume_count), + }; + } + }); + }; return (
-
-

Total Activity

+
+

{title}

- + @@ -35,29 +57,16 @@ export const UserWithDocumentChart = ({ className, data }: UserWithDocumentChart labelStyle={{ color: 'hsl(var(--primary-foreground))', }} - formatter={(value, name) => [ - Number(value).toLocaleString('en-US'), - { - count: 'User with document', - signed_count: 'Users with signed document', - }[name], - ]} + formatter={(value) => [Number(value).toLocaleString('en-US'), 'Documents']} cursor={{ fill: 'hsl(var(--primary) / 10%)' }} /> - diff --git a/packages/lib/server-only/admin/get-users-stats.ts b/packages/lib/server-only/admin/get-users-stats.ts index cf4d0b540..f79b4b66d 100644 --- a/packages/lib/server-only/admin/get-users-stats.ts +++ b/packages/lib/server-only/admin/get-users-stats.ts @@ -41,7 +41,7 @@ export const getUserWithAtLeastOneDocumentSignedPerMonth = async () => { status: { equals: DocumentStatus.COMPLETED, }, - createdAt: { + completedAt: { gte: new Date(new Date().setMonth(new Date().getMonth() - 1)), }, }, From c1449e01b188a0efafbeb1b4823244deda21540f Mon Sep 17 00:00:00 2001 From: Timur Ercan Date: Tue, 21 May 2024 14:07:27 +0200 Subject: [PATCH 06/14] chore: remove cummulative for clarity --- apps/web/src/app/(dashboard)/admin/stats/page.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/apps/web/src/app/(dashboard)/admin/stats/page.tsx b/apps/web/src/app/(dashboard)/admin/stats/page.tsx index dd246d02e..ae39051f3 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/page.tsx @@ -110,22 +110,11 @@ export default async function AdminStatsPage() { data={MONTHLY_USERS_SIGNED} title="Monthly users who created documents" /> - -
From 39e7eb0568eba5348c6c8c12147ee05b5e678b55 Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Tue, 21 May 2024 22:44:44 +0000 Subject: [PATCH 07/14] fix: remove cummulative --- .../admin/stats/user-with-document.tsx | 36 ++++++++----------- .../lib/server-only/admin/get-users-stats.ts | 10 +----- 2 files changed, 16 insertions(+), 30 deletions(-) diff --git a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx index 8ffc9db8c..82dd93566 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx @@ -9,7 +9,6 @@ export type UserWithDocumentChartProps = { className?: string; title: string; data: GetUserWithDocumentMonthlyGrowth; - cummulative?: boolean; completed?: boolean; }; @@ -17,28 +16,23 @@ export const UserWithDocumentChart = ({ className, data, title, - cummulative = false, completed = false, }: UserWithDocumentChartProps) => { const formattedData = (data: GetUserWithDocumentMonthlyGrowth, completed: boolean) => { - return [...data] - .reverse() - .map(({ month, count, cume_count, signed_count, cume_signed_count }) => { - const formattedMonth = DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLL'); - if (completed) { - return { - month: formattedMonth, - count: Number(signed_count), - cummulative: Number(cume_signed_count), - }; - } else { - return { - month: formattedMonth, - count: Number(count), - cummulative: Number(cume_count), - }; - } - }); + return [...data].reverse().map(({ month, count, signed_count }) => { + const formattedMonth = DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLL'); + if (completed) { + return { + month: formattedMonth, + count: Number(signed_count), + }; + } else { + return { + month: formattedMonth, + count: Number(count), + }; + } + }); }; return ( @@ -62,7 +56,7 @@ export const UserWithDocumentChart = ({ /> { export type GetUserWithDocumentMonthlyGrowth = Array<{ month: string; count: number; - cume_count: number; signed_count: number; - cume_signed_count: number; }>; type GetUserWithDocumentMonthlyGrowthQueryResult = Array<{ month: Date; count: bigint; - cume_count: bigint; signed_count: bigint; - cume_signed_count: bigint; }>; export const getUserWithSignedDocumentMonthlyGrowth = async () => { @@ -71,9 +67,7 @@ export const getUserWithSignedDocumentMonthlyGrowth = async () => { SELECT DATE_TRUNC('month', "Document"."createdAt") AS "month", COUNT(DISTINCT "Document"."userId") as "count", - SUM(COUNT(DISTINCT "Document"."userId")) OVER (ORDER BY DATE_TRUNC('month', "Document"."createdAt")) as "cume_count", - COUNT(DISTINCT CASE WHEN "Document"."status" = 'COMPLETED' THEN "Document"."userId" END) as "signed_count", - SUM(COUNT(DISTINCT CASE WHEN "Document"."status" = 'COMPLETED' THEN "Document"."userId" END)) OVER (ORDER BY DATE_TRUNC('month', "Document"."createdAt")) as "cume_signed_count" + COUNT(DISTINCT CASE WHEN "Document"."status" = 'COMPLETED' THEN "Document"."userId" END) as "signed_count" FROM "Document" GROUP BY "month" ORDER BY "month" DESC @@ -83,8 +77,6 @@ export const getUserWithSignedDocumentMonthlyGrowth = async () => { return result.map((row) => ({ month: DateTime.fromJSDate(row.month).toFormat('yyyy-MM'), count: Number(row.count), - cume_count: Number(row.cume_count), signed_count: Number(row.signed_count), - cume_signed_count: Number(row.cume_signed_count), })); }; From 72d0a1b69ccedbeb110fce48b4f98318511232e7 Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Tue, 21 May 2024 22:53:31 +0000 Subject: [PATCH 08/14] chore: custom tooltip --- apps/web/src/app/(dashboard)/admin/stats/page.tsx | 7 ++----- .../src/app/(dashboard)/admin/stats/user-with-document.tsx | 6 ++++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/web/src/app/(dashboard)/admin/stats/page.tsx b/apps/web/src/app/(dashboard)/admin/stats/page.tsx index ae39051f3..5037729f5 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/page.tsx @@ -106,14 +106,11 @@ export default async function AdminStatsPage() {

Charts

- +
diff --git a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx index 82dd93566..1dfdbb269 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx @@ -10,6 +10,7 @@ export type UserWithDocumentChartProps = { title: string; data: GetUserWithDocumentMonthlyGrowth; completed?: boolean; + tooltip?: string; }; export const UserWithDocumentChart = ({ @@ -17,6 +18,7 @@ export const UserWithDocumentChart = ({ data, title, completed = false, + tooltip, }: UserWithDocumentChartProps) => { const formattedData = (data: GetUserWithDocumentMonthlyGrowth, completed: boolean) => { return [...data].reverse().map(({ month, count, signed_count }) => { @@ -51,7 +53,7 @@ export const UserWithDocumentChart = ({ labelStyle={{ color: 'hsl(var(--primary-foreground))', }} - formatter={(value) => [Number(value).toLocaleString('en-US'), 'Documents']} + formatter={(value) => [Number(value).toLocaleString('en-US'), tooltip]} cursor={{ fill: 'hsl(var(--primary) / 10%)' }} /> @@ -60,7 +62,7 @@ export const UserWithDocumentChart = ({ fill="hsl(var(--primary))" radius={[4, 4, 0, 0]} maxBarSize={60} - label="Documents" + label={tooltip} /> From 3b2d184f05485f9dcc635c37a9ee63f05301a954 Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Wed, 29 May 2024 08:26:58 +0000 Subject: [PATCH 09/14] chore: custom tooltip since it's hiding values under other charts --- .../src/app/(dashboard)/admin/stats/page.tsx | 7 ++++- .../admin/stats/user-with-document.tsx | 27 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/apps/web/src/app/(dashboard)/admin/stats/page.tsx b/apps/web/src/app/(dashboard)/admin/stats/page.tsx index 5037729f5..a6749a94e 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/page.tsx @@ -106,11 +106,16 @@ export default async function AdminStatsPage() {

Charts

- +
diff --git a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx index 1dfdbb269..cf9f11e23 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/user-with-document.tsx @@ -2,6 +2,8 @@ import { DateTime } from 'luxon'; import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'; +import type { TooltipProps } from 'recharts'; +import type { NameType, ValueType } from 'recharts/types/component/DefaultTooltipContent'; import type { GetUserWithDocumentMonthlyGrowth } from '@documenso/lib/server-only/admin/get-users-stats'; @@ -13,6 +15,27 @@ export type UserWithDocumentChartProps = { tooltip?: string; }; +const CustomTooltip = ({ + active, + payload, + label, + tooltip, +}: TooltipProps & { tooltip?: string }) => { + if (active && payload && payload.length) { + return ( +
+

{label}

+

+ {`${tooltip} : `} + {payload[0].value} +

+
+ ); + } + + return null; +}; + export const UserWithDocumentChart = ({ className, data, @@ -45,15 +68,15 @@ export const UserWithDocumentChart = ({
- + } labelStyle={{ color: 'hsl(var(--primary-foreground))', }} - formatter={(value) => [Number(value).toLocaleString('en-US'), tooltip]} cursor={{ fill: 'hsl(var(--primary) / 10%)' }} /> From 1bbfd9d0f3d8fcb8a882f4a6bd2755d27b6855bc Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Thu, 13 Jun 2024 05:46:34 +0000 Subject: [PATCH 10/14] fix: remove redundant cards --- .../src/app/(dashboard)/admin/stats/page.tsx | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/apps/web/src/app/(dashboard)/admin/stats/page.tsx b/apps/web/src/app/(dashboard)/admin/stats/page.tsx index a6749a94e..bcce0b608 100644 --- a/apps/web/src/app/(dashboard)/admin/stats/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/stats/page.tsx @@ -60,23 +60,6 @@ export default async function AdminStatsPage() {
-
-

User metrics

- -
- - -
-
-

Document metrics

From b6a2fe88cb081216e0947cca4ec92e07a572bab2 Mon Sep 17 00:00:00 2001 From: Timur Ercan Date: Mon, 24 Jun 2024 17:34:52 +0200 Subject: [PATCH 11/14] chore: add direct link video --- apps/marketing/src/components/(marketing)/carousel.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/marketing/src/components/(marketing)/carousel.tsx b/apps/marketing/src/components/(marketing)/carousel.tsx index 307d4a4f0..f3d903809 100644 --- a/apps/marketing/src/components/(marketing)/carousel.tsx +++ b/apps/marketing/src/components/(marketing)/carousel.tsx @@ -30,6 +30,12 @@ const SLIDES = [ srcLight: 'https://github.com/documenso/design/raw/main/marketing/zapier.webm', srcDark: 'https://github.com/documenso/design/raw/main/marketing/dark/zapier.webm', }, + { + label: 'Direct Link', + type: 'video', + srcLight: 'https://github.com/documenso/design/raw/main/marketing/direct-links.webm', + srcDark: 'https://github.com/documenso/design/raw/main/marketing/dark/direct-links.webm', + }, { label: 'Webhooks', type: 'video', From 817103ebba3a32c8423f185f1e067480b2af28fe Mon Sep 17 00:00:00 2001 From: Timur Ercan Date: Tue, 25 Jun 2024 15:42:25 +0200 Subject: [PATCH 12/14] Update README.md chore: add shiny badges --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d6a5053f4..1ae2362bf 100644 --- a/README.md +++ b/README.md @@ -73,10 +73,22 @@ Contact us if you are interested in our Enterprise plan for large organizations Book us with Cal.com ## Tech Stack +

+ TypeScript + NextJS + Made with Prisma + + + + + + +

+ - [Typescript](https://www.typescriptlang.org/) - Language - [Next.js](https://nextjs.org/) - Framework -- [Prisma](https://www.prisma.io/) - ORM +- [Prisma](https://www.prisma.io/) - ORM - [Tailwind](https://tailwindcss.com/) - CSS - [shadcn/ui](https://ui.shadcn.com/) - Component Library - [NextAuth.js](https://next-auth.js.org/) - Authentication From bbd68f37c241a3720059534a9b6c4fcff36afb61 Mon Sep 17 00:00:00 2001 From: Timur Ercan Date: Tue, 25 Jun 2024 15:43:28 +0200 Subject: [PATCH 13/14] Update README.md chore alt --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ae2362bf..16738923c 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ Contact us if you are interested in our Enterprise plan for large organizations TypeScript NextJS Made with Prisma - + Tailwind CSS From 7e065764ec130ba51726d81d9df40f1baa6ab983 Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Tue, 25 Jun 2024 15:10:58 +0000 Subject: [PATCH 14/14] chore: use luxon for dates --- packages/lib/server-only/admin/get-users-stats.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lib/server-only/admin/get-users-stats.ts b/packages/lib/server-only/admin/get-users-stats.ts index 089591954..0f4a2f0b4 100644 --- a/packages/lib/server-only/admin/get-users-stats.ts +++ b/packages/lib/server-only/admin/get-users-stats.ts @@ -25,7 +25,7 @@ export const getUserWithAtLeastOneDocumentPerMonth = async () => { Document: { some: { createdAt: { - gte: new Date(new Date().setMonth(new Date().getMonth() - 1)), + gte: DateTime.now().minus({ months: 1 }).toJSDate(), }, }, }, @@ -42,7 +42,7 @@ export const getUserWithAtLeastOneDocumentSignedPerMonth = async () => { equals: DocumentStatus.COMPLETED, }, completedAt: { - gte: new Date(new Date().setMonth(new Date().getMonth() - 1)), + gte: DateTime.now().minus({ months: 1 }).toJSDate(), }, }, },