From 4e0fd3106d8e2795ff30606aeae95d56988d5483 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 29 Sep 2026 12:31:31 +0900 Subject: [PATCH] =?UTF-8?q?feat(B05=C2=B7B06):=20=EC=A7=91=EA=B3=84=20?= =?UTF-8?q?=ED=95=AD=EB=AA=A9=20=EA=B3=A0=EB=A5=B4=EA=B8=B0=EB=A5=BC=20?= =?UTF-8?q?=EA=B3=B5=EC=9A=A9=20=EB=AA=A8=EB=8B=AC(21-5)=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EC=9D=8C=20=C2=B7=20=EC=9E=84=EC=8B=9C=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=20=EC=82=AD=EC=A0=9C(21-9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 임시 Summary_Picker 삭제 · Panel 은 @ui/ui_template_item_picker 의 openItemPicker({current, canCopy}) 결과(apply · clear · cancel)로 처리 - 임시 모달 전용 CSS 삭제 - origin/dev 되받기 충돌 둘(List · Panel_Types) 양쪽 살려 풂 · 쓰지 않는 import 하나 정리 Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01TULoa94ZFL26KU6ZqVpjkF --- .../B05_Profile_UI_Structures_Panel.ts | 10 +- ...05_Profile_UI_Structures_Summary_Picker.ts | 107 ------------------ .../B05_Profile_UI_Style_Structures.css | 12 -- 3 files changed, 5 insertions(+), 124 deletions(-) delete mode 100644 B05_Profile/B05_Profile_UI_Structures_Summary_Picker.ts diff --git a/B05_Profile/B05_Profile_UI_Structures_Panel.ts b/B05_Profile/B05_Profile_UI_Structures_Panel.ts index 78f40336..eb4ab118 100644 --- a/B05_Profile/B05_Profile_UI_Structures_Panel.ts +++ b/B05_Profile/B05_Profile_UI_Structures_Panel.ts @@ -14,7 +14,6 @@ * ========================================================================== */ import { - isB05Option, structureAnchorM, type StructureInstance, type StructuresSectionOptions, @@ -25,7 +24,7 @@ import type { PipeFacility } from "../B04_PreProcess/B04_PreProcess_Api_Fetch"; import { type FacilityAttributes } from "./B05_Profile_UI_Drainage_Facility"; import { field } from "./B05_Profile_UI_Structures_Fields"; import { renderOptionFields as renderOptionFieldsInto } from "./B05_Profile_UI_Structures_Panel_Options"; -import { openItemPicker } from "./B05_Profile_UI_Structures_Summary_Picker"; +import { openItemPicker } from "@ui/ui_template_item_picker"; import { buildStructuresForm } from "./B05_Profile_UI_Structures_Form"; import { bindStructuresEvents, @@ -475,9 +474,10 @@ export function createStructuresSection( // (새 항목은 종전대로 [추가]가 확정). 안 고른 채 닫으면 그대로. summary.bind({ pick: () => { - void openItemPicker({ current: summary.get() }).then((result) => { - if (!result) return; - summary.set("item" in result ? result.item : null); + // canCopy — 개인 층에 쓸 수 없는 사용자의 복사는 서버가 막은 까닭을 모달이 그대로 보임 + void openItemPicker({ current: summary.get(), canCopy: true }).then((result) => { + if (result.action === "cancel") return; + summary.set(result.action === "apply" ? result.item : null); liveCommit(); }); }, diff --git a/B05_Profile/B05_Profile_UI_Structures_Summary_Picker.ts b/B05_Profile/B05_Profile_UI_Structures_Summary_Picker.ts deleted file mode 100644 index 9ae4edfe..00000000 --- a/B05_Profile/B05_Profile_UI_Structures_Summary_Picker.ts +++ /dev/null @@ -1,107 +0,0 @@ -/* ============================================================================= - * B05_Profile_UI_Structures_Summary_Picker.ts - * ⚠ **임시(가짜) 항목 고르기 모달** — 21-5(sub1) `ui_template/ui_template_item_picker.ts` 의 - * `openItemPicker()` 가 오면 이 파일을 지우고 `Summary_Row` 를 쓰는 패널의 import 한 줄만 바꾼다. - * - * 이름 · 돌려주는 값은 21-5 와 맞춘 자리다: - * openItemPicker({ current }) → Promise<{ item } | { clear: true } | null> - * (item = 21-1 `summary_item` · clear = [해제] · null = 닫음) - * 목록은 `GET /api/m02/items?all=1`(21-2) 을 읽고, 아직 없으면(404 등) 같은 21-1 모양의 가짜 세 줄. - * ========================================================================== */ - -import { API_BASE_URL } from "@config/config_frontend"; -import { createButton, el } from "@ui/ui_template_elements"; -import { openModal } from "@ui/ui_template_modal"; -import { - sameSummaryItem, - summaryLabel, - type SummaryItem, - type SummaryLayer, -} from "../common_util/common_util_summary_item"; - -export type ItemPickResult = { item: SummaryItem } | { clear: true } | null; - -interface ItemRow { - key: string; - 이름?: string; - 종류?: string; - 분류1?: string; - layer?: SummaryLayer; - owner?: string | null; -} - -/** 21-2 서버가 없을 때의 가짜 응답 — 21-1 모양. */ -const FAKE_ITEMS: SummaryItem[] = [ - { layer: "system", owner: null, key: "SS000001", name: "돌기슭막이 메쌓기(가짜)" }, - { layer: "company", owner: "가짜회사", key: "SS000002", name: "옹벽 콘크리트(가짜)" }, - { layer: "personal", owner: "가짜회사/가짜사용자", key: "SS000003", name: "돌쌓기 찰쌓기(가짜)" }, -]; - -async function loadItems(): Promise { - try { - const response = await fetch(`${API_BASE_URL}/m02/items?all=1`, { credentials: "include" }); - if (!response.ok) return FAKE_ITEMS; - const rows = (await response.json()) as ItemRow[]; - if (!Array.isArray(rows) || !rows.length) return FAKE_ITEMS; - return rows.map((row) => ({ - layer: row.layer ?? "system", - owner: row.owner ?? null, - key: row.key, - name: row.분류1 ? `${row.종류 ?? ""} · ${row.분류1} · ${row.key}` : (row.종류 ?? row.key), - })); - } catch { - return FAKE_ITEMS; - } -} - -export function openItemPicker(options: { current: SummaryItem | null }): Promise { - return new Promise((resolve) => { - let settled = false; - const finish = (result: ItemPickResult, close?: () => void): void => { - if (settled) return; - settled = true; - close?.(); - resolve(result); - }; - const modal = openModal({ - title: "집계 항목 고르기(임시)", - closeLabel: "닫기", - mount: (body, close) => { - const list = el("div", { className: "b05-structure__pick-list" }); - const apply = createButton({ label: "적용", variant: "filled" }); - apply.disabled = true; - let chosen: SummaryItem | null = null; - void loadItems().then((items) => { - items.forEach((item) => { - const row = createButton({ label: summaryLabel(item), variant: "ghost" }); - row.dataset.b05PickItem = item.key; - // 지금 지정된 항목은 미리 표시(눌러서 바로 [적용] 가능) - if (sameSummaryItem(item, options.current)) { - chosen = item; - apply.disabled = false; - row.classList.add("is-picked"); - } - row.addEventListener("click", () => { - chosen = item; - apply.disabled = false; - list - .querySelectorAll(".is-picked") - .forEach((node) => node.classList.remove("is-picked")); - row.classList.add("is-picked"); - }); - list.append(row); - }); - }); - apply.addEventListener("click", () => chosen && finish({ item: chosen }, close)); - const clear = createButton({ label: "해제", variant: "ghost" }); - clear.addEventListener("click", () => finish({ clear: true }, close)); - body.append(list, el("div", { children: [apply, clear] })); - }, - beforeClose: () => { - finish(null); - return true; - }, - }); - void modal; - }); -} diff --git a/B05_Profile/B05_Profile_UI_Style_Structures.css b/B05_Profile/B05_Profile_UI_Style_Structures.css index d84fa351..ef31e1d8 100644 --- a/B05_Profile/B05_Profile_UI_Style_Structures.css +++ b/B05_Profile/B05_Profile_UI_Style_Structures.css @@ -484,15 +484,3 @@ .b05-route__irregular-item.is-assigned span { color: color-mix(in srgb, var(--color-success) 65%, var(--color-text)); } - -/* 임시 항목 고르기 모달(21-5 가 오면 사라짐) */ -.b05-structure__pick-list { - display: flex; - flex-direction: column; - gap: var(--spacing-4); - margin-bottom: var(--spacing-8); -} - -.b05-structure__pick-list .is-picked { - outline: 2px solid var(--color-success); -}