@@ -8,7 +8,7 @@ import React, {
88} from 'react' ;
99import type { QueryObserverResult } from '@tanstack/react-query' ;
1010import { useRouter } from 'next/router' ;
11- import { useFeatureValue } from '@growthbook/growthbook-react' ;
11+ import { GrowthBookContext } from '@growthbook/growthbook-react' ;
1212import type { AnonymousUser , LoggedUser } from '../lib/user' ;
1313import { deleteAccount , logout as dispatchLogout } from '../lib/user' ;
1414import type { AccessToken , Boot , Visit } from '../lib/boot' ;
@@ -49,6 +49,12 @@ type ShowLoginParams = {
4949 options ?: LoginOptions ;
5050} ;
5151
52+ type GrowthBookContextData = {
53+ growthbook ?: {
54+ getFeatureValue : < T > ( id : string , defaultValue : T ) => T | undefined ;
55+ } ;
56+ } ;
57+
5258export interface AuthContextData {
5359 user ?: LoggedUser ;
5460 isLoggedIn : boolean ;
@@ -79,9 +85,12 @@ export interface AuthContextData {
7985 isGdprCovered ?: boolean ;
8086 isValidRegion ?: boolean ;
8187 isFunnel ?: boolean ;
88+ inlineLoginEnabled ?: boolean ;
8289}
8390
8491const isExtension = checkIsExtension ( ) ;
92+ const inlineLoginFeatureId = 'inline_login' ;
93+ const inlineLoginDefaultValue : boolean = false ;
8594const AuthContext = React . createContext < AuthContextData > ( null ) ;
8695export const useAuthContext = ( ) : AuthContextData => useContext ( AuthContext ) ;
8796export default AuthContext ;
@@ -159,20 +168,37 @@ export const AuthContextProvider = ({
159168 isAndroidApp,
160169} : AuthContextProviderProps ) : ReactElement => {
161170 const [ loginState , setLoginState ] = useState < LoginState | null > ( null ) ;
171+ const [ inlineLoginEnabled , setInlineLoginEnabled ] = useState < boolean > ( ) ;
172+ const inlineLoginEnabledRef = useRef < boolean > ( ) ;
162173 const endUser = user && 'providers' in user ? user : null ;
163174 const referral = user ?. referralId || user ?. referrer ;
164175 const referralOrigin = user ?. referralOrigin ;
165176 const router = useRouter ( ) ;
166177 const isFunnelRef = useRef ( ! ! router ?. pathname ?. startsWith ( webFunnelPrefix ) ) ;
178+ const growthbookContext = useContext (
179+ GrowthBookContext ,
180+ ) as unknown as GrowthBookContextData ;
181+ const growthbook = growthbookContext ?. growthbook ;
167182 const isValidRegion = useMemo (
168183 ( ) => ! invalidPlusRegions . includes ( geo ?. region ) ,
169184 [ geo ?. region ] ,
170185 ) ;
171- // Inline-login experiment flag. Source of truth for the local default lives
172- // in `lib/featureManagement.ts` as `featureInlineLogin`. We can't import it
173- // here because `featureManagement` → `graphql/posts` → `AuthContext` would
174- // be a cycle, so the default is duplicated below; keep them in sync.
175- const isInlineLoginEnabled = useFeatureValue < boolean > ( 'inline_login' , true ) ;
186+ const evaluateInlineLogin = useCallback ( ( ) : boolean => {
187+ if ( ! isNullOrUndefined ( inlineLoginEnabledRef . current ) ) {
188+ return inlineLoginEnabledRef . current ;
189+ }
190+
191+ const isEnabled =
192+ growthbook ?. getFeatureValue < boolean > (
193+ inlineLoginFeatureId ,
194+ inlineLoginDefaultValue ,
195+ ) === true ;
196+
197+ inlineLoginEnabledRef . current = isEnabled ;
198+ setInlineLoginEnabled ( isEnabled ) ;
199+
200+ return isEnabled ;
201+ } , [ growthbook ] ) ;
176202
177203 return (
178204 < AuthContext . Provider
@@ -186,6 +212,7 @@ export const AuthContextProvider = ({
186212 firstVisit : user ?. firstVisit ,
187213 trackingId : user ?. id ,
188214 shouldShowLogin : loginState !== null ,
215+ inlineLoginEnabled,
189216 showLogin : useCallback (
190217 ( { trigger, options = { } } ) => {
191218 const hasCompanion = ! ! isCompanionActivated ( ) ;
@@ -196,6 +223,7 @@ export const AuthContextProvider = ({
196223 }
197224
198225 const params = new URLSearchParams ( globalThis ?. location . search ) ;
226+ const shouldUseInlineLogin = ! isExtension && evaluateInlineLogin ( ) ;
199227
200228 setLoginState ( { ...options , trigger } ) ;
201229 if ( isExtension ) {
@@ -206,19 +234,20 @@ export const AuthContextProvider = ({
206234 params . set ( AFTER_AUTH_PARAM , window . location . pathname ) ;
207235 }
208236
237+ const onboardingPath = isExtension
238+ ? `${ onboardingUrl } ?${ params . toString ( ) } `
239+ : `/onboarding?${ params . toString ( ) } ` ;
240+
209241 // Inline login experiment: render the modal in-place instead of
210242 // redirecting to /onboarding. Extension keeps the redirect because
211243 // it has no host page to mount the modal on.
212- if ( isInlineLoginEnabled && ! isExtension ) {
244+ if ( shouldUseInlineLogin ) {
213245 return ;
214246 }
215247
216- const onboardingPath = `${ onboardingUrl } ?${ params . toString ( ) } ` ;
217- router . push (
218- isExtension ? onboardingPath : `/onboarding?${ params . toString ( ) } ` ,
219- ) ;
248+ router . push ( onboardingPath ) ;
220249 } ,
221- [ router , isInlineLoginEnabled ] ,
250+ [ evaluateInlineLogin , router ] ,
222251 ) ,
223252 closeLogin : useCallback ( ( ) => setLoginState ( null ) , [ ] ) ,
224253 loginState,
0 commit comments