diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDetailDrawer.tsx b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDetailDrawer.tsx index f34cf3e7..70f59890 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDetailDrawer.tsx +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDetailDrawer.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { X, CheckCircle2, Circle, AlertTriangle, ChevronRight, ChevronDown, Trash2, RotateCcw } from "lucide-react"; import { @@ -25,6 +25,17 @@ import { } from "@/app/shadcn_components/ui/tooltip"; import { STAGE_COLORS } from "./types"; import type { ClassifiedDeal, PortfolioCapabilityType, RemovalRequest } from "./types"; +import { parseMeasures } from "@/app/lib/parseMeasures"; + +// Sections that the drawer can scroll-focus on initial open. Keep the keys in +// stable, stage-ordered order so the layout remains predictable. +export type DrawerSection = + | "survey" + | "measures" + | "pibi" + | "domna" + | "halted" + | "technical"; // ----------------------------------------------------------------------- // Removal request section @@ -476,6 +487,34 @@ interface PropertyDetailDrawerProps { userRole: string; userCapability: PortfolioCapabilityType; userEmail: string; + /** + * If provided, the drawer scrolls the named section into view on open. This + * powers entry-points like the Measures table row click that should land + * the user inside the Measures section instead of the top of the drawer. + */ + focusSection?: DrawerSection; +} + +// Section metadata — central to keep the on-screen ordering aligned with the +// stage-ordered acceptance criteria of issue #251. +const SECTION_TITLES: Record = { + survey: "Survey", + measures: "Measures", + pibi: "PIBI", + domna: "Domna Survey", + halted: "Halted", + technical: "Technical Approved", +}; + +function SectionHeader({ id, label }: { id: DrawerSection; label: string }) { + return ( +

+ {label} +

+ ); } export default function PropertyDetailDrawer({ @@ -484,13 +523,54 @@ export default function PropertyDetailDrawer({ onClose, userRole, userCapability, + focusSection, }: PropertyDetailDrawerProps) { const open = !!deal; const [isLogOpen, setIsLogOpen] = useState(false); + // Refs for each scroll-targetable section. + const sectionRefs = useRef>({ + survey: null, + measures: null, + pibi: null, + domna: null, + halted: null, + technical: null, + }); + + // Scroll the requested section into view once the drawer has rendered. + useEffect(() => { + if (!open || !focusSection) return; + // Defer to next tick so the drawer body has mounted. + const t = setTimeout(() => { + const el = sectionRefs.current[focusSection]; + if (el) el.scrollIntoView({ behavior: "smooth", block: "start" }); + }, 50); + return () => clearTimeout(t); + }, [open, focusSection, deal?.dealId]); + + // Parsed measure lists used by the new sections. + const pibiMeasures = parseMeasures(deal?.measuresForPibiOrdered ?? null); + const technicalApprovedMeasures = parseMeasures( + deal?.technicalApprovedMeasuresForInstall ?? null, + ); + + // Domna section: prefer the new text column when present, otherwise fall + // back to the legacy boolean ("Required" / "Not required"). + const domnaSurveyTypeDisplay: string | null = (() => { + if (!deal) return null; + if (deal.domnaSurveyType) return deal.domnaSurveyType; + if (deal.domnaSurveyRequired === true) return "Required"; + if (deal.domnaSurveyRequired === false) return "Not required"; + return null; + })(); + return ( !v && onClose()} direction="right"> - +
{deal && ( @@ -547,7 +627,7 @@ export default function PropertyDetailDrawer({
)} - {/* Key details */} + {/* Property details (general context — kept above stage sections) */}

Property Details

@@ -578,18 +658,95 @@ export default function PropertyDetailDrawer({
- {/* Measures */} - {(deal.proposedMeasures || deal.approvedPackage || deal.actualMeasuresInstalled) && ( -
-

Measures

-
- - - - -
+ {/* Survey section */} +
{ sectionRefs.current.survey = el; }}> + +
+ + + +
- )} +
+ + {/* Measures section — keeps existing approval table content */} +
{ sectionRefs.current.measures = el; }}> + +
+ + + + +
+
+ + {/* PIBI section */} +
{ sectionRefs.current.pibi = el; }}> + +
+ + + 0 ? ( + + {pibiMeasures.map((m) => ( + + {m} + + ))} + + ) : null + } + /> +
+
+ + {/* Domna Survey section */} +
{ sectionRefs.current.domna = el; }}> + +
+ + +
+
+ + {/* Halted section */} +
{ sectionRefs.current.halted = el; }}> + +
+ + +
+
+ + {/* Technical Approved section */} +
{ sectionRefs.current.technical = el; }}> + +
+ 0 ? ( + + {technicalApprovedMeasures.map((m) => ( + + {m} + + ))} + + ) : null + } + /> +
+
{/* Timeline */}