Files
Aislo/B01_Dashboard/B01_Dashboard_UI_CompanyPick.ts
T
eomsangdonandClaude Opus 5.5 9ed36efe08 fix(B01): 회사 알약 제목 바로 옆 · 누르면 조회 후 고르기 창(29-5)
- 알약을 컨테이너 제목 바로 옆 왼쪽 맞춤(다섯 컨테이너 같게 · 제목과 16px)
- 드롭다운 메뉴 대신 회사 고르기 창: 찾기 칸(이름 · 사업자번호 · 띄어쓰기 단어 모두) → 거른 목록(최근 등록 순 · 50줄까지 · 넘으면 좁히라는 안내) → 줄 누름 또는 Enter 로 고름 · Esc · 바깥 누름 닫기
- 공용 item_picker 는 구조물 항목 전용이라 안 씀 · B01 모달 꼴 새 파일 B01_Dashboard_UI_CompanyPick
- 시험 test_b01_settings_cards 맞춤 · 거르기 시험 보탬

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ly2oHAaTDYRjcniAmHR81z
2026-09-30 18:10:21 +09:00

101 lines
4.0 KiB
TypeScript

/* =============================================================================
* 회사 조회 후 고르기(시스템 관리자 회사 알약 · 29-5)
* 찾기 칸(이름 · 사업자번호 · 띄어쓰기 단어 모두 맞음) → 거른 목록(처음엔 최근 등록 순) →
* 줄 누르면 고름. 목록은 LIMIT 줄까지만 그림 — 회사가 많아도 찾기로 좁힘.
* ========================================================================== */
import { createButton, createInputField } from "@ui/ui_template_elements";
import type { CompanyInfo } from "./B01_Dashboard_Api_Fetch";
import { L } from "./B01_Dashboard_UI_Common";
const LIMIT = 50;
/** 이름 · 사업자번호(줄표 빼고도)에 모든 단어가 들어간 회사 — 순서는 받은 그대로 */
export function filterCompanies(companies: CompanyInfo[], text: string): CompanyInfo[] {
const words = text.toLowerCase().split(/\s+/).filter(Boolean);
return companies.filter((c) => {
const no = c.business_registration_number ?? "";
const hay = `${c.name} ${no} ${no.replace(/-/g, "")}`.toLowerCase();
return words.every((w) => hay.includes(w));
});
}
export function openCompanyPicker(
companies: CompanyInfo[],
currentId: number | null,
onPick: (company: CompanyInfo) => void,
): void {
const modal = document.createElement("div");
modal.className = "b01-dashboard__modal";
const panel = document.createElement("div");
panel.className = "b01-dashboard__modal-panel";
const heading = document.createElement("h3");
heading.className = "b01-dashboard__modal-title";
heading.textContent = L("B01_Dashboard_PickCompany");
const query = createInputField({
label: L("B01_Dashboard_Field_Search"),
placeholder: L("B01_Dashboard_PickCompanyHint"),
});
const count = document.createElement("p");
count.className = "b01-dashboard__company-count";
const list = document.createElement("div");
list.className = "b01-dashboard__company-list";
const close = (): void => {
modal.remove();
document.removeEventListener("keydown", onKey, true);
};
const pick = (company: CompanyInfo): void => {
close();
onPick(company);
};
let shown: CompanyInfo[] = [];
const render = (): void => {
const found = filterCompanies(companies, query.input.value);
shown = found.slice(0, LIMIT);
count.textContent =
found.length > LIMIT
? L("B01_Dashboard_PickCompanyMore")
.replace("{count}", String(found.length))
.replace("{limit}", String(LIMIT))
: L("B01_Dashboard_PickCompanyCount").replace("{count}", String(found.length));
list.replaceChildren(
...shown.map((company) => {
const row = document.createElement("button");
row.type = "button";
row.className = "b01-dashboard__company-row";
row.classList.toggle("is-current", company.id === currentId);
const name = document.createElement("span");
name.textContent = company.name;
const no = document.createElement("small");
no.textContent = company.business_registration_number ?? "";
row.append(name, no);
row.addEventListener("click", () => pick(company));
return row;
}),
);
};
// Enter = 첫 줄 고름 · Esc = 닫기
const onKey = (event: KeyboardEvent): void => {
if (event.key === "Escape") close();
else if (event.key === "Enter" && event.target === query.input && shown[0]) pick(shown[0]);
else return;
event.preventDefault();
event.stopPropagation();
};
query.input.addEventListener("input", render);
document.addEventListener("keydown", onKey, true);
modal.addEventListener("click", (event) => {
if (event.target === modal) close();
});
const actions = document.createElement("div");
actions.className = "b01-dashboard__actions";
actions.append(createButton({ label: L("Common_Btn_Cancel"), variant: "ghost", onClick: close }));
panel.append(heading, query.root, count, list, actions);
modal.append(panel);
document.body.append(modal);
render();
query.input.focus();
}