feat(web): residential_projects feature flag for /du-an routes (TEC-2757)
- Add useResidentialProjectsFlag hook with NEXT_PUBLIC_FEATURE_RESIDENTIAL_PROJECTS env + URL/localStorage override (mirrors AVM v2 pattern) - Gate /du-an index (client) and /du-an/[slug] detail (server) routes via notFound() when flag disabled - Add component tests for index page including disabled-flag notFound branch Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
59
apps/web/lib/hooks/use-residential-projects-flag.ts
Normal file
59
apps/web/lib/hooks/use-residential-projects-flag.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const LOCAL_STORAGE_KEY = 'goodgo:residential_projects';
|
||||
const QUERY_PARAM = 'residential_projects';
|
||||
|
||||
function readEnvDefault(): boolean {
|
||||
const raw = process.env['NEXT_PUBLIC_FEATURE_RESIDENTIAL_PROJECTS'];
|
||||
if (!raw) return false;
|
||||
return raw === '1' || raw.toLowerCase() === 'true';
|
||||
}
|
||||
|
||||
function readOverride(): boolean | null {
|
||||
if (typeof window === 'undefined') return null;
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const qp = params.get(QUERY_PARAM);
|
||||
if (qp === '1' || qp === 'true') {
|
||||
try {
|
||||
window.localStorage.setItem(LOCAL_STORAGE_KEY, '1');
|
||||
} catch {
|
||||
// localStorage may be blocked — ignore
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (qp === '0' || qp === 'false') {
|
||||
try {
|
||||
window.localStorage.setItem(LOCAL_STORAGE_KEY, '0');
|
||||
} catch {
|
||||
// localStorage may be blocked — ignore
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const stored = window.localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (stored === '1') return true;
|
||||
if (stored === '0') return false;
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function useResidentialProjectsFlag(): boolean {
|
||||
const [enabled, setEnabled] = useState<boolean>(readEnvDefault());
|
||||
|
||||
useEffect(() => {
|
||||
const override = readOverride();
|
||||
setEnabled(override ?? readEnvDefault());
|
||||
}, []);
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
export function isResidentialProjectsEnabledServer(): boolean {
|
||||
return readEnvDefault();
|
||||
}
|
||||
Reference in New Issue
Block a user