feat(sf-fe-a7): Section 3.1 «Настройки выборки» + Server/Client split (rebased) #356

Merged
lekss361 merged 2 commits from fix/sf-fe-a7-rebased into main 2026-05-18 00:55:06 +00:00
Owner

Recreated from #355 (closed — branched off pre-A6 main, conflicted on page.tsx). Rebased onto current main (307a75f after #354), conflict resolved (kept A7 Server Component version, fixup commit 9065cca preserves Section1+2 wiring).

Summary

SF Frontend Wave 3 §A7: Section 3.1 «Настройки выборки» в Section 3 wrapper. Параллельно — [cad]/page.tsx split на Server Component + AnalysisPageContent.tsx (Client) для SEO + SSR streaming.

Files

NEW frontend/src/components/site-finder/analysis/Section3SettingsAndCompetitors.tsx:

  • Section 3 wrapper id="section-3" + HeadlineBar + competitor count
  • Section 3.1 id="section-3-1" «Настройки выборки»:
    • Radius slider 1-5 км (default 2)
    • 4 chips: «Только строящиеся» / «+3 мес» / «-6 мес» / «Только квартиры» (aria-pressed)
    • Reuse <WeightProfilePanel/> (POI weights)
  • Section 3.2 / 3.3 — dashed placeholders (ждут A8)

Refactor [cad]/page.tsx → Server Component:

  • generateMetadata для SEO
  • Wraps <AnalysisPageContent/> в <Suspense/>
  • decodeURIComponent(cad) preserved

NEW [cad]/AnalysisPageContent.tsx:

  • "use client"
  • Canonical useParcelAnalyzeQuery из @/lib/site-finder-api
  • Wires Section 1 (<Section1ParcelInfo/>) — A5 preserved
  • Wires Section 2 (<Section2NetworksUtilities/>) — A6 preserved
  • Wires Section 3 (<Section3SettingsAndCompetitors/>) — new
  • Sections 4-5 placeholders (TODO A10/A11)

Deleted frontend/src/hooks/useParcelAnalyzeQuery.ts — duplicate (canonical в lib)

Constraints

  • TS strict, Server/Client split
  • TanStack Query reuse
  • Real backend data (B5)
  • CSS tokens (globals.css)
  • pre-commit prettier + lint pass
  • Sections 1+2 preserved (rebase conflict resolved keeping A7 structure + fixup wiring)

Verify post-deploy

  • /site-finder/analysis/66:41:0204016:10 — Section 3 + filters работают, Sections 1+2 продолжают рендериться
  • Toggle chips → aria-pressed updates
  • Radius slider → competitor count updates live

Closes #355.

Recreated from #355 (closed — branched off pre-A6 main, conflicted on page.tsx). Rebased onto current `main` (`307a75f` after #354), conflict resolved (kept A7 Server Component version, fixup commit `9065cca` preserves Section1+2 wiring). ## Summary SF Frontend Wave 3 §A7: Section 3.1 «Настройки выборки» в Section 3 wrapper. Параллельно — `[cad]/page.tsx` split на Server Component + `AnalysisPageContent.tsx` (Client) для SEO + SSR streaming. ## Files **NEW** `frontend/src/components/site-finder/analysis/Section3SettingsAndCompetitors.tsx`: - Section 3 wrapper `id="section-3"` + HeadlineBar + competitor count - Section 3.1 `id="section-3-1"` «Настройки выборки»: - Radius slider 1-5 км (default 2) - 4 chips: «Только строящиеся» / «+3 мес» / «-6 мес» / «Только квартиры» (aria-pressed) - Reuse `<WeightProfilePanel/>` (POI weights) - Section 3.2 / 3.3 — dashed placeholders (ждут A8) **Refactor** `[cad]/page.tsx` → Server Component: - `generateMetadata` для SEO - Wraps `<AnalysisPageContent/>` в `<Suspense/>` - `decodeURIComponent(cad)` preserved **NEW** `[cad]/AnalysisPageContent.tsx`: - `"use client"` - Canonical `useParcelAnalyzeQuery` из `@/lib/site-finder-api` - Wires Section 1 (`<Section1ParcelInfo/>`) — A5 preserved - Wires Section 2 (`<Section2NetworksUtilities/>`) — A6 preserved - Wires Section 3 (`<Section3SettingsAndCompetitors/>`) — new - Sections 4-5 placeholders (TODO A10/A11) **Deleted** `frontend/src/hooks/useParcelAnalyzeQuery.ts` — duplicate (canonical в lib) ## Constraints - ✅ TS strict, Server/Client split - ✅ TanStack Query reuse - ✅ Real backend data (B5) - ✅ CSS tokens (globals.css) - ✅ pre-commit prettier + lint pass - ✅ **Sections 1+2 preserved** (rebase conflict resolved keeping A7 structure + fixup wiring) ## Verify post-deploy - `/site-finder/analysis/66:41:0204016:10` — Section 3 + filters работают, Sections 1+2 продолжают рендериться - Toggle chips → aria-pressed updates - Radius slider → competitor count updates live Closes #355.
lekss361 added 2 commits 2026-05-18 00:50:57 +00:00
Author
Owner

