/* ============================================================================= * A06_Login_UI_Page.ts * 로그인 전 06: 로그인 (이메일 + 비밀번호 폼) * * 제약 준수: * - 모든 문구는 ui_template_locale.ts 참조 (하드코딩 금지). * - 색상/간격은 A06_Login_UI_Style.css + theme.css 변수만 사용. * - 공통 컴포넌트(createButton/createInputField/createCard) 우선 사용. * - 이벤트 핸들러는 on[페이지]_[기능]_[액션] 명명. * - 백엔드 전송 전 1차 유효성 검사 (frontend.md §4). * ========================================================================== */ import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale"; import { createButton, createInputField } from "@ui/ui_template_elements"; import { isBlank, isValidEmail } from "@util/common_util_validate"; import { navigateTo } from "../A00_Common/router"; import { ROUTES, AUTH_TOKEN_KEY } from "@config/config_frontend"; import "./A06_Login_UI_Style.css"; /** locale 헬퍼 */ function L(key: keyof typeof ui_locales): string { return ui_locales[key][currentLanguageIndex]; } /* ----------------------------------------------------------------------------- * 페이지 진입점 * -------------------------------------------------------------------------- */ export function renderA06Login(root: HTMLElement): void { const page = document.createElement("div"); page.className = "a06-login"; const card = document.createElement("div"); card.className = "a06-login__card"; const title = document.createElement("h1"); title.className = "a06-login__title"; title.textContent = L("A06_Login_Title"); const subtitle = document.createElement("p"); subtitle.className = "a06-login__subtitle"; subtitle.textContent = L("A06_Login_Subtitle"); // 입력 필드 const emailField = createInputField({ label: L("A06_Login_Field_Email"), placeholder: L("A06_Login_Field_Email_Placeholder"), type: "email", required: true, }); const passwordField = createInputField({ label: L("A06_Login_Field_Password"), placeholder: L("A06_Login_Field_Password_Placeholder"), type: "password", required: true, }); const form = document.createElement("form"); form.className = "a06-login__form"; form.noValidate = true; const submitBtn = createButton({ label: L("A06_Login_Submit"), variant: "filled", type: "submit", }); submitBtn.classList.add("a06-login__submit"); /* 이벤트 핸들러: 제출 시 1차 유효성 검사 */ function onA06_Login_Submit_Click(event: Event): void { event.preventDefault(); emailField.setError(); passwordField.setError(); const email = emailField.input.value; const password = passwordField.input.value; if (isBlank(email) || isBlank(password)) { if (isBlank(email)) emailField.setError(L("A06_Login_Error_Required")); if (isBlank(password)) passwordField.setError(L("A06_Login_Error_Required")); return; } if (!isValidEmail(email)) { emailField.setError(L("A06_Login_Error_Email")); return; } // TODO: POST /api/a06/login 연동. 성공 시 토큰 저장 후 계정 페이지로. localStorage.setItem(AUTH_TOKEN_KEY, "dev-placeholder-token"); navigateTo(ROUTES.B01_ACCOUNT); } form.addEventListener("submit", onA06_Login_Submit_Click); form.append(emailField.root, passwordField.root, submitBtn); // 회원가입 링크 const toRegister = createButton({ label: L("A06_Login_ToRegister"), variant: "ghost", onClick: () => navigateTo(ROUTES.A07_REGISTER), }); toRegister.classList.add("a06-login__link"); card.append(title, subtitle, form, toRegister); page.append(card); root.append(page); }