/* ============================================================================= * 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; }); }