Files
goodgo-platform/apps/web/lib/hooks/use-residential-projects-flag.ts
Ho Ngoc Hai 6ff039db1e
Some checks failed
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m28s
Deploy / Build API Image (push) Failing after 26s
Deploy / Build Web Image (push) Failing after 16s
Deploy / Build AI Services Image (push) Failing after 11s
E2E Tests / Playwright E2E (push) Failing after 23s
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 11s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Smoke Test Production (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
Security Scanning / Trivy Scan — Web Image (push) Has been cancelled
Security Scanning / Trivy Scan — AI Services Image (push) Has been cancelled
Security Scanning / Trivy Filesystem Scan (push) Has been cancelled
Security Scanning / Security Gate (push) Has been cancelled
Security Scanning / Trivy Scan — API Image (push) Has been cancelled
fix(du-an): stop detail page crash from thin backend payload + client/server flag boundary
- Split `isResidentialProjectsEnabledServer` out of the `'use client'`
  hook file into `lib/feature-flags/residential-projects.ts` so Server
  Components can import it without Next.js treating it as a client ref.
- Detail endpoint preserves `media` via new `shapeProjectDetail`
  instead of stripping it in `shapeProject`.
- `fetchProjectBySlug` now normalizes the response: fills missing
  arrays (media, blocks, amenities, priceRanges, priceHistory,
  neighborhoodScores, pois, documents) with `[]`, remaps
  `developer.logo` → `logoUrl`, defaults `totalProjects` to 0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 10:11:06 +07:00

59 lines
1.5 KiB
TypeScript

'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 == null || raw === '') return true;
return !(raw === '0' || raw.toLowerCase() === 'false');
}
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;
}
// NOTE: The server-side helper lives in `@/lib/feature-flags/residential-projects`
// to avoid making it a client-only export (this file has `'use client'`).