/* ============================================================================= * M02_MasterTemplete_TreePanel_Roots.ts * 라이브러리 층 단추 셋(마스터 · 회사 · 개인 · PLAN 29-2) — 좌측 패널 「일위대가 라이브러리」 · * 「구조물 조합」 아래 한 줄 · 나무 종류와 무관한 공용 부품. 고른 층의 나무는 부르는 쪽이 이 줄 아래에 붙임. * 권한 없는 층 = 단추 글 끝에 「읽기」(권한 = `accessFor` · 서버 `M02_Layer_Access` 와 짝) * 회사 = 볼 회사(`viewCompany` — 시스템 관리자는 해시 `company` · `aislo.adminCompany` · 자기 회사) * 「사람 고르기」(같은 줄 select · 시스템 관리자만) = 고른 회사 사람의 개인 층 · 고르면 해시 `owner` * 누르면 `go`(부르는 쪽이 해시로 다시 엶). * ========================================================================== */ import { el } from "@ui/ui_template_elements"; import { t as L } from "@ui/ui_template_locale"; import type { SessionUser } from "../A06_Login/A06_Login_Api_Fetch"; import { fetchOwners } from "./M02_MasterTemplete_Api_Fetch"; import { accessFor, buildNeedCompany, layerOfRoot, ownOwner, type Root, } from "./M02_MasterTemplete_Layer"; export interface LayerBarOptions { user: SessionUser | null; /** 지금 고른 층 — `owner` null = 자기 층 */ active: { root: Root; owner: string | null }; /** 볼 회사 id — 없으면 회사 · 개인 단추 없음 */ company: string | null; /** 다른 층을 누름 — `owner` null = 자기 층 */ go: (root: Root, owner: string | null) => void; } /** 회사 단추의 주인 — 볼 회사가 자기 회사면 null(자기 층) */ export const companyOwner = (company: string | null, user: SessionUser | null): string | null => company && company !== ownOwner("company", user) ? company : null; export function createLayerBar(opt: LayerBarOptions): HTMLElement { const { user, active } = opt; const isSystem = user?.role === "SYSTEM_ADMIN"; const ownPersonal = ownOwner("personal", user); if (!opt.company && !isSystem) { return el("div", { className: "m02-layers", children: [button("master", null), buildNeedCompany()], }); } function button(root: Root, owner: string | null): HTMLButtonElement { const readOnly = !accessFor(layerOfRoot(root), owner, user).canWrite; const name = L( root === "master" ? "M02_PickerSystem" : root === "company" ? "M02_PickerCompany" : "M02_PickerPersonal", ); const current = root === active.root && (root !== "personal" || !active.owner); const b = el("button", { className: `m02-layers__btn${current ? " is-active" : ""}`, text: readOnly ? `${name} · ${L("M02_RootReadOnly")}` : name, attrs: { type: "button", "data-root": root, "aria-pressed": String(current) }, }); b.addEventListener("click", () => { if (!current) opt.go(root, owner); }); return b; } const buttons = [ button("master", null), ...(opt.company ? [button("company", companyOwner(opt.company, user))] : []), ...(ownPersonal ? [button("personal", null)] : []), ]; const row = el("div", { className: "m02-layers__row", children: buttons }); const bar = el("div", { className: "m02-layers", children: [row] }); if (isSystem && opt.company) row.append(buildPeople(opt)); // 같은 줄 · 시스템 관리자만 return bar; } /** 「사람 고르기」 — 그 회사 사람(본인 뺌 · 층 폴더 있는 사람)의 개인 층 · 지금 고른 남의 층은 목록에 없어도 보임 */ function buildPeople(opt: LayerBarOptions): HTMLElement { const { active } = opt; const picked = active.root === "personal" ? active.owner : null; const select = el("select", { className: "m02-layers__people", attrs: { "aria-label": L("M02_PeoplePick") }, }) as HTMLSelectElement; const option = (value: string, text: string): HTMLOptionElement => { const one = el("option", { text, attrs: { value } }) as HTMLOptionElement; one.selected = value === (picked ?? ""); return one; }; select.append(option("", "—"), ...(picked ? [option(picked, picked)] : [])); select.disabled = true; void fetchOwners("personal", opt.company) .then((list) => { const rows = picked && !list.some((one) => one.owner === picked) ? [...list, { owner: picked, name: picked }] : list; select.replaceChildren(option("", "—"), ...rows.map((one) => option(one.owner, one.name))); select.disabled = rows.length === 0; select.title = rows.length ? "" : L("M02_RootNone"); }) .catch((error: unknown) => { select.title = error instanceof Error ? error.message : ""; }); select.addEventListener("change", () => { if (select.value) opt.go("personal", select.value); }); return el("label", { className: "m02-layers__pick", children: [el("span", { text: L("M02_PeoplePick") }), select], }); }