diff --git a/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx b/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx index e94529e29..af09e6eb6 100644 --- a/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx +++ b/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx @@ -1,3 +1,6 @@ +/** + * 지도에서 feature 선택시 팝업 + */ "use client"; import { useWrStore } from "@/app/store"; import CoSttnDetailPopup from "@/components/ui/map/detailPopup/coSttnDetailPopup/coSttnDetailPopup"; @@ -20,7 +23,7 @@ export default function MapFeaturePopup() { coSttnMapDetail } = useWrStore((state) => state); const { pbnMapHeadList } = pbnMap; - const [isDetail, setIsDetail] = useState(undefined); + const [isDetail, setIsDetail] = useState(undefined); // isFeatureCd && layerNm const [layerNm, setLayerNm] = useState(); const searchParams = useSearchParams(); @@ -57,32 +60,32 @@ export default function MapFeaturePopup() { useEffect(() => { console.log(' layerNm ' , layerNm) if (isFeatureCd && layerNm) { - if (layerNm === "tb_wr_bdst_ruse_fclt") { + if (layerNm === "tb_wr_bdst_ruse_fclt") { // 하수재이용시설 setIsDetail(isFeatureCd); - } else if (layerNm === "tb_il_swage_prcs_fclt") { + } else if (layerNm === "tb_il_swage_prcs_fclt") { // 하수처리시설 pbnMapDetaile(isFeatureCd).then((res) => { console.log('res', res) setIsDetail([res]); }); - } else if (layerNm === "tb_wr_rnwtr_utztn_fclt") { + } else if (layerNm === "tb_wr_rnwtr_utztn_fclt") { // 빗물이용시설 rainMapDetile(isFeatureCd).then((res) => { setIsDetail(res); }); - } else if (layerNm === "tb_wr_rswtr_fclt") { + } else if (layerNm === "tb_wr_rswtr_fclt") { // 중수도시설 rswtMapDetile(isFeatureCd).then((res) => { setIsDetail(res); }); - } else if (layerNm === "tb_wr_htdfl_fclt") { + } else if (layerNm === "tb_wr_htdfl_fclt") { // 온배수시설 htdfMapDetile(isFeatureCd).then((res) => { setIsDetail(res); }); - }else if(layerNm ==='tb_wr_ruse_fclt_dmd_co'){ + }else if(layerNm ==='tb_wr_ruse_fclt_dmd_co'){ // 수요처 coSttnMapDetail(isFeatureCd).then((res) => { console.log('tb_wr_ruse_fclt_dmd_co ', res) setIsDetail(res); }); - } else if (layerNm === "tb_wr_tmpr_dmd_co") { + } else if (layerNm === "tb_wr_tmpr_dmd_co") { // 잠재수요처 ldrmntMapDetile(isFeatureCd).then((res) => { setIsDetail(res); }); diff --git a/apps/wr/docs/작업계획/지도팝업_20260626.md b/apps/wr/docs/작업계획/지도팝업_20260626.md new file mode 100644 index 000000000..3da41c87d --- /dev/null +++ b/apps/wr/docs/작업계획/지도팝업_20260626.md @@ -0,0 +1,300 @@ +# 지도 팝업 레이아웃 점검 작업계획 + +작성일: 2026-06-26 +대상 앱: `D:\iipbs\frontend\apps\wr` +대상 화면: +- `http://localhost:3001/mapFeaturePopup?layerNm=tb_wr_bdst_ruse_fclt&featureCd=43150SW001F` +- `http://localhost:3001/mapFeaturePopup?layerNm=tb_wr_tmpr_dmd_co&featureCd=미래산업` +- 선택 팝업 공통 검토 범위: + - `tb_wr_bdst_ruse_fclt` 하수재이용시설 + - `tb_wr_tmpr_dmd_co` 잠재수요처 + - `tb_wr_ruse_fclt_dmd_co` 수요처 + - `tb_wr_rnwtr_utztn_fclt` 빗물이용시설 + - `tb_wr_rswtr_fclt` 중수도시설 + - `tb_wr_htdfl_fclt` 온배수시설 + - `tb_il_swage_prcs_fclt` 하수처리시설 +- 공통 진입 파일: + - `apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx` + - `apps/wr/components/lib/func/mapUtil.ts` + +## 1. 작업 배경 + +- 지도 팝업에서 두 종류의 레이아웃 문제가 확인되었다. +- `하수재이용시설` 팝업은 컨텐츠 높이가 늘어나지 못해 하단 영역이 잘린다. +- `잠재수요처` 팝업은 컨텐츠 자체는 보이지만, 팝업 창 하단이 검은 배경으로 채워지지 않고 흰색 여백으로 남는다. +- 이 문제는 개별 폼 내부만이 아니라 지도 팝업 공통 래퍼, 팝업별 본문 높이 전략, 새 창 크기 전략을 함께 점검해야 재발을 막을 수 있다. + +## 2. 현재 구조 분석 + +### 2.1 지도 팝업 공통 진입 구조 + +- `apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx` + - `layerNm` 값에 따라 서로 다른 상세 컴포넌트를 렌더링한다. + - 공통 본문 래퍼는 다음 클래스를 사용한다. + - `className="box-border m-0 bg-background p-4 pb-24 text-foreground md:p-6"` +- 현재 이 공통 래퍼에는 `min-h-screen`, `min-h-dvh`, `h-full` 같은 viewport 채움 조건이 없다. +- 따라서 컨텐츠 높이가 창 높이보다 작을 때는 문서 body의 기본 배경색이 하단에 그대로 노출될 수 있다. + +### 2.2 하수재이용시설 경로 + +- `mapFeaturePopup/page.tsx` + - `layerNm === "tb_wr_bdst_ruse_fclt"` 일 때 `RuseDetailPopup` 렌더링 +- `apps/wr/components/ui/map/detailPopup/ruseDetailPopup.tsx` + - 시설별 탭을 만들고 각 탭에서 `PbnstSttnModal data={item} isMap={true}` 렌더링 +- `apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx:257` + - `const Wrapper: React.ElementType = isMap ? "div" : ScrollArea;` +- `apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx:267` + - 지도 팝업 여부와 무관하게 `` 적용 +- 지도 팝업에서는 `Wrapper`가 일반 `div`이므로: + - 내부 스크롤이 생기지 않고 + - 높이만 `70vh`로 고정되어 + - 아래쪽 `하수재이용시설 현황`, `하수재이용실적` 테이블이 박스 밖으로 밀린다. + +### 2.3 잠재수요처 경로 + +- `mapFeaturePopup/page.tsx` + - `layerNm === "tb_wr_tmpr_dmd_co"` 일 때 `CoDetailModal isMap={true}` 렌더링 +- `apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx` + - 내부 본문은 `` 사용 +- 즉 잠재수요처는 내부 폼 스크롤은 이미 있으나, + - 공통 팝업 바깥 래퍼가 viewport 전체 높이를 채우지 못하면 + - 컨텐츠가 끝난 뒤 창 하단의 남는 공간이 `bg-background`가 아닌 흰색으로 보일 수 있다. +- 추가로 `pb-24` 같은 하단 padding이 공통 래퍼에 고정 적용되어 있어, + - 팝업별 실제 본문 높이와 맞지 않으면 시각적으로 불필요한 하단 여백처럼 보일 수 있다. + +### 2.4 다른 선택 팝업 경로 + +- `tb_wr_ruse_fclt_dmd_co` + - `apps/wr/components/ui/map/detailPopup/coSttnDetailPopup/coSttnDetailPopup.tsx` + - 내부 `bodyClassNm={"w-full mx-auto bg-background rounded-lg shadow-md p-6"}` 사용 +- `tb_wr_rnwtr_utztn_fclt`, `tb_wr_rswtr_fclt`, `tb_wr_htdfl_fclt` + - `apps/wr/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal.tsx` + - 별도 `ScrollArea`는 주석 처리되어 있고, 최상위 공통 팝업 래퍼 의존도가 높다. +- `tb_il_swage_prcs_fclt` + - `mapFeaturePopup/page.tsx` 안에서 `UiTable` 2개를 직접 렌더링 + - 역시 공통 래퍼 배경/높이 정책의 영향을 그대로 받는다. + +### 2.5 흰 여백이 없는 팝업과 있는 팝업의 구조 차이 + +- 흰 여백이 없다고 확인된 팝업: + - `tb_wr_ruse_fclt_dmd_co` + - `tb_wr_rnwtr_utztn_fclt` + - `tb_wr_rswtr_fclt` +- 흰 여백이 나타난다고 확인된 팝업: + - `tb_wr_tmpr_dmd_co` + - `tb_wr_bdst_ruse_fclt` + - `tb_il_swage_prcs_fclt` + +차이점 1. 개별 본문 컴포넌트의 배경 책임 + +- 흰 여백이 없는 `tb_wr_ruse_fclt_dmd_co`는 + - `coSttnDetailPopup.tsx:23`에서 `bodyClassNm={"w-full mx-auto bg-background rounded-lg shadow-md p-6"}`를 직접 넘긴다. + - 즉 공통 팝업 래퍼 바깥이 아니라, 실제 본문 카드 자체가 `bg-background`를 명시적으로 가진다. +- 반대로 `tb_wr_tmpr_dmd_co`는 + - `coDatailModal.tsx:52`의 최상위가 단순 `
`이고, + - 내부는 `ScrollArea className="h-[79vh] mx-8"` 중심 구조다. + - 본문 전체 배경을 개별 카드로 강하게 감싸기보다 공통 팝업 래퍼 배경에 더 의존한다. +- `tb_il_swage_prcs_fclt`는 + - `mapFeaturePopup/page.tsx:103` 이하에서 `UiTable` 2개를 직접 렌더링하고, + - 별도 카드형 본문 래퍼 없이 공통 래퍼 위에 바로 쌓는다. + +차이점 2. 본문 높이 점유 방식 + +- 흰 여백이 없는 `tb_wr_rnwtr_utztn_fclt`, `tb_wr_rswtr_fclt`는 + - `sttnDetailModal.tsx:81` 이하에서 상세 폼 컴포넌트를 직접 렌더링한다. + - 현재 지도 팝업용 `ScrollArea`는 주석 처리되어 있어, 공통 래퍼 안에서 폼이 자연 높이로 이어진다. + - 실제 데이터량이 비교적 충분하면 본문이 창 하단 가까이까지 내려와 흰 여백이 드러나지 않을 수 있다. +- 반대로 `tb_wr_tmpr_dmd_co`는 + - `coDatailModal.tsx:67`의 `h-[79vh]` 스크롤 영역이 명시되어 있고, + - 바깥 공통 래퍼에는 `pb-24`가 남아 있어 하단 잔여 공간이 시각적으로 더 잘 드러날 가능성이 있다. +- `tb_wr_bdst_ruse_fclt`는 + - `pbnstSttnModal.tsx:267`에서 `h-[70vh]` 고정 높이를 사용한다. + - 이 경우 본문이 자연스럽게 창 끝까지 이어지지 못하고, 잘림 또는 하단 여백 문제가 함께 나타날 수 있다. + +차이점 3. 공통 래퍼 의존도 + +- 흰 여백이 없는 쪽은 + - 개별 컴포넌트가 자체 배경 카드나 충분한 컨텐츠 높이를 가져 공통 래퍼 결함이 눈에 덜 띈다. +- 흰 여백이 있는 쪽은 + - 개별 카드 배경이 약하거나 + - 본문 높이가 고정되거나 짧아 + - `mapFeaturePopup/page.tsx:100`의 공통 래퍼가 viewport 끝까지 채워지지 않는 문제가 바로 노출된다. + +### 2.6 팝업 창 자체 크기 + +- `apps/wr/components/lib/func/mapUtil.ts:146` + - 하수재이용시설: `window.innerHeight - 100` + - 잠재수요처: `window.innerHeight - 300` + - 수요처: `window.innerHeight - 430` +- 팝업 창 크기 자체 차이도 존재하지만, +- 이번 증상은 우선 새 창 크기보다 내부 공통 래퍼와 개별 팝업의 높이 전략 불일치 영향이 더 크다. + +## 3. 문제 유형 정리 + +### 3.1 유형 A: 내부 컨텐츠 잘림 + +- 대상: + - `tb_wr_bdst_ruse_fclt` +- 원인: + - `isMap=true`인데도 내부 래퍼가 `h-[70vh]`로 고정 + - `ScrollArea`가 아닌 일반 `div`라서 컨텐츠가 늘어나지 못함 + +### 3.2 유형 B: 팝업 하단 흰색 잔여 영역 + +- 우선 확인 대상: + - `tb_wr_tmpr_dmd_co` +- 함께 점검할 대상: + - `tb_wr_bdst_ruse_fclt` + - `tb_il_swage_prcs_fclt` +- 원인 후보: + - 공통 래퍼가 viewport 전체 높이를 채우지 않음 + - 공통 래퍼의 하단 padding이 팝업별 컨텐츠 높이와 맞지 않음 + - 팝업별 내부 스크롤 높이와 새 창 높이 계산이 제각각임 + - 개별 팝업이 본문 배경을 자체적으로 채우지 못하고 공통 래퍼에 의존함 + +## 4. 수정 대상 + +### 4.1 공통 우선 수정 파일 + +- `D:\iipbs\frontend\apps\wr\app\(popUp-layout)\mapFeaturePopup\page.tsx` + +### 4.2 하수재이용시설 직접 수정 파일 + +- `D:\iipbs\frontend\apps\wr\components\ui\modal\sttn\pbnstSttnModal\pbnstSttnModal.tsx` +- `D:\iipbs\frontend\apps\wr\components\ui\map\detailPopup\ruseDetailPopup.tsx` +- `D:\iipbs\frontend\apps\wr\components\ui\form\fcltReg\pbnstReg\mngReg\mngRegForm.tsx` + +### 4.3 잠재수요처 및 타 팝업 점검 파일 + +- `D:\iipbs\frontend\apps\wr\components\ui\modal\sttn\sttnDetailModal\coDatailModal.tsx` +- `D:\iipbs\frontend\apps\wr\components\ui\map\detailPopup\coSttnDetailPopup\coSttnDetailPopup.tsx` +- `D:\iipbs\frontend\apps\wr\components\ui\modal\sttn\sttnDetailModal\sttnDetailModal.tsx` +- `D:\iipbs\frontend\apps\wr\components\lib\func\mapUtil.ts` + +## 5. 권장 구현 방향 + +### 5.1 공통 팝업 래퍼 정규화 + +- `mapFeaturePopup/page.tsx`의 최상위 래퍼를 지도 팝업 공통 레이아웃 기준점으로 삼는다. +- 다음 방향으로 정리하는 것이 우선이다. +- `bg-background`가 항상 팝업 창 하단까지 채워지도록 `min-h-screen` 또는 `min-h-dvh` 적용 +- 필요 시 `h-full`과 조합해 새 창 viewport를 안정적으로 덮도록 조정 +- 공통 `pb-24`는 팝업별로 과도한 여백을 만드는지 점검하고, 필요하면 축소 또는 분기 처리 + +### 5.2 하수재이용시설 전용 높이 분기 + +- `PbnstSttnModal`에서 `isMap`일 때 `h-[70vh]`를 제거하거나 `max-h` 기반으로 완화 +- 비지도 화면에서는 기존 `ScrollArea + h-[70vh]` 유지 +- 지도 팝업에서는: + - 본문 전체가 자연스럽게 늘어나게 하거나 + - 큰 테이블만 별도 스크롤 처리 + +### 5.3 잠재수요처 하단 흰 영역 대응 + +- `CoDetailModal` 자체의 `ScrollArea h-[79vh]`는 유지하되, +- 먼저 공통 팝업 래퍼의 배경/최소높이 문제를 해결한다. +- 그 다음에도 하얀 영역이 남으면 아래 순서로 추가 점검: + - `pb-24` 제거 또는 축소 시 시각적 개선 여부 + - `ScrollArea` 높이를 `79vh` 고정 대신 `calc(100vh - 헤더/패딩)` 기반으로 변경할지 검토 + - 팝업 창 자체 높이(`mapUtil.ts`)가 본문 높이 전략과 맞는지 재조정 + +### 5.4 선택된 타 팝업 공통 점검 + +- 잠재수요처 수정과 동일한 공통 래퍼 아래에서 동작하는 팝업들은 모두 한 번씩 확인한다. +- 특히 다음을 확인: + - 컨텐츠가 짧을 때 창 하단이 흰색으로 비는지 + - 컨텐츠가 길 때 내부 스크롤/전체 스크롤이 자연스러운지 + - 배경색이 본문 카드까지만 적용되고 바깥 여백은 흰색으로 남지 않는지 +- 이번 확인 결과상 우선순위는 두 그룹으로 나눈다. +- 흰 여백 발생 그룹: + - `tb_wr_tmpr_dmd_co` + - `tb_wr_bdst_ruse_fclt` + - `tb_il_swage_prcs_fclt` +- 비교 기준 그룹: + - `tb_wr_ruse_fclt_dmd_co` + - `tb_wr_rnwtr_utztn_fclt` + - `tb_wr_rswtr_fclt` + +## 6. 상세 작업 단계 + +### 단계 1. 공통 래퍼 수정 + +- `mapFeaturePopup/page.tsx` + - 최상위 래퍼에 viewport 채움 클래스 추가 + - `pb-24`의 필요성 재검토 + - 팝업 종류별로 공통 패딩 분기 필요 여부 확인 + +### 단계 2. 하수재이용시설 잘림 수정 + +- `pbnstSttnModal.tsx` + - `isMap`일 때 `h-[70vh]` 제거 또는 `max-h`로 전환 + - 비지도 화면 동작은 유지 +- 필요 시: + - `RuseDetailPopup`의 `TabsContent` + - `PbnstMngForm` 내부 `h-[200px] overflow-y-auto` + - `하수재이용실적` 테이블 영역 + - 순서로 추가 보정 + +### 단계 3. 잠재수요처 하단 흰 영역 점검 + +- `coDatailModal.tsx` + - 공통 래퍼 수정 후에도 하얀 하단이 남는지 재확인 + - 남는 경우 `ScrollArea h-[79vh]`를 `calc()` 기반으로 조정 검토 +- 함께 비교: + - `coSttnDetailPopup.tsx`의 `bodyClassNm bg-background` 구조와 어떤 차이로 결과가 갈리는지 확인 +- `mapUtil.ts` + - 잠재수요처 팝업 높이(`window.innerHeight - 300`)가 현재 본문 구조와 맞는지 재검토 + +### 단계 4. 선택된 타 팝업 회귀 점검 + +- 발생 그룹 확인: + - `tb_wr_tmpr_dmd_co` + - `tb_wr_bdst_ruse_fclt` + - `tb_il_swage_prcs_fclt` +- 비교 그룹 확인: + - `tb_wr_ruse_fclt_dmd_co` + - `tb_wr_rnwtr_utztn_fclt` + - `tb_wr_rswtr_fclt` +- 두 그룹 비교 기준: + - 개별 본문이 `bg-background` 카드를 직접 가지는지 + - 본문이 자연 높이인지 고정 `vh` 높이인지 + - 공통 래퍼 `pb-24`와 결합될 때 하단 빈 공간이 드러나는지 +- 이후 추가 증상이 확인되면: + - 공통 래퍼로 해결 가능한지 우선 판단 + - 개별 컴포넌트 고정 높이/패딩이 있으면 2차 수정 대상으로 분리 + +## 7. 구현 시 주의사항 + +- 지도 팝업 컴포넌트들은 일반 화면/등록 화면과 공용인 경우가 많다. +- 따라서 수정은 반드시 `isMap` 또는 팝업 전용 경로 기준으로 제한해야 한다. +- `PbnstSttnModal`의 일반 화면 `ScrollArea + h-[70vh]` 동작은 회귀되지 않게 유지해야 한다. +- 잠재수요처의 경우 내부 폼이 아니라 바깥 공통 래퍼 문제일 가능성이 크므로, 개별 폼 높이부터 섣불리 줄이지 않는다. +- `UiTable`, `ScrollArea`, 카드형 래퍼가 혼합되어 있어, 공통 래퍼와 개별 본문 래퍼의 책임을 분리해서 봐야 한다. + +## 8. 검증 계획 + +### 8.1 하수재이용시설 검증 + +- `tb_wr_bdst_ruse_fclt` 클릭 시 팝업 본문 하단이 잘리지 않는다. +- `하수재이용시설 현황` 아래 `하수재이용실적` 영역이 같은 배경 안에서 정상적으로 이어진다. +- 데이터가 길어도 전체 스크롤 또는 의도한 내부 스크롤이 정상 동작한다. + +### 8.2 잠재수요처 검증 + +- `tb_wr_tmpr_dmd_co` 클릭 시 마지막 입력 필드 아래로 흰색 빈 영역이 남지 않는다. +- 팝업 창 하단까지 `bg-background`가 자연스럽게 이어진다. +- 내부 스크롤은 유지되되, 배경색이 창 하단에서 끊기지 않는다. + +### 8.3 선택 팝업 공통 검증 + +- 발생 그룹인 `tb_wr_tmpr_dmd_co`, `tb_wr_bdst_ruse_fclt`, `tb_il_swage_prcs_fclt`는 흰 여백이 제거되는지 확인한다. +- 비교 그룹인 `tb_wr_ruse_fclt_dmd_co`, `tb_wr_rnwtr_utztn_fclt`, `tb_wr_rswtr_fclt`는 기존처럼 흰 여백 없이 유지되는지 확인한다. +- 컨텐츠가 짧은 팝업에서 하단 흰색 잔여 영역이 남지 않는다. +- 컨텐츠가 긴 팝업에서 잘림 없이 스크롤이 가능하다. + +## 9. 결론 + +- 이번 이슈는 `하수재이용시설`의 고정 높이 문제와 `잠재수요처`·`하수처리시설`의 하단 배경 노출 문제로 나뉘지만, 비교 결과 공통 출발점은 `mapFeaturePopup/page.tsx` 공통 래퍼다. +- 1차 우선순위는 `mapFeaturePopup/page.tsx` 공통 래퍼를 viewport 기준으로 정규화하는 것이다. +- 2차 우선순위는 `PbnstSttnModal`의 지도 팝업 전용 `70vh` 고정 높이 제거다. +- 이후에는 "개별 본문 배경을 직접 가지는 팝업"과 "공통 래퍼 배경에 의존하는 팝업"의 차이를 기준으로, 하단 흰색 잔여 영역과 컨텐츠 잘림을 함께 정리하는 것이 맞다.