Skip to content

Commit

Permalink
feat(web): add openpanel tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
cstrnt committed Sep 3, 2024
1 parent b4bdd8e commit 12c5e19
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 2 deletions.
1 change: 1 addition & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@next-auth/prisma-adapter": "1.0.5",
"@next/mdx": "14.0.4",
"@octokit/webhooks": "^13.3.0",
"@openpanel/nextjs": "^1.0.3",
"@prisma/client": "5.19.0",
"@radix-ui/react-avatar": "^1.0.3",
"@radix-ui/react-dialog": "^1.0.5",
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/env/schema.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const serverSchema = z.object({
),
GITHUB_APP_WEBHOOK_SECRET: z.string().optional(),
OPENAI_API_KEY: z.string().optional(),
OPENPANEL_CLIENT_SECRET: z.string().optional(),
});

/**
Expand All @@ -56,6 +57,7 @@ export const clientSchema = z.object({
NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE_ID: z.string().min(1),
NEXT_PUBLIC_ABBY_PROJECT_ID: z.string().min(1),
NEXT_PUBLIC_PLAUSIBLE_DOMAIN: z.string().optional(),
NEXT_PUBLIC_OPENPANEL_CLIENT_ID: z.string().optional(),
});

/**
Expand Down
23 changes: 21 additions & 2 deletions apps/web/src/lib/tracking.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
import { usePlausible as _usePlausible } from "next-plausible";
import { useOpenPanel } from "@openpanel/nextjs";
import { usePlausible } from "next-plausible";
import { useCallback } from "react";
import type { EventOptionsTuple } from "server/common/tracking";
import type { PlausibleEvents } from "types/plausible-events";

export const useTracking = _usePlausible<PlausibleEvents>;
export const useTracking = <const N extends keyof PlausibleEvents>() => {
const trackPlausible = usePlausible<PlausibleEvents>();
const { track: trackOpenPanel } = useOpenPanel();

return useCallback(
(
eventName: N,
...rest: PlausibleEvents[N] extends never
? []
: EventOptionsTuple<PlausibleEvents[N]>
) => {
trackPlausible(eventName, ...rest);
trackOpenPanel(eventName, ...rest);
},
[trackPlausible, trackOpenPanel]
);
};
7 changes: 7 additions & 0 deletions apps/web/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { AbbyDevtools, AbbyProvider, withAbby } from "lib/abby";
import type { NextPage } from "next";
import { useRouter } from "next/router";
import type { ReactElement, ReactNode } from "react";
import { OpenPanelComponent } from "@openpanel/nextjs";
import "@fontsource/martian-mono/600.css";

import "../styles/shadcn.css";
Expand Down Expand Up @@ -40,6 +41,12 @@ const MyApp: AppType<{ session: Session | null }> = ({
const getLayout = Component.getLayout ?? ((page) => page);
return (
<>
{env.NEXT_PUBLIC_OPENPANEL_CLIENT_ID && (
<OpenPanelComponent
clientId={env.NEXT_PUBLIC_OPENPANEL_CLIENT_ID}
trackScreenViews={true}
/>
)}
<AbbyProvider initialData={__ABBY_PROJECT_DATA__}>
{/* we render different devtools on the landing page */}
{router.asPath !== "/" && <AbbyDevtools />}
Expand Down
45 changes: 45 additions & 0 deletions apps/web/src/server/common/tracking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { OpenPanel } from "@openpanel/nextjs";
import { env } from "env/server.mjs";
import type { ServerEvents } from "types/plausible-events";

export type EventProps = Record<string, unknown> | never;
export type EventOptionsTuple<P extends EventProps> = P extends never
? [Omit<EventOptions<P>, "props">?]
: [EventOptions<P>];

export type EventOptions<P extends EventProps> = {
props: P;
revenue?: {
currency: string;
amount: number;
};
u?: string;
callback?: VoidFunction;
};

class TrackingService {
private instance: OpenPanel | null = null;

constructor() {
if (env.OPENPANEL_CLIENT_SECRET && env.NEXT_PUBLIC_OPENPANEL_CLIENT_ID) {
this.instance = new OpenPanel({
clientId: "your-client-id",
clientSecret: "your-client-secret",
});
}
}
public trackEvent<const N extends keyof ServerEvents>(
eventName: N,
...eventProperties: ServerEvents[N] extends never
? []
: [EventOptionsTuple<ServerEvents[N]>[0]["props"]]
) {
if (env.NODE_ENV === "development") {
console.log(`Tracking event: ${eventName}`, eventProperties[0]);
return;
}
this.instance?.track(eventName, eventProperties[0]);
}
}

export const serverTrackingService = new TrackingService();
6 changes: 6 additions & 0 deletions apps/web/src/server/trpc/router/flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { FlagService } from "server/services/FlagService";
import { validateFlag } from "utils/validateFlags";
import { z } from "zod";
import { protectedProcedure, router } from "../trpc";
import { serverTrackingService } from "server/common/tracking";

export const flagRouter = router({
getFlags: protectedProcedure
Expand Down Expand Up @@ -434,6 +435,11 @@ export const flagRouter = router({
})
)
).flat();

serverTrackingService.trackEvent("flag_removal_pr_created", {
files_changed: fileContents.length,
});

const baseBranchResponse = await gh.rest.git.getRef({
owner,
repo: name,
Expand Down
6 changes: 6 additions & 0 deletions apps/web/src/types/plausible-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,9 @@ export type PlausibleEvents = {
"Dashboard Help Clicked": never;
"Dashboard Code Clicked": never;
};

export type ServerEvents = {
flag_removal_pr_created: {
files_changed: number;
};
};
26 changes: 26 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 12c5e19

Please sign in to comment.