Deep Code Review — verdict: APPROVE

Summary

  • Status: APPROVE
  • Files reviewed: 3 (P2: 3) — frontend only
  • Lines: +800 / -167
  • Mergeable: yes (clean rebase onto 307a75f, no conflicts)

Server/Client split (page.tsx)

  • No "use client" — server component ✓
  • generateMetadata({params}): Promise<Metadata> is async, uses await params — correct Next 15 async params API
  • AnalysisPage itself is async, await params, hands decoded cad (string) to client component as prop — clean hydration boundary
  • <Suspense fallback={...}> wraps AnalysisPageContent so server-streaming works
  • decodeURIComponent from #351 dropped — acceptable: on server, Next router decodes URL segments before populating params, so the explicit decode was only needed in the old use(params) client pattern. If backend regex starts rejecting cad post-deploy, revisit.

Section 1/2 wiring preserved

  • AnalysisPageContent.tsx imports and renders <Section1ParcelInfo cad={cad} /> (A5) and <Section2NetworksUtilities cad={cad} /> (A6) — verified
  • Section1 + Section2 themselves import useParcelAnalyzeQuery from @/lib/site-finder-api (canonical) — no stale paths
  • Anchor IDs section-1 / section-2 / section-3 / section-3-1..3 / section-4 / section-5 all present for scrollspy (A4)
  • Fixup commit f970671 confirmed restores wiring + deletes duplicate hook

Deletion cleanup

  • frontend/src/hooks/useParcelAnalyzeQuery.ts fully removed from tree (verified via ls-tree)
  • Zero stale imports from old path anywhere in frontend/src/ on branch — git grep returns nothing
  • All callers (Section1, Section2, AnalysisPageContent) now use canonical @/lib/site-finder-api

Section 3 deps verified

  • WeightProfilePanel exists at components/site-finder/WeightProfilePanel.tsx, signature (currentWeights, onWeightsChange(weights, profileId)) matches usage
  • POI_DEFAULT_WEIGHTS + PoiCategoryKey exported from @/lib/api/weightProfiles — import path correct
  • ParcelAnalysisCompetitor.distance_m: number (non-nullable) — radius filter safe
  • 4 chips have aria-pressed={selected} — a11y ✓
  • Radius slider <input type="range" min={1} max={5} step={0.5}> with linked <label htmlFor>

Conventions

  • TS strict — no any, single pragmatic as unknown as ParcelAnalysis cast bridging response/analysis types is documented inline
  • TanStack Query reuse (no new HTTP)
  • CSS tokens (var(--...)) consistent with #353
  • No XSS — cad rendered as text, no dangerouslySetInnerHTML, Link href is static /site-finder

