diff --git a/frontends/main/next.config.js b/frontends/main/next.config.js
index 44af6220cc..11658fe0cc 100644
--- a/frontends/main/next.config.js
+++ b/frontends/main/next.config.js
@@ -3,6 +3,22 @@ const { validateEnv } = require("./validateEnv")
validateEnv()
+const processFeatureFlags = () => {
+ const featureFlagPrefix =
+ process.env.NEXT_PUBLIC_POSTHOG_FEATURE_PREFIX || "FEATURE_"
+ const bootstrapFeatureFlags = {}
+
+ for (const [key, value] of Object.entries(process.env)) {
+ if (key.startsWith(`NEXT_PUBLIC_${featureFlagPrefix}`)) {
+ bootstrapFeatureFlags[
+ key.replace(`NEXT_PUBLIC_${featureFlagPrefix}`, "")
+ ] = value === "True" ? true : JSON.stringify(value)
+ }
+ }
+
+ return bootstrapFeatureFlags
+}
+
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: (config, { webpack }) => {
@@ -57,6 +73,10 @@ const nextConfig = {
},
],
},
+
+ env: {
+ FEATURE_FLAGS: JSON.stringify(processFeatureFlags()),
+ },
}
module.exports = nextConfig
diff --git a/frontends/main/src/app/providers.tsx b/frontends/main/src/app/providers.tsx
index 80b9632231..f0e66a07ff 100644
--- a/frontends/main/src/app/providers.tsx
+++ b/frontends/main/src/app/providers.tsx
@@ -5,17 +5,20 @@ import { getQueryClient } from "./getQueryClient"
import { QueryClientProvider } from "@tanstack/react-query"
import { ThemeProvider, NextJsAppRouterCacheProvider } from "ol-components"
import { Provider as NiceModalProvider } from "@ebay/nice-modal-react"
+import ConfiguredPostHogProvider from "@/components/ConfiguredPostHogProvider/ConfiguredPostHogProvider"
export default function Providers({ children }: { children: React.ReactNode }) {
const queryClient = getQueryClient()
return (
-
-
-
- {children}
-
-
-
+
+
+
+
+ {children}
+
+
+
+
)
}
diff --git a/frontends/main/src/components/ConfiguredPostHogProvider/ConfiguredPostHogProvider.tsx b/frontends/main/src/components/ConfiguredPostHogProvider/ConfiguredPostHogProvider.tsx
new file mode 100644
index 0000000000..78b3e9cb8e
--- /dev/null
+++ b/frontends/main/src/components/ConfiguredPostHogProvider/ConfiguredPostHogProvider.tsx
@@ -0,0 +1,28 @@
+import React from "react"
+import { PostHogProvider } from "posthog-js/react"
+
+const ConfiguredPostHogProvider: React.FC<{ children: React.ReactNode }> = ({
+ children,
+}) => {
+ const apiKey = process.env.NEXT_PUBLIC_POSTHOG_PROJECT_API_KEY || ""
+ const apiHost =
+ process.env.NEXT_PUBLIC_POSTHOG_API_HOST || "https://us.i.posthog.com"
+ const featureFlags = JSON.parse(process.env.FEATURE_FLAGS || "")
+
+ const postHogOptions = {
+ api_host: apiHost,
+ bootstrap: {
+ featureFlags: featureFlags,
+ },
+ }
+
+ return apiKey ? (
+
+ {children}
+
+ ) : (
+ children
+ )
+}
+
+export default ConfiguredPostHogProvider
diff --git a/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.test.tsx b/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.test.tsx
index 97eaa142d3..f09800d5b4 100644
--- a/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.test.tsx
+++ b/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.test.tsx
@@ -37,17 +37,16 @@ jest.mock("posthog-js/react", () => ({
}))
describe("LearningResourceDrawer", () => {
- it.skip.each([
+ it.each([
{ descriptor: "is enabled", enablePostHog: true },
{ descriptor: "is not enabled", enablePostHog: false },
])(
"Renders drawer content when resource=id is in the URL and captures the view if PostHog $descriptor",
async ({ enablePostHog }) => {
setMockResponse.get(urls.userMe.get(), {})
- // @ts-expect-error reinstante posthog
- APP_SETTINGS.POSTHOG = {
- api_key: enablePostHog ? "test1234" : "", // pragma: allowlist secret
- }
+ process.env.NEXT_PUBLIC_POSTHOG_PROJECT_API_KEY = enablePostHog
+ ? "12345abcdef" // pragma: allowlist secret
+ : ""
const resource = factories.learningResources.resource()
setMockResponse.get(
urls.learningResources.details({ id: resource.id }),
diff --git a/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.tsx b/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.tsx
index 4d6ba70e75..fbc8f2d857 100644
--- a/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.tsx
+++ b/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.tsx
@@ -1,4 +1,4 @@
-import React, { Suspense, useCallback, useMemo } from "react"
+import React, { Suspense, useCallback, useEffect, useMemo } from "react"
import {
RoutedDrawer,
LearningResourceExpanded,
@@ -23,38 +23,35 @@ import {
AddToUserListDialog,
} from "../Dialogs/AddToListDialog"
import { SignupPopover } from "../SignupPopover/SignupPopover"
+import { usePostHog } from "posthog-js/react"
const RESOURCE_DRAWER_PARAMS = [RESOURCE_DRAWER_QUERY_PARAM] as const
-/*
const useCapturePageView = (resourceId: number) => {
const { data, isSuccess } = useLearningResourcesDetail(Number(resourceId))
const posthog = usePostHog()
-
- // TODO Provide POSTHOG env vars
-
- // const { POSTHOG } = APP_SETTINGS
-
- // useEffect(() => {
- // if (!POSTHOG?.api_key || POSTHOG.api_key.length < 1) return
- // if (!isSuccess) return
- // posthog.capture("lrd_view", {
- // resourceId: data?.id,
- // readableId: data?.readable_id,
- // platformCode: data?.platform?.code,
- // resourceType: data?.resource_type,
- // })
- // }, [
- // isSuccess,
- // posthog,
- // data?.id,
- // data?.readable_id,
- // data?.platform?.code,
- // data?.resource_type,
- // POSTHOG?.api_key,
- // ])
+ const apiKey = process.env.NEXT_PUBLIC_POSTHOG_PROJECT_API_KEY
+
+ useEffect(() => {
+ if (!apiKey || apiKey.length < 1) return
+ if (!isSuccess) return
+ posthog.capture("lrd_view", {
+ resourceId: data?.id,
+ readableId: data?.readable_id,
+ platformCode: data?.platform?.code,
+ resourceType: data?.resource_type,
+ })
+ }, [
+ isSuccess,
+ posthog,
+ data?.id,
+ data?.readable_id,
+ data?.platform?.code,
+ data?.resource_type,
+ apiKey,
+ ])
}
-*/
+
/**
* Convert HTML to plaintext, removing any HTML tags.
* This conversion method has some issues:
@@ -93,6 +90,7 @@ const DrawerContent: React.FC<{
NiceModal.show(AddToUserListDialog, { resourceId })
}
}, [user])
+ useCapturePageView(Number(resourceId))
return (
<>
diff --git a/frontends/main/validateEnv.js b/frontends/main/validateEnv.js
index 74f01e2cf7..ed1ff36222 100644
--- a/frontends/main/validateEnv.js
+++ b/frontends/main/validateEnv.js
@@ -21,6 +21,9 @@ const schema = yup.object().shape({
.string()
.oneOf(["true", "false"]),
NEXT_PUBLIC_CSRF_COOKIE_NAME: yup.string().required(),
+ NEXT_PUBLIC_POSTHOG_PROJECT_API_KEY: yup.string(),
+ NEXT_PUBLIC_POSTHOG_FEATURE_PREFIX: yup.string(),
+ NEXT_PUBLIC_POSTHOG_API_HOST: yup.string(),
})
const validateEnv = () => schema.validateSync(process.env)