import { ROUTES } from "@config/config_frontend"; import { createButton, createTag, hideLoadingOverlay, showLoadingOverlay, showToast, } from "@ui/ui_template_elements"; import { section } from "@ui/ui_template_general_blocks"; import { createGeneralLayout } from "@ui/ui_template_general_layout"; import { navigateTo } from "../A00_Common/router"; import { fetchAllCompanies, fetchAllJoinRequests, fetchAllProjects, fetchAllUsers, fetchAuditLogs, fetchCompanyJoinRequests, fetchCompanyMembers, fetchCompanyProjects, fetchDashboardMe, fetchSystemResources, fetchUserCompany, fetchUserProjects, type AuditLog, type CompanyInfo, type DashboardUser, type JoinRequest, type Member, type ProjectItem, type ResourceData, } from "./B01_Dashboard_Api_Fetch"; import { auditLogTable, userTable } from "./B01_Dashboard_UI_Admin"; import { L, roleLabel } from "./B01_Dashboard_UI_Common"; import { buildCompanyPanel, companyTable, joinRequestTable, memberTable, } from "./B01_Dashboard_UI_Company"; import { openAddMemberModal, openCreateCompanyModal } from "./B01_Dashboard_UI_Modals"; import { buildProfileForm, buildSecurityForm } from "./B01_Dashboard_UI_Profile"; import { projectTable } from "./B01_Dashboard_UI_Projects"; import { buildResourcePanel } from "./B01_Dashboard_UI_Resources"; import { buildTempUploadSection } from "./B01_Dashboard_UI_TempUpload"; import "./B01_Dashboard_UI_Style.css"; export interface DashboardState { user: DashboardUser; userProjects: ProjectItem[]; companyProjects: ProjectItem[]; allProjects: ProjectItem[]; company: CompanyInfo | null; members: Member[]; joinRequests: JoinRequest[]; allCompanies: CompanyInfo[]; allUsers: DashboardUser[]; allJoinRequests: JoinRequest[]; auditLogs: AuditLog[]; resources: ResourceData | null; } export async function renderB01Dashboard(root: HTMLElement): Promise { showLoadingOverlay(); try { const user = await fetchDashboardMe(); const state: DashboardState = { user, userProjects: [], companyProjects: [], allProjects: [], company: null, members: [], joinRequests: [], allCompanies: [], allUsers: [], allJoinRequests: [], auditLogs: [], resources: null, }; await loadRoleData(state); root.innerHTML = ""; root.append(buildPage(state)); } catch (error) { showToast(error instanceof Error ? error.message : L("B01_Dashboard_LoadFailed"), "error"); } finally { hideLoadingOverlay(); } } async function loadRoleData(state: DashboardState): Promise { if (state.user.role === "SYSTEM_ADMIN") { const results = await Promise.allSettled([ fetchAllCompanies(), fetchAllUsers(), fetchAllJoinRequests(), fetchAuditLogs(), fetchSystemResources(7), fetchAllProjects(), ]); state.allCompanies = results[0].status === "fulfilled" ? results[0].value : []; state.allUsers = results[1].status === "fulfilled" ? results[1].value : []; state.allJoinRequests = results[2].status === "fulfilled" ? results[2].value : []; state.auditLogs = results[3].status === "fulfilled" ? results[3].value : []; state.resources = results[4].status === "fulfilled" ? results[4].value : null; state.allProjects = results[5].status === "fulfilled" ? results[5].value : []; results.forEach((res, idx) => { if (res.status === "rejected") { console.error(`System Admin API failed at index ${idx}:`, res.reason); } }); return; } const [projects, company] = await Promise.all([ fetchUserProjects().catch(() => []), fetchUserCompany().catch(() => null), ]); state.userProjects = projects; state.company = company; if (state.user.role === "ADMIN") { const [members, requests, companyProjects] = await Promise.all([ fetchCompanyMembers().catch(() => []), fetchCompanyJoinRequests().catch(() => []), fetchCompanyProjects().catch(() => []), ]); state.members = members; state.joinRequests = requests; state.companyProjects = companyProjects; } } function buildSystemSettingsPanel(): HTMLElement { const wrap = document.createElement("div"); wrap.className = "b01-dashboard__actions"; wrap.append( createButton({ label: L("B01_Dashboard_MasterData"), variant: "ghost", onClick: () => navigateTo(ROUTES.Z01_MASTER_DATA), }), ); return wrap; } function buildPage(state: DashboardState): HTMLElement { // 제목·여백은 공용 템플릿을 따른다 (2026-09-06 사용자 지시) — B02 등 다른 화면과 같은 모양. const page = document.createElement("div"); const grid = document.createElement("div"); grid.className = "b01-dashboard__grid"; if (state.user.role === "SYSTEM_ADMIN") { // 리소스 현황 오른쪽에 시스템 설정 — 앞으로 다른 설정 단추도 이 칸에 듦 (2026-09-15 브레인 Z01). const topRow = document.createElement("div"); topRow.className = "b01-dashboard__top-row"; topRow.append( section(L("B01_Dashboard_Resources"), buildResourcePanel(state.resources)), section(L("B01_Dashboard_SystemSettings"), buildSystemSettingsPanel()), ); grid.append( topRow, section(L("B01_Dashboard_Projects"), projectTable(state.allProjects, state.user), true, [ createButton({ label: "+", onClick: () => navigateTo(ROUTES.B02_PROJ_REGISTER) }), ]), buildTempUploadSection(), section(L("B01_Dashboard_Users"), userTable(state.allUsers, state.user), true, [ createButton({ label: "+", onClick: () => openAddMemberModal() }), ]), section(L("B01_Dashboard_JoinRequests"), joinRequestTable(state.allJoinRequests, true), true), section(L("B01_Dashboard_Companies"), companyTable(state.allCompanies, state.user), true, [ createButton({ label: "+", onClick: () => openCreateCompanyModal() }), ]), ); } else if (state.user.role === "ADMIN") { grid.append( section(L("B01_Dashboard_Projects"), projectTable(state.companyProjects, state.user), true, [ createButton({ label: "+", onClick: () => navigateTo(ROUTES.B02_PROJ_REGISTER) }), ]), buildTempUploadSection(), section(L("B01_Dashboard_Members"), memberTable(state.members, state.user), true, [ createButton({ label: "+", onClick: () => openAddMemberModal() }), ]), section(L("B01_Dashboard_JoinRequests"), joinRequestTable(state.joinRequests, false), true), section(L("B01_Dashboard_Company"), buildCompanyPanel(state), true), ); } else { grid.append( section(L("B01_Dashboard_Projects"), projectTable(state.userProjects, state.user), true, [ createButton({ label: "+", onClick: () => navigateTo(ROUTES.B02_PROJ_REGISTER) }), ]), // 임시 보관함 — 프로젝트를 만들기 전에 자료를 올려 두는 곳이라 프로젝트 목록 // 바로 아래에 둔다(2026-08-08 사용자 지시). buildTempUploadSection(), section(L("B01_Dashboard_Company"), buildCompanyPanel(state), true), ); } grid.append( section(L("B01_Dashboard_Profile"), buildProfileForm(state.user)), section(L("B01_Account_Section_Security"), buildSecurityForm()), ); // 시스템 로그는 맨 아래 (2026-09-06 사용자 지시). if (state.user.role === "SYSTEM_ADMIN") { grid.append(section(L("B01_Dashboard_AuditLogs"), auditLogTable(state.auditLogs), true)); } page.append(grid); const layout = createGeneralLayout({ pageClass: "b01-dashboard", title: L("B01_Dashboard_Title"), subtitle: L("B01_Dashboard_Subtitle"), content: page, }); // 역할 배지는 제목 줄 오른쪽에 둔다(자리는 CSS 격자가 잡는다). const tag = createTag( roleLabel(state.user.role), state.user.role === "SYSTEM_ADMIN" ? "accent" : "neutral", ); tag.classList.add("b01-dashboard__role"); layout.root.querySelector(".ui-general-layout__header")?.append(tag); return layout.root; }