- 알약을 컨테이너 제목 바로 옆 왼쪽 맞춤(다섯 컨테이너 같게 · 제목과 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
101 lines
4.0 KiB
TypeScript
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();
|
|
}
|