Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ pnpm-debug.log*
.DS_Store

.superpowers/
.env.local
1 change: 1 addition & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export default defineConfig({
"/home-new/",
"/endorsements-new/",
"/e4p/pledge-new/",
"/growthbook-test/",
];
return !exclude.some((path) => page.endsWith(path));
},
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@emotion/styled": "^11.14.1",
"@fontsource/fraunces": "^5.2.9",
"@fontsource/outfit": "^5.2.8",
"@growthbook/growthbook-react": "^1.7.0",
"@iconify-json/simple-icons": "^1.2.54",
"@mui/icons-material": "^6.5.0",
"@mui/material": "^6.5.0",
Expand Down
28 changes: 28 additions & 0 deletions pnpm-lock.yaml

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

14 changes: 14 additions & 0 deletions src/components/GrowthBookProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { GrowthBookProvider as GBProvider } from "@growthbook/growthbook-react";
import type { ReactNode } from "react";
import { growthbook } from "../growthbook";

interface Props {
children: ReactNode;
}

// Wrap a client:only="react" island in this to read GrowthBook flags with
// useFeatureIsOn / useFeatureValue. Each island mounts its own React root, so
// there's no single app entry point to wrap once — use this per island instead.
export default function GrowthBookProvider({ children }: Props) {
return <GBProvider growthbook={growthbook}>{children}</GBProvider>;
}
21 changes: 21 additions & 0 deletions src/components/GrowthBookTestBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useFeatureIsOn } from "@growthbook/growthbook-react";
import GrowthBookProvider from "./GrowthBookProvider";

// Throwaway banner to confirm the GrowthBook SDK is wired end to end.
// Safe to delete once the connection shows as Connected in the dashboard.
function Banner() {
const enabled = useFeatureIsOn("growthbook-test");
return (
<div style={{ padding: "1rem", fontFamily: "monospace" }}>
growthbook-test flag is {enabled ? "ON" : "OFF"}
</div>
);
}

export default function GrowthBookTestBanner() {
return (
<GrowthBookProvider>
<Banner />
</GrowthBookProvider>
);
}
22 changes: 22 additions & 0 deletions src/growthbook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { GrowthBook } from "@growthbook/growthbook-react";

const clientKey = import.meta.env.PUBLIC_GROWTHBOOK_CLIENT_KEY;

if (!clientKey) {
// Fail loudly. A missing key makes every flag return its default instead,
// which looks like working code that simply never turns anything on.
throw new Error(
"Missing PUBLIC_GROWTHBOOK_CLIENT_KEY — GrowthBook flags will not load without it.",
);
}

export const growthbook = new GrowthBook({
apiHost: "https://cdn.growthbook.io",
clientKey,
enableDevMode: true,
});

// streaming: false — fetch the payload once on load. Flag changes then land on the
// next page load. Streaming holds an SSE connection open per client; opt in only
// if you want live updates.
export const ready = growthbook.init({ streaming: false });
2 changes: 1 addition & 1 deletion src/middleware/csp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const csp = defineMiddleware(async (context, next) => {
`style-src 'nonce-${nonce}' 'self' https://fonts.googleapis.com https://secure.qgiv.com`,
"font-src 'self' https://fonts.gstatic.com https://gallery.eo.page",
"img-src 'self' data: https:",
"connect-src 'self' https://plausible.io https://pal-chat.net https://eomail4.com https://www.google.com https://1k0gztb8b2.execute-api.us-east-2.amazonaws.com https://www.charitystack.com https://www.donation.charitystack.com https://*.ingest.sentry.io https://*.ingest.de.sentry.io",
"connect-src 'self' https://plausible.io https://pal-chat.net https://eomail4.com https://www.google.com https://1k0gztb8b2.execute-api.us-east-2.amazonaws.com https://www.charitystack.com https://www.donation.charitystack.com https://*.ingest.sentry.io https://*.ingest.de.sentry.io https://cdn.growthbook.io",
"frame-src https://secure.qgiv.com https://calendly.com https://www.youtube.com https://www.youtube-nocookie.com https://www.google.com https://validaid.org https://www.charitystack.com",
"object-src 'none'",
"base-uri 'self'",
Expand Down
10 changes: 10 additions & 0 deletions src/pages/growthbook-test.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
import Layout from "../layouts/Layout.astro";
import GrowthBookTestBanner from "../components/GrowthBookTestBanner";
---

<Layout title="GrowthBook test">
<main class="flex flex-1 items-center justify-center px-6 py-24">
<GrowthBookTestBanner client:only="react" />
</main>
</Layout>
Loading