/* ============================================================================= * M02_MyMachine_View.ts * M02 「내 기계」 화면(PLAN 821-3 · 요구서 796 3 장) — 좌측 「내 기계」 칸을 펼치면 가운데에 뜸(개인 층). * 목록 = 이름 · 규격 · 방식 · 시간당 경비(서버 셈) · 쓰는 곳 수 · 넣은 날 · 고친 날 · 찾기 · [새 기계] * 줄 누름 = 양식 한 장(`M02_MyMachine_Form`) · [목록] = 저장 안 한 고침이면 물음 · 저장 · 지우기 뒤 목록 다시 * ========================================================================== */ import { createButton } from "@ui/ui_template_button"; import { createDataTable } from "@ui/ui_template_data_table"; import { createInputField, el, showConfirmDialog, showToast } from "@ui/ui_template_elements"; import { createText } from "@ui/ui_template_text"; import { listMyMachines, type MyMachineRow } from "./M02_MyMachine_Api"; import { mountMyMachineForm } from "./M02_MyMachine_Form"; import { mt, type MtKey } from "./M02_MyMachine_Text"; import "./M02_MyMachine.css"; export interface MyMachineViewOptions { owner: string | null; /** 저장 안 한 고침 표시(페이지 떠남 물음) */ setDirty: (dirty: boolean) => void; } const day = (t: string | undefined): string => (t ?? "").slice(0, 10); export function buildMyMachineView(opt: MyMachineViewOptions): HTMLElement { const host = el("div", { className: "m02-mymach-view" }); let rows: MyMachineRow[] = []; let shown: MyMachineRow[] = []; let dirty = (): boolean => false; const mark = (d: boolean): void => opt.setDirty(d); const search = createInputField({ type: "search", placeholder: mt("Find") }); const hint = createText(""); const fail = el("div"); const table = createDataTable({ caption: mt("Title"), columns: [ { key: "이름", label: mt("Name"), width: 180 }, { key: "규격", label: mt("Spec"), width: 120 }, { key: "방식", label: mt("How"), width: 100 }, { key: "시간당", label: mt("Hourly"), kind: "number", decimals: 0, width: 110 }, { key: "쓰는곳", label: mt("Uses_Count"), kind: "number", decimals: 0, width: 70 }, { key: "넣은날", label: mt("Made"), width: 96 }, { key: "고친날", label: mt("Edited"), width: 96 }, ], rows: [], empty: mt("None"), onRowClick: (i) => shown[i] && void openForm(shown[i].키), }); const draw = (): void => { const words = search.input.value.trim().toLowerCase().split(/\s+/).filter(Boolean); shown = rows.filter((r) => { const text = `${r.이름} ${r.규격} ${r.키}`.toLowerCase(); return words.every((w) => text.includes(w)); }); hint.textContent = rows.length ? `${shown.length} / ${rows.length}` : ""; table.setRows( shown.map((r) => ({ 이름: r.이름, 규격: r.규격, 방식: mt(r.방식 as MtKey), 시간당: r.시간당.ok ? (r.시간당.계 ?? null) : null, 쓰는곳: r.쓰는곳수, 넣은날: day(r.넣은날), 고친날: day(r.고친날), })), ); }; search.input.addEventListener("input", draw); const newBtn = createButton({ label: mt("New"), variant: "filled", size: 28, onClick: () => void openForm(), }); newBtn.dataset.mymachNew = ""; const list = el("div", { className: "m02-mymach-view__list", children: [ el("div", { className: "ui-toolbar", children: [newBtn, search.root, hint] }), createText(mt("Own_Note"), "muted"), fail, table.root, ], }); async function showList(): Promise { dirty = () => false; mark(false); host.replaceChildren(list); fail.replaceChildren(); try { rows = await listMyMachines(opt.owner); } catch (error) { rows = []; fail.replaceChildren( createText(error instanceof Error ? error.message : mt("Personal_Only"), "error"), ); } draw(); } async function openForm(key?: string): Promise { const slot = el("div"); host.replaceChildren(slot); try { const h = await mountMyMachineForm(slot, { owner: opt.owner, key, onSaved: (got) => void openForm(got.줄.키), onDeleted: () => void showList(), onBack: async () => { if (!dirty() || (await showConfirmDialog(mt("Leave_Ask")))) await showList(); }, onDirty: mark, }); dirty = h.dirty; } catch (error) { showToast(error instanceof Error ? error.message : mt("Failed"), "error"); await showList(); } } void showList(); return host; }