/* ============================================================================= * B08_Quantity_UI_Side_FaceDressing.ts * 산출 조건 「면고르기」 구획 — 절토면 토질 · 성토면 시공·토질 고르기 둘 + 면적 덮어쓰기 둘 * (2026-09-14 브레인 판정 Ⓐ~Ⓓ · 서버 ee9368ec). * * 페이지 본문(`B08_Quantity_UI_Page.ts`)이 700줄을 넘어 새 칸을 이 파일로 뺌(CLAUDE.md 4장). * ⚠ 선택지는 **서버가 내려준 목록 그대로**(`face_dressing_choices`) — 화면에 다시 적지 않음(두 벌 금지). * ⚠ 스스로 안 고름(판정 Ⓒ) — 첫 보기가 「안 정함」이고 비면 내역 줄이 입력 사유로 섬. 성토면 제안은 * 회색 근거 + [제안값 넣기]를 **누른 때만**(메인 976e5fd9 `fill_suggested`). * ⚠ 면적은 화면이 셈하지 않음 — 비우면 서버가 파종 면적(초류종자살포 × 반영률)을 씀. * ========================================================================== */ import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale"; import { createButton } from "@ui/ui_template_elements"; import type { SideFieldHelpers } from "./B08_Quantity_UI_Side_TreeWaste"; function L(key: keyof typeof ui_locales): string { return ui_locales[key][currentLanguageIndex]; } export interface FaceDressingDraft { /** `""` 는 「안 정함」 — 서버가 선택지 밖 값도 `""` 로 되돌림. */ face_dressing_cut_class: string; face_dressing_fill_class: string; /** `null` 은 「파종 면적 그대로」. */ face_dressing_fill_area_m2: number | null; face_dressing_cut_area_m2: number | null; dirty: boolean; } export interface FaceDressingChoices { cut: string[]; fill: string[]; /** 성토면 제안(서버 한 곳 · 실무 관측) — 회색으로 보이고 [제안값 넣기]를 **누른 때만** 들어감. */ fill_suggested?: { value: string; basis: string }; } export function appendFaceDressingFields( panel: HTMLElement, draft: FaceDressingDraft, choices: FaceDressingChoices | undefined, h: SideFieldHelpers, ): void { if (!choices) return; const pick = ( label: keyof typeof ui_locales, value: string, list: string[], set: (value: string) => void, ): HTMLElement => h.selectField( L(label), value, [ { value: "", label: L("B08_Quantity_FaceDressing_Unset") }, ...list.map((name) => ({ value: name, label: name })), ], (picked) => { set(picked); draft.dirty = true; }, ); const area = ( label: keyof typeof ui_locales, value: number | null, set: (v: number | null) => void, ) => { const row = h.optionalNumberField(L(label), value, "0.01", (typed) => { set(typed); draft.dirty = true; }); const input = row.querySelector("input"); if (input) input.placeholder = L("B08_Quantity_FaceDressing_Area_Placeholder"); return row; }; panel.append(h.field(L("B08_Quantity_Side_FaceDressing"), "")); panel.append( pick("B08_Quantity_FaceDressing_Cut", draft.face_dressing_cut_class, choices.cut, (v) => { draft.face_dressing_cut_class = v; }), ); const fillRow = pick( "B08_Quantity_FaceDressing_Fill", draft.face_dressing_fill_class, choices.fill, (v) => { draft.face_dressing_fill_class = v; }, ); panel.append(fillRow); // 성토면 제안 — 칸은 비워 둔 채 회색 근거 + 단추(층따기와 같은 모양). 비우면 「안 정함」 그대로. const suggested = choices.fill_suggested; if (suggested?.value) { panel.append( h.hintRow( `${L("B08_Quantity_FaceDressing_Suggest")} ${suggested.value} — ${suggested.basis}`, ), ); panel.append( createButton({ label: L("B08_Quantity_FaceDressing_FillSuggested"), variant: "ghost", onClick: () => { const select = fillRow.querySelector("select"); if (select) select.value = suggested.value; draft.face_dressing_fill_class = suggested.value; draft.dirty = true; }, }), ); } panel.append( area("B08_Quantity_FaceDressing_FillArea", draft.face_dressing_fill_area_m2, (v) => { draft.face_dressing_fill_area_m2 = v; }), ); panel.append( area("B08_Quantity_FaceDressing_CutArea", draft.face_dressing_cut_area_m2, (v) => { draft.face_dressing_cut_area_m2 = v; }), ); panel.append(h.hintRow(L("B08_Quantity_Side_FaceDressing_Hint"))); }