diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4749858..9d855ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -370,6 +370,9 @@ importers: postgres: specifier: ^3.4.3 version: 3.4.4 + posthog-js: + specifier: ^1.130.0 + version: 1.130.0 react: specifier: 18.2.0 version: 18.2.0 @@ -6202,6 +6205,10 @@ packages: dependencies: reusify: 1.0.4 + /fflate@0.4.8: + resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==} + dev: false + /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -8652,6 +8659,13 @@ packages: engines: {node: '>=12'} dev: false + /posthog-js@1.130.0: + resolution: {integrity: sha512-bCrw5HunoXLybO20Q1bYEg68i5WCZWKxhStYJK4OR/9jrm7GwZ53GDrN78p8apFi0EH5ay4YZGbLFSkg+SsZWQ==} + dependencies: + fflate: 0.4.8 + preact: 10.19.3 + dev: false + /preact-render-to-string@5.2.3(preact@10.11.3): resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==} peerDependencies: diff --git a/starterkits/saas/.env.example b/starterkits/saas/.env.example index 575c006..1b5df5f 100644 --- a/starterkits/saas/.env.example +++ b/starterkits/saas/.env.example @@ -39,3 +39,7 @@ UPLOADTHING_ID="" LEMONSQUEEZY_API_KEY="" LEMONSQUEEZY_STORE_ID="" LEMONSQUEEZY_WEBHOOK_SECRET="" + +# Posthog +NEXT_PUBLIC_POSTHOG_KEY="" +NEXT_PUBLIC_POSTHOG_HOST="" \ No newline at end of file diff --git a/starterkits/saas/package.json b/starterkits/saas/package.json index 56fd1ef..efd0d87 100644 --- a/starterkits/saas/package.json +++ b/starterkits/saas/package.json @@ -53,6 +53,7 @@ "next-themes": "^0.3.0", "nodemailer": "^6.9.13", "postgres": "^3.4.3", + "posthog-js": "^1.130.0", "react": "18.2.0", "react-dom": "18.2.0", "react-hook-form": "^7.51.3", diff --git a/starterkits/saas/src/components/posthog-provider.tsx b/starterkits/saas/src/components/posthog-provider.tsx new file mode 100644 index 0000000..a2fd2fb --- /dev/null +++ b/starterkits/saas/src/components/posthog-provider.tsx @@ -0,0 +1,42 @@ +"use client"; + +import { env } from "@/env"; +import { useSession } from "next-auth/react"; +import posthog from "posthog-js"; +import { PostHogProvider as CSPostHogProvider } from "posthog-js/react"; +import { useEffect } from "react"; + +if (typeof window !== "undefined") { + posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, { + api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, + }); +} + +type PostHogProviderProps = { + children: React.ReactNode; +}; + +export function PosthogProvider({ children }: PostHogProviderProps) { + return ( + + {children} + + ); +} + +function PosthogAuthWrapper({ children }: PostHogProviderProps) { + const { data: session, status } = useSession(); + + useEffect(() => { + if (status === "authenticated") { + posthog.identify(session.user.id, { + email: session.user.email, + name: session.user.name, + }); + } else if (status === "unauthenticated") { + posthog.reset(); + } + }, [session, status]); + + return children; +} diff --git a/starterkits/saas/src/components/providers.tsx b/starterkits/saas/src/components/providers.tsx index f0d4745..44fd314 100644 --- a/starterkits/saas/src/components/providers.tsx +++ b/starterkits/saas/src/components/providers.tsx @@ -2,6 +2,8 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ThemeProvider } from "@/components/theme-provider"; +import { PosthogProvider } from "@/components/posthog-provider"; +import { SessionProvider } from "next-auth/react"; type ProvidersProps = { children: React.ReactNode; @@ -11,8 +13,12 @@ export function Providers({ children }: ProvidersProps) { const queryClient = new QueryClient(); return ( - - {children} - + + + + {children} + + + ); } diff --git a/starterkits/saas/src/env.js b/starterkits/saas/src/env.js index 8700e9c..dbff56d 100644 --- a/starterkits/saas/src/env.js +++ b/starterkits/saas/src/env.js @@ -41,6 +41,8 @@ export const env = createEnv({ */ client: { // NEXT_PUBLIC_CLIENTVAR: z.string(), + NEXT_PUBLIC_POSTHOG_KEY: z.string(), + NEXT_PUBLIC_POSTHOG_HOST: z.string().url(), }, /** @@ -62,6 +64,8 @@ export const env = createEnv({ LEMONSQUEEZY_API_KEY: process.env.LEMONSQUEEZY_API_KEY, LEMONSQUEEZY_STORE_ID: process.env.LEMONSQUEEZY_STORE_ID, LEMONSQUEEZY_WEBHOOK_SECRET: process.env.LEMONSQUEEZY_WEBHOOK_SECRET, + NEXT_PUBLIC_POSTHOG_HOST: process.env.NEXT_PUBLIC_POSTHOG_HOST, + NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY, }, /** * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially