import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale"; import { createButton, createInputField, createSelectField, showToast, showLoadingOverlay, hideLoadingOverlay, } from "@ui/ui_template_elements"; import { updateProject, deleteProject, changeUserRole, updateDashboardUser, removeCompanyMember, fetchProjectAutomations, createProjectAutomation, updateProjectAutomation, deleteProjectAutomation, executeProjectAutomation, createCompany, joinCompany, searchCompanies, addCompanyMember, type DashboardUser, type ProjectItem, type Member, type AutomationItem, type CompanyInfo, } from "./B01_Dashboard_Api_Fetch"; function L(key: keyof typeof ui_locales): string { return ui_locales[key][currentLanguageIndex]; } function openModal(title: string, body: HTMLElement[], onConfirm: () => Promise): void { const modal = document.createElement("div"); modal.className = "b01-dashboard__modal"; const panel = document.createElement("div"); panel.className = "b01-dashboard__modal-panel"; const heading = document.createElement("h3"); heading.className = "b01-dashboard__modal-title"; heading.textContent = title; const actions = document.createElement("div"); actions.className = "b01-dashboard__actions"; actions.append( createButton({ label: L("Common_Btn_Cancel"), variant: "ghost", onClick: () => modal.remove(), }), createButton({ label: L("Common_Btn_Confirm"), onClick: async () => { showLoadingOverlay(); try { await onConfirm(); modal.remove(); window.dispatchEvent(new HashChangeEvent("hashchange")); } catch (error) { showToast( error instanceof Error ? error.message : L("B01_Dashboard_RequestFailed"), "error", ); } finally { hideLoadingOverlay(); } }, }), ); panel.append(heading, ...body, actions); modal.append(panel); document.body.append(modal); } export function openEditProjectModal(user: DashboardUser, project: ProjectItem): void { const isUserOnly = user.role === "USER"; const name = createInputField({ label: L("B01_Dashboard_Table_Project"), value: project.name, required: true, }); const region = createInputField({ label: L("B01_Dashboard_Table_Region"), value: project.region ?? "", }); const roadType = createInputField({ label: "임도 종류", value: project.road_type ?? "" }); const year = createInputField({ label: "사업 연도", type: "number", value: String(project.project_year ?? ""), }); const length = createInputField({ label: "예상 연장 (m)", type: "number", value: String(project.estimated_length_m ?? ""), }); const memo = createInputField({ label: "비고", value: project.memo ?? "" }); if (isUserOnly) { name.input.disabled = true; region.input.disabled = true; roadType.input.disabled = true; year.input.disabled = true; length.input.disabled = true; memo.input.disabled = true; } openModal( L("B01_Dashboard_EditProject"), [name.root, region.root, roadType.root, year.root, length.root, memo.root], async () => { await updateProject(project.id, { name: name.input.value.trim(), region: region.input.value.trim() || null, road_type: roadType.input.value.trim() || null, project_year: year.input.value ? Number(year.input.value) : null, estimated_length_m: length.input.value ? Number(length.input.value) : null, memo: memo.input.value.trim() || null, status: project.status, }); showToast(L("B01_Dashboard_Saved"), "success"); }, ); } export function openDeleteProjectModal(project: ProjectItem): void { const warning = document.createElement("p"); warning.className = "b01-dashboard__modal-text"; warning.textContent = L("B01_Dashboard_Confirm_DeleteProject"); openModal(L("B01_Dashboard_DeleteProject"), [warning], async () => { await deleteProject(project.id); showToast(L("B01_Dashboard_Saved"), "success"); }); } export function openEditUserModal(user: DashboardUser, target: Member | DashboardUser): void { const name = createInputField({ label: L("B01_Dashboard_Table_Name"), value: target.name, required: true, }); const position = createInputField({ label: L("B01_Dashboard_Table_Position"), value: target.position ?? "", }); const department = createInputField({ label: L("B01_Dashboard_Table_Department"), value: target.department ?? "", }); const phoneVal = (target as DashboardUser).phone || ""; const phone = createInputField({ label: L("B01_Account_Field_Phone"), value: phoneVal }); if (user.role === "ADMIN") { // ADMIN은 직책(position) / 부서(department)만 수정 정보 가능 name.input.disabled = true; phone.input.disabled = true; } else if (user.role === "USER" && user.id !== target.id) { name.input.disabled = true; position.input.disabled = true; department.input.disabled = true; phone.input.disabled = true; } openModal( L("B01_Dashboard_EditUser"), [name.root, position.root, department.root, phone.root], async () => { await updateDashboardUser(target.id, { name: name.input.value.trim(), position: position.input.value.trim() || null, department: department.input.value.trim() || null, phone: phone.input.value.trim() || null, status: target.status, }); showToast(L("B01_Dashboard_Saved"), "success"); }, ); } export function openChangeRoleModal(target: Member | DashboardUser): void { const roleField = createSelectField({ label: L("B01_Dashboard_Table_Role"), options: [ { value: "USER", text: "USER" }, { value: "ADMIN", text: "ADMIN" }, ], value: target.role, }); openModal(L("B01_Dashboard_ChangeRole"), [roleField.root], async () => { await changeUserRole(target.id, roleField.select.value); showToast(L("B01_Dashboard_Saved"), "success"); }); } export function openDeleteUserModal(target: Member | DashboardUser): void { const warning = document.createElement("p"); warning.className = "b01-dashboard__modal-text"; warning.textContent = L("B01_Dashboard_Confirm_DeleteUser"); openModal(L("B01_Dashboard_DeleteUser"), [warning], async () => { await removeCompanyMember(target.id); showToast(L("B01_Dashboard_Saved"), "success"); }); } export function openCreateCompanyModal(): void { const name = createInputField({ label: L("B01_Dashboard_Table_Company"), required: true }); const number = createInputField({ label: L("B01_Dashboard_Field_BusinessNumber"), required: true, }); const address = createInputField({ label: L("B01_Dashboard_Field_Address") }); const owner = createInputField({ label: L("B01_Dashboard_Field_Owner") }); openModal( L("B01_Dashboard_Modal_CreateCompany"), [name.root, number.root, address.root, owner.root], async () => { if (!name.input.value.trim() || !number.input.value.trim()) return; await createCompany({ name: name.input.value.trim(), business_registration_number: number.input.value.trim(), business_address: address.input.value.trim() || null, business_owner: owner.input.value.trim() || null, }); showToast(L("B01_Dashboard_Saved"), "success"); }, ); } export function openFindCompanyModal(): void { const query = createInputField({ label: L("B01_Dashboard_Field_Search"), required: true }); const results = document.createElement("div"); results.className = "b01-dashboard__actions"; const search = createButton({ label: L("Common_Btn_Search"), variant: "ghost", onClick: async function onB01_Company_Search_Click() { results.innerHTML = ""; const companies = await searchCompanies(query.input.value.trim()); for (const company of companies) { results.append( createButton({ label: `${company.name} ${L("B01_Dashboard_JoinCompany")}`, variant: "ghost", onClick: async () => { showLoadingOverlay(); try { await joinCompany(company.id); showToast(L("B01_Dashboard_Saved"), "success"); } catch (e) { showToast("요청 실패", "error"); } finally { hideLoadingOverlay(); } }, }), ); } }, }); openModal( L("B01_Dashboard_Modal_FindCompany"), [query.root, search, results], async () => undefined, ); } export function openAddMemberModal(): void { const email = createInputField({ label: L("B01_Dashboard_Field_MemberEmail"), type: "email", required: true, }); openModal(L("B01_Dashboard_Modal_AddMember"), [email.root], async () => { if (!email.input.value.trim()) return; await addCompanyMember(email.input.value.trim()); showToast(L("B01_Dashboard_Saved"), "success"); }); } export async function openAutomationModal(project: ProjectItem): Promise { const modal = document.createElement("div"); modal.className = "b01-dashboard__modal"; const panel = document.createElement("div"); panel.className = "b01-dashboard__modal-panel b01-dashboard__modal-panel--wide"; const heading = document.createElement("h3"); heading.className = "b01-dashboard__modal-title"; heading.textContent = `${project.name} - ${L("B01_Dashboard_AutomationLogic")}`; const listWrap = document.createElement("div"); listWrap.className = "b01-dashboard__automation-list"; const refreshList = async () => { listWrap.innerHTML = L("Common_Status_Loading"); try { const data = await fetchProjectAutomations(project.id); listWrap.innerHTML = ""; if (data.length === 0) { listWrap.textContent = L("Common_Status_Empty"); return; } data.forEach((item) => { const itemEl = document.createElement("div"); itemEl.className = "b01-dashboard__automation-item"; const info = document.createElement("div"); info.innerHTML = `${item.name} (${item.logic_type}) - status: ${item.status}`; const actions = document.createElement("div"); actions.className = "b01-dashboard__actions"; const runBtn = createButton({ label: L("B01_Dashboard_ExecuteAutomation"), variant: "ghost", onClick: async () => { await executeProjectAutomation(item.id); showToast("실행 성공", "success"); refreshList(); }, }); const editBtn = createButton({ label: L("Common_Btn_Edit"), variant: "ghost", onClick: () => { modal.remove(); openEditAutomationModal(project, item); }, }); const delBtn = createButton({ label: L("Common_Btn_Delete"), variant: "danger", onClick: () => { modal.remove(); openDeleteAutomationModal(project, item); }, }); actions.append(runBtn, editBtn, delBtn); itemEl.append(info, actions); listWrap.append(itemEl); }); } catch (e) { listWrap.textContent = "로딩 에러"; } }; const createBtn = createButton({ label: L("B01_Dashboard_CreateAutomation"), onClick: () => { modal.remove(); openCreateAutomationModal(project); }, }); const closeBtn = createButton({ label: L("Common_Btn_Close"), variant: "ghost", onClick: () => modal.remove(), }); panel.append(heading, createBtn, listWrap, closeBtn); modal.append(panel); document.body.append(modal); await refreshList(); } function openCreateAutomationModal(project: ProjectItem): void { const name = createInputField({ label: "자동화 로직명", required: true }); const type = createInputField({ label: "로직 타입", required: true }); openModal(L("B01_Dashboard_CreateAutomation"), [name.root, type.root], async () => { await createProjectAutomation(project.id, { name: name.input.value.trim(), logic_type: type.input.value.trim(), config_json: {}, status: "DRAFT", }); showToast(L("B01_Dashboard_Saved"), "success"); setTimeout(() => openAutomationModal(project), 300); }); } function openEditAutomationModal(project: ProjectItem, item: AutomationItem): void { const name = createInputField({ label: "자동화 로직명", value: item.name, required: true }); const type = createInputField({ label: "로직 타입", value: item.logic_type, required: true }); openModal(L("B01_Dashboard_EditAutomation"), [name.root, type.root], async () => { await updateProjectAutomation(item.id, { name: name.input.value.trim(), logic_type: type.input.value.trim(), config_json: item.config_json, status: item.status, }); showToast(L("B01_Dashboard_Saved"), "success"); setTimeout(() => openAutomationModal(project), 300); }); } function openDeleteAutomationModal(project: ProjectItem, item: AutomationItem): void { const warning = document.createElement("p"); warning.textContent = L("B01_Dashboard_DeleteAutomation") + "?"; openModal(L("B01_Dashboard_DeleteAutomation"), [warning], async () => { await deleteProjectAutomation(item.id); showToast(L("B01_Dashboard_Saved"), "success"); setTimeout(() => openAutomationModal(project), 300); }); }