Files
Aislo/A08_Support/A08_Support_UI_Page.ts
T

177 lines
5.8 KiB
TypeScript

/* =============================================================================
* A08_Support_UI_Page.ts
* 로그인 전 08: 기술지원 요청 (이름 + 이메일 + 제목 + 문의내용 폼)
*
* 제약 준수:
* - 모든 문구는 ui_template_locale.ts 참조 (하드코딩 금지).
* - 색상/간격은 A08_Support_UI_Style.css + theme.css 변수만 사용.
* - 공통 컴포넌트(createButton/createInputField) 우선 사용.
* - 이벤트 핸들러는 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 "./A08_Support_UI_Style.css";
/** locale 헬퍼 */
function L(key: keyof typeof ui_locales): string {
return ui_locales[key][currentLanguageIndex];
}
/** 문의내용 textarea 핸들 (createInputField와 유사한 형태로 에러 슬롯 포함) */
interface TextAreaHandle {
root: HTMLDivElement;
textarea: HTMLTextAreaElement;
setError: (msg?: string) => void;
}
/** 여러 줄 입력용 textarea 필드 생성 (공통 .ui-field/.ui-input 스타일 상속). */
function createTextAreaField(label: string, placeholder: string): TextAreaHandle {
const root = document.createElement("div");
root.className = "ui-field";
const labelEl = document.createElement("label");
labelEl.className = "ui-field__label";
labelEl.textContent = label;
const textarea = document.createElement("textarea");
textarea.className = "ui-input a08-support__textarea";
textarea.placeholder = placeholder;
textarea.rows = 6;
const errorSlot = document.createElement("span");
errorSlot.className = "ui-field__error";
errorSlot.setAttribute("role", "alert");
root.append(labelEl, textarea, errorSlot);
const setError = (msg?: string): void => {
if (msg) {
textarea.classList.add("ui-input--error");
errorSlot.textContent = msg;
errorSlot.classList.add("is-visible");
} else {
textarea.classList.remove("ui-input--error");
errorSlot.textContent = "";
errorSlot.classList.remove("is-visible");
}
};
return { root, textarea, setError };
}
/* -----------------------------------------------------------------------------
* 페이지 진입점
* -------------------------------------------------------------------------- */
export function renderA08Support(root: HTMLElement): void {
const page = document.createElement("div");
page.className = "a08-support";
const card = document.createElement("div");
card.className = "a08-support__card";
const title = document.createElement("h1");
title.className = "a08-support__title";
title.textContent = L("A08_Support_Title");
const subtitle = document.createElement("p");
subtitle.className = "a08-support__subtitle";
subtitle.textContent = L("A08_Support_Subtitle");
// 성공 메시지 슬롯 (제출 성공 시 표시)
const successMsg = document.createElement("p");
successMsg.className = "a08-support__success";
successMsg.textContent = L("A08_Support_Success");
successMsg.hidden = true;
// 입력 필드
const nameField = createInputField({
label: L("A08_Support_Field_Name"),
placeholder: L("A08_Support_Field_Name_Placeholder"),
type: "text",
required: true,
});
const emailField = createInputField({
label: L("A08_Support_Field_Email"),
placeholder: L("A08_Support_Field_Email_Placeholder"),
type: "email",
required: true,
});
const subjectField = createInputField({
label: L("A08_Support_Field_Subject"),
placeholder: L("A08_Support_Field_Subject_Placeholder"),
type: "text",
required: true,
});
const messageField = createTextAreaField(
L("A08_Support_Field_Message"),
L("A08_Support_Field_Message_Placeholder"),
);
const form = document.createElement("form");
form.className = "a08-support__form";
form.noValidate = true;
const submitBtn = createButton({
label: L("A08_Support_Submit"),
variant: "filled",
type: "submit",
});
submitBtn.classList.add("a08-support__submit");
/* 이벤트 핸들러: 제출 시 1차 유효성 검사 */
function onA08_Support_Submit_Click(event: Event): void {
event.preventDefault();
successMsg.hidden = true;
nameField.setError();
emailField.setError();
subjectField.setError();
messageField.setError();
const name = nameField.input.value;
const email = emailField.input.value;
const subject = subjectField.input.value;
const message = messageField.textarea.value;
// 필수값 검사
let hasError = false;
if (isBlank(name)) {
nameField.setError(L("A08_Support_Error_Required"));
hasError = true;
}
if (isBlank(email)) {
emailField.setError(L("A08_Support_Error_Required"));
hasError = true;
}
if (isBlank(subject)) {
subjectField.setError(L("A08_Support_Error_Required"));
hasError = true;
}
if (isBlank(message)) {
messageField.setError(L("A08_Support_Error_Required"));
hasError = true;
}
if (hasError) return;
// 형식 검사
if (!isValidEmail(email)) {
emailField.setError(L("A08_Support_Error_Email"));
return;
}
// TODO: POST /api/a08/support 연동. 성공 시 폼 초기화 후 성공 메시지 표시.
form.reset();
messageField.textarea.value = "";
successMsg.hidden = false;
}
form.addEventListener("submit", onA08_Support_Submit_Click);
form.append(nameField.root, emailField.root, subjectField.root, messageField.root, submitBtn);
card.append(title, subtitle, successMsg, form);
page.append(card);
root.append(page);
}