From c3d52c68e7cc1c10aaabb9e2283cf88df1ed217f Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Fri, 22 Sep 2023 13:27:10 +0000 Subject: [PATCH] feat: add early adopters graph --- .../open/early-adopter-metrics.tsx | 59 +++++++++++++++++++ .../src/app/(marketing)/open/gh-metrics.tsx | 2 +- .../src/app/(marketing)/open/page.tsx | 33 ++++++++++- 3 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 apps/marketing/src/app/(marketing)/open/early-adopter-metrics.tsx diff --git a/apps/marketing/src/app/(marketing)/open/early-adopter-metrics.tsx b/apps/marketing/src/app/(marketing)/open/early-adopter-metrics.tsx new file mode 100644 index 000000000..b84deea37 --- /dev/null +++ b/apps/marketing/src/app/(marketing)/open/early-adopter-metrics.tsx @@ -0,0 +1,59 @@ +'use client'; + +import { HTMLAttributes } from 'react'; + +import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'; + +import { formatMonth } from '@documenso/lib/client-only/format-month'; +import { cn } from '@documenso/ui/lib/utils'; + +import { EarlyAdoptersType } from './page'; + +export type MetricsDataKey = keyof Omit; +export type EarlyAdopterMetricsProps = HTMLAttributes & { + data: EarlyAdoptersType; + metricKey: MetricsDataKey; + title: string; + label: string; + chartHeight?: number; +}; + +export const EarlyAdopterMetrics = ({ + className, + data, + metricKey, + title, + label, + chartHeight = 400, + ...props +}: EarlyAdopterMetricsProps) => { + const formattedData = Object.keys(data) + .map((key) => ({ + month: formatMonth(key), + [metricKey]: data[key][metricKey], + })) + .reverse(); + + return ( +
+

{title}

+ +
+ + + + + [Number(value), label]} + cursor={{ fill: 'hsl(var(--primary) / 10%)' }} + /> + + + +
+
+ ); +}; diff --git a/apps/marketing/src/app/(marketing)/open/gh-metrics.tsx b/apps/marketing/src/app/(marketing)/open/gh-metrics.tsx index 5c0c79716..357c110c2 100644 --- a/apps/marketing/src/app/(marketing)/open/gh-metrics.tsx +++ b/apps/marketing/src/app/(marketing)/open/gh-metrics.tsx @@ -9,7 +9,7 @@ import { cn } from '@documenso/ui/lib/utils'; import { StargazersType } from './page'; -export type MetricsDataKey = 'stars' | 'forks' | 'mergedPRs' | 'openIssues'; +export type MetricsDataKey = keyof StargazersType[string]; export type GithubMetricProps = HTMLAttributes & { data: StargazersType; metricKey: MetricsDataKey; diff --git a/apps/marketing/src/app/(marketing)/open/page.tsx b/apps/marketing/src/app/(marketing)/open/page.tsx index 2d5bc2aa4..1740a65ad 100644 --- a/apps/marketing/src/app/(marketing)/open/page.tsx +++ b/apps/marketing/src/app/(marketing)/open/page.tsx @@ -4,6 +4,7 @@ import { MetricCard } from '~/app/(marketing)/open/metric-card'; import { SalaryBands } from '~/app/(marketing)/open/salary-bands'; import { CapTable } from './cap-table'; +import { EarlyAdopterMetrics } from './early-adopter-metrics'; import { FundingRaised } from './funding-raised'; import { GithubMetric } from './gh-metrics'; import { TeamMembers } from './team-members'; @@ -29,7 +30,16 @@ const ZStargazersLiveResponse = z.record( }), ); +const ZEarlyAdoptersResponse = z.record( + z.object({ + id: z.number(), + time: z.string().datetime(), + earlyAdopters: z.number(), + }), +); + export type StargazersType = z.infer; +export type EarlyAdoptersType = z.infer; // const ZOpenPullRequestsResponse = ZMergedPullRequestsResponse; @@ -65,6 +75,14 @@ export default async function OpenPage() { .then(async (res) => res.json()) .then((res) => ZStargazersLiveResponse.parse(res)); + const EARLY_ADOPTERS_DATA = await fetch('https://stargrazer-live.onrender.com/api/stats/stripe', { + headers: { + accept: 'application/json', + }, + }) + .then(async (res) => res.json()) + .then((res) => ZEarlyAdoptersResponse.parse(res)); + return (
@@ -110,6 +128,15 @@ export default async function OpenPage() { + + +