Skip to content

Commit

Permalink
feat: add FeatureFlagProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
codeincontext committed Nov 7, 2024
1 parent b2e525c commit 5d7cf5a
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 29 deletions.
9 changes: 8 additions & 1 deletion apps/nextjs/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import "@/app/theme-config.css";
import { Providers } from "@/components/AppComponents/Chat//providers";
import { AnalyticsProvider } from "@/components/ContextProviders/AnalyticsProvider";
import { CookieConsentProvider } from "@/components/ContextProviders/CookieConsentProvider";
import { FeatureFlagProvider } from "@/components/ContextProviders/FeatureFlagProvider";
import FontProvider from "@/components/ContextProviders/FontProvider";
import { GleapProvider } from "@/components/ContextProviders/GleapProvider";
import { WebDebuggerPosition } from "@/lib/avo/Avo";
Expand Down Expand Up @@ -118,7 +119,13 @@ export default async function RootLayout({
}}
bootstrappedFeatures={bootstrappedFeatures}
>
<GleapProvider>{children}</GleapProvider>
<GleapProvider>
<FeatureFlagProvider
bootstrappedFeatures={bootstrappedFeatures}
>
{children}
</FeatureFlagProvider>
</GleapProvider>
</AnalyticsProvider>
</CookieConsentProvider>
</Providers>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use client";

import type { ReactNode } from "react";
import {
useMemo,
createContext,
useContext,
useEffect,
useState,
useRef,
} from "react";

import { aiLogger } from "@oakai/logger";

import useAnalytics from "@/lib/analytics/useAnalytics";

const log = aiLogger("feature-flags");

export interface FeatureFlagContextProps {
bootstrappedFeatures: Record<string, string | boolean>;
}

const FeatureFlagContext = createContext<FeatureFlagContextProps>({
bootstrappedFeatures: {},
});

export interface FeatureFlagProviderProps {
children: ReactNode;
bootstrappedFeatures: Record<string, boolean>;
}

export const FeatureFlagProvider = ({
children,
bootstrappedFeatures,
}: FeatureFlagProviderProps) => {
log.info("FeatureFlagProvider", bootstrappedFeatures);
const value = useMemo(
() => ({ bootstrappedFeatures }),
[bootstrappedFeatures],
);

return (
<FeatureFlagContext.Provider value={value}>
{children}
</FeatureFlagContext.Provider>
);
};

export const useClientSideFeatureFlag = (flag: string) => {
const context = useContext(FeatureFlagContext);

const { posthogAiBetaClient: posthog } = useAnalytics();
const hasLogged = useRef(false);

const [featureEnabled, setFeatureEnabled] = useState<boolean | undefined>();

const bootstrappedFlag = context.bootstrappedFeatures[flag];

useEffect(() => {
return posthog.onFeatureFlags(() => {
const updatedValue = posthog.isFeatureEnabled(flag);
if (updatedValue !== bootstrappedFlag) {
log.info(`Updating ${flag} to ${updatedValue}`);
setFeatureEnabled(updatedValue);
}
});
}, [posthog, flag, bootstrappedFlag]);

const isDebug = process.env.NEXT_PUBLIC_POSTHOG_DEBUG === "true";
if (isDebug) {
if (!hasLogged.current) {
hasLogged.current = true;
log.info(`Feature flag ${flag} is enabled in debug mode`);
}
return true;
}

// NOTE: This will flash from the bootstrapped value to the posthog value
// only on page load within 1 minute of toggling a flag
return featureEnabled ?? bootstrappedFlag ?? false;
};
28 changes: 0 additions & 28 deletions apps/nextjs/src/utils/useClientSideFeatureFlag.ts

This file was deleted.

0 comments on commit 5d7cf5a

Please sign in to comment.