/* ============================================================================= * B02_ProjRegister_UI_Page.ts * 로그인 후 02: 프로젝트 등록 (신규 임도 설계 프로젝트 기본 정보 입력) * * 제약 준수 (frontend.md): * - 모든 문구는 ui_template_locale.ts 참조 (하드코딩 금지, §3). * - 색상/간격은 theme.css 변수 + 공통 컴포넌트만 사용 (§1, §2). * - 이벤트 핸들러는 onB02_[기능]_[액션] 명명 (§4). * - 백엔드 전송 전 1차 유효성 검사 (§4). * ========================================================================== */ import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale"; import { createButton, createInputField, createCard, showToast } from "@ui/ui_template_elements"; import { isBlank } from "@util/common_util_validate"; import { navigateTo } from "../A00_Common/router"; import { ROUTES } from "@config/config_frontend"; import "./B02_ProjRegister_UI_Style.css"; /** locale 헬퍼 */ function L(key: keyof typeof ui_locales): string { return ui_locales[key][currentLanguageIndex]; } /** select 필드 핸들 (공통 .ui-field/.ui-input 스타일 상속) */ interface SelectFieldHandle { root: HTMLDivElement; select: HTMLSelectElement; } /** 드롭다운 필드 생성 (공통 컴포넌트에 없어 로컬 정의, 공통 스타일 상속) */ function createSelectField( label: string, options: { value: string; text: string }[], ): SelectFieldHandle { const root = document.createElement("div"); root.className = "ui-field"; const labelEl = document.createElement("label"); labelEl.className = "ui-field__label"; labelEl.textContent = label; const select = document.createElement("select"); select.className = "ui-input b02-proj__select"; for (const opt of options) { const optionEl = document.createElement("option"); optionEl.value = opt.value; optionEl.textContent = opt.text; select.append(optionEl); } root.append(labelEl, select); return { root, select }; } /* ----------------------------------------------------------------------------- * 페이지 진입점 * -------------------------------------------------------------------------- */ export function renderB02ProjRegister(root: HTMLElement): void { const page = document.createElement("div"); page.className = "b02-proj"; const header = document.createElement("div"); header.className = "b02-proj__header"; const title = document.createElement("h1"); title.className = "b02-proj__title"; title.textContent = L("B02_Proj_Title"); const subtitle = document.createElement("p"); subtitle.className = "b02-proj__subtitle"; subtitle.textContent = L("B02_Proj_Subtitle"); header.append(title, subtitle); // 입력 필드 const nameField = createInputField({ label: L("B02_Proj_Field_Name"), placeholder: L("B02_Proj_Field_Name_Placeholder"), required: true, }); const regionField = createInputField({ label: L("B02_Proj_Field_Region"), placeholder: L("B02_Proj_Field_Region_Placeholder"), required: true, }); const roadTypeField = createSelectField(L("B02_Proj_Field_RoadType"), [ { value: "main", text: L("B02_Proj_RoadType_Main") }, { value: "branch", text: L("B02_Proj_RoadType_Branch") }, { value: "fire", text: L("B02_Proj_RoadType_Fire") }, { value: "stream", text: L("B02_Proj_RoadType_Stream") }, ]); const currentYear = new Date().getFullYear(); const yearField = createInputField({ label: L("B02_Proj_Field_Year"), type: "number", value: String(currentYear), min: 2000, max: currentYear + 5, }); const lengthField = createInputField({ label: L("B02_Proj_Field_Length"), placeholder: L("B02_Proj_Field_Length_Placeholder"), type: "number", min: 0, }); const memoField = createInputField({ label: L("B02_Proj_Field_Memo"), placeholder: L("B02_Proj_Field_Memo_Placeholder"), type: "text", }); const submitBtn = createButton({ label: L("B02_Proj_Submit"), variant: "filled", onClick: onB02_Proj_Submit_Click, }); submitBtn.classList.add("b02-proj__submit"); function onB02_Proj_Submit_Click(): void { nameField.setError(); regionField.setError(); // 1차 유효성: 필수값 검사 let hasError = false; if (isBlank(nameField.input.value)) { nameField.setError(L("B02_Proj_Error_Required")); hasError = true; } if (isBlank(regionField.input.value)) { regionField.setError(L("B02_Proj_Error_Required")); hasError = true; } if (hasError) return; // TODO: POST /api/b02/project 연동 (로딩 오버레이 + 성공/실패 처리). // 성공 시 반환된 프로젝트 ID로 storage 폴더 생성 후 파일 입력으로 이동. showToast(L("B02_Proj_Success"), "success"); navigateTo(ROUTES.B03_FILE_INPUT); } const grid = document.createElement("div"); grid.className = "b02-proj__grid"; grid.append( nameField.root, regionField.root, roadTypeField.root, yearField.root, lengthField.root, memoField.root, ); const card = createCard({ body: [grid, submitBtn], raised: true }); page.append(header, card); root.append(page); }