Nits (non-blocking, defer)

  • Chips onlyUnderConstruction / minDeadline3mo / maxAge6mo / onlyApartments toggle state but don't actually filter — comment in applyFilters explicitly acknowledges this is intentional shell awaiting B6 enrichment / Wave 4 backend pass-through. Acceptable per scope.
  • _profileId underscore-prefixed unused arg — fine.

Risk

  • Low — additive UI shell, no backend / DB / migration impact, no auth surface touched
  • Reversibility: trivial revert (3 files, frontend only)
  • Merge window: anytime

Merging via deep-code-reviewer per APPROVE auto-merge policy.

## Deep Code Review — verdict: APPROVE ### Summary - **Status**: APPROVE - **Files reviewed**: 3 (P2: 3) — frontend only - **Lines**: +800 / -167 - **Mergeable**: yes (clean rebase onto `307a75f`, no conflicts) ### Server/Client split (page.tsx) - No `"use client"` — server component ✓ - `generateMetadata({params}): Promise<Metadata>` is `async`, uses `await params` — correct Next 15 async params API - `AnalysisPage` itself is `async`, `await params`, hands decoded `cad` (string) to client component as prop — clean hydration boundary - `<Suspense fallback={...}>` wraps `AnalysisPageContent` so server-streaming works - `decodeURIComponent` from #351 dropped — acceptable: on server, Next router decodes URL segments before populating `params`, so the explicit decode was only needed in the old `use(params)` client pattern. If backend regex starts rejecting `cad` post-deploy, revisit. ### Section 1/2 wiring preserved - `AnalysisPageContent.tsx` imports and renders `<Section1ParcelInfo cad={cad} />` (A5) and `<Section2NetworksUtilities cad={cad} />` (A6) — verified - Section1 + Section2 themselves import `useParcelAnalyzeQuery` from `@/lib/site-finder-api` (canonical) — no stale paths - Anchor IDs `section-1` / `section-2` / `section-3` / `section-3-1..3` / `section-4` / `section-5` all present for scrollspy (A4) - Fixup commit `f970671` confirmed restores wiring + deletes duplicate hook ### Deletion cleanup - `frontend/src/hooks/useParcelAnalyzeQuery.ts` fully removed from tree (verified via `ls-tree`) - Zero stale imports from old path anywhere in `frontend/src/` on branch — `git grep` returns nothing - All callers (Section1, Section2, AnalysisPageContent) now use canonical `@/lib/site-finder-api` ### Section 3 deps verified - `WeightProfilePanel` exists at `components/site-finder/WeightProfilePanel.tsx`, signature `(currentWeights, onWeightsChange(weights, profileId))` matches usage - `POI_DEFAULT_WEIGHTS` + `PoiCategoryKey` exported from `@/lib/api/weightProfiles` — import path correct - `ParcelAnalysisCompetitor.distance_m: number` (non-nullable) — radius filter safe - 4 chips have `aria-pressed={selected}` — a11y ✓ - Radius slider `<input type="range" min={1} max={5} step={0.5}>` with linked `<label htmlFor>` ✓ ### Conventions - TS strict — no `any`, single pragmatic `as unknown as ParcelAnalysis` cast bridging response/analysis types is documented inline - TanStack Query reuse (no new HTTP) - CSS tokens (`var(--...)`) consistent with #353 - No XSS — `cad` rendered as text, no `dangerouslySetInnerHTML`, `Link` href is static `/site-finder` ### Nits (non-blocking, defer) - Chips `onlyUnderConstruction` / `minDeadline3mo` / `maxAge6mo` / `onlyApartments` toggle state but don't actually filter — comment in `applyFilters` explicitly acknowledges this is intentional shell awaiting B6 enrichment / Wave 4 backend pass-through. Acceptable per scope. - `_profileId` underscore-prefixed unused arg — fine. ### Risk - **Low** — additive UI shell, no backend / DB / migration impact, no auth surface touched - **Reversibility**: trivial revert (3 files, frontend only) - **Merge window**: anytime Merging via deep-code-reviewer per APPROVE auto-merge policy.
lekss361 merged commit 68b1968826 into main 2026-05-18 00:55:06 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#356
No description provided.