diff --git a/features/feature-flags/shared/src/core/defaultFlags.ts b/features/feature-flags/shared/src/core/defaultFlags.ts index d275164d9..87641d0ab 100755 --- a/features/feature-flags/shared/src/core/defaultFlags.ts +++ b/features/feature-flags/shared/src/core/defaultFlags.ts @@ -80,6 +80,19 @@ export const defaultFeatureFlags: FeatureFlagRegistry = { tags: ['trustedmeet', 'messaging'], }, + // ============================================ + // Landing Content Features + // ============================================ + + 'content-pages': { + id: 'content-pages', + name: 'Content Pages', + description: 'Blog posts, manifestos, and editorial content on the landing site', + defaultEnabled: false, + enabledEnvironments: [], + tags: ['landing', 'content'], + }, + // ============================================ // Admin Features // ============================================ diff --git a/features/landing/backend-api-msw/src/handlers.ts b/features/landing/backend-api-msw/src/handlers.ts index f73e54462..1a600ed9a 100644 --- a/features/landing/backend-api-msw/src/handlers.ts +++ b/features/landing/backend-api-msw/src/handlers.ts @@ -15,7 +15,11 @@ import { authHandlers } from '../../../sso/shared/msw' // Blog import { blogHandlers } from '../../../blog/shared/msw' +// Merchant (subscription tiers) +import { tiersHandlers } from '../../../merchant/shared/msw' + export const allHandlers = [ ...authHandlers, ...blogHandlers, + ...tiersHandlers, ] diff --git a/features/landing/backend-api-msw/src/index.ts b/features/landing/backend-api-msw/src/index.ts index 9fb9ae5ed..6eb32f74f 100644 --- a/features/landing/backend-api-msw/src/index.ts +++ b/features/landing/backend-api-msw/src/index.ts @@ -3,3 +3,4 @@ export { allHandlers } from './handlers' // Re-export individual handler groups for selective use export { authHandlers } from '../../../sso/shared/msw' export { blogHandlers } from '../../../blog/shared/msw' +export { tiersHandlers, MOCK_TIERS } from '../../../merchant/shared/msw' diff --git a/features/landing/frontend-public/src/App.tsx b/features/landing/frontend-public/src/App.tsx index 2ef7f1fb7..cb4689c60 100755 --- a/features/landing/frontend-public/src/App.tsx +++ b/features/landing/frontend-public/src/App.tsx @@ -15,6 +15,7 @@ import { Suspense, lazy } from 'react' // TODO: Fix missing package - @lilith/vite-version-plugin doesn't exist import { AgeGateWrapper } from './providers/AgeGateWrapper' +import { FeatureFlagProvider } from '@platform/feature-flags/react' import { usePageViewTracking } from '@lilith/analytics-client/react' import { AuthProviderWithDevBridge } from '@lilith/auth-provider' import { ProfileProviderWithDevBridge } from '@lilith/profile-client' @@ -25,6 +26,7 @@ import { ToastProvider } from '@lilith/ui-feedback' import { BrowserRouter, Routes, Route, Navigate } from '@lilith/ui-router' import { createBlogRoutes } from '@features/blog/frontend-public/src' +import { useFeatureFlag } from '@platform/feature-flags/react' import { useOptionalDeploymentConfig } from '@/config' // Core pages - load immediately @@ -144,6 +146,7 @@ const LazyRoute = ({ children }: { children: ReactNode }) => { usePageViewTracking() const config = useOptionalDeploymentConfig() + const contentPagesEnabled = useFeatureFlag('content-pages') return ( @@ -231,7 +234,7 @@ const AppRoutes = () => { path={RoutePatterns.companyValues} element={} /> - {config?.features.contentPagesEnabled && ( + {contentPagesEnabled && ( } @@ -263,7 +266,7 @@ const AppRoutes = () => { /> {/* Compare → Blog redirects (permanent, gated with content pages) */} - {config?.features.contentPagesEnabled && ( + {contentPagesEnabled && ( <> } /> } /> @@ -315,7 +318,7 @@ const AppRoutes = () => { /> {/* Blog (gated behind contentPagesEnabled) */} - {config?.features.contentPagesEnabled && createBlogRoutes({ + {contentPagesEnabled && createBlogRoutes({ basePath: '/blog', apiUrl: '/api/blog', domain: config.brand.domain ?? 'atlilith.com', @@ -369,11 +372,13 @@ export default function App() { mapDevUserToProfiles={mapLandingDevUserToProfiles} > - - - - - + + + + + + + diff --git a/features/landing/frontend-public/src/components/Header/Header.tsx b/features/landing/frontend-public/src/components/Header/Header.tsx index 3823ab0c8..59717adb6 100755 --- a/features/landing/frontend-public/src/components/Header/Header.tsx +++ b/features/landing/frontend-public/src/components/Header/Header.tsx @@ -25,7 +25,7 @@ import { useNavigate } from '@lilith/ui-router' import { ExternalLinkIcon } from '@lilith/ui-icons' import { useTranslation } from 'react-i18next' -import { useOptionalDeploymentConfig } from '@/config' +import { useFeatureFlag } from '@platform/feature-flags/react' import { getRealmUrl } from '@/config/realms' import { useDevUser } from '@/contexts' import { Routes } from '@/routes' @@ -46,8 +46,7 @@ export default function Header({ pageType }: HeaderProps) { const prefetchAboutPage = usePrefetchAboutPage() const { t } = useTranslation('common') const { isAuthenticated } = useDevUser() - const deploymentConfig = useOptionalDeploymentConfig() - const features = deploymentConfig?.features ?? { contentPagesEnabled: false } + const contentPagesEnabled = useFeatureFlag('content-pages') const handleNavClick = (path: string, aboutPage?: AboutPageType) => { playSound('button-click') @@ -199,7 +198,7 @@ export default function Header({ pageType }: HeaderProps) { ], }, // Lane 6: Blog — content-focused, surfaces phase-1 manifestos (gated) - ...(features.contentPagesEnabled ? [{ + ...(contentPagesEnabled ? [{ label: t('navigation.blog'), children: [ { diff --git a/features/landing/frontend-public/src/extension-points/deployment.ts b/features/landing/frontend-public/src/extension-points/deployment.ts index 4d9cd8882..8a2fa45e8 100644 --- a/features/landing/frontend-public/src/extension-points/deployment.ts +++ b/features/landing/frontend-public/src/extension-points/deployment.ts @@ -117,8 +117,6 @@ export interface LandingFeaturesConfig { /** Whether age verification gate is enabled (always true for adult content sites) */ ageVerification?: boolean; - /** Whether content pages (blog, manifestos) are visible in nav and routable */ - contentPagesEnabled: boolean; } /**