Files
pipeline/frontend/app/(main)/admin/userMng/userMngList/page.tsx
T
kjs 1d49fc7ac7 Implement multi-language support in user management and system management pages
- Integrated multi-language functionality across various user management components, including user list, roles list, and user authorization pages, enhancing accessibility for diverse users.
- Updated UI elements to utilize translation keys, ensuring that all text is dynamically translated based on user preferences.
- Improved error handling messages to be localized, providing a better user experience in case of issues.

These changes significantly enhance the usability and internationalization of the user management features, making the application more inclusive.
2026-04-01 15:57:12 +09:00

279 lines
8.1 KiB
TypeScript

"use client";
import { useState } from "react";
import { useUserManagement } from "@/hooks/useUserManagement";
import { UserToolbar } from "@/components/admin/UserToolbar";
import { UserTable } from "@/components/admin/UserTable";
import { Pagination } from "@/components/common/Pagination";
import { UserPasswordResetModal } from "@/components/admin/UserPasswordResetModal";
import { UserFormModal } from "@/components/admin/UserFormModal";
import { ScrollToTop } from "@/components/common/ScrollToTop";
import { usePageMultiLang } from "@/hooks/usePageMultiLang";
// 다국어 키 목록
const USER_MNG_KEYS = [
"user.mng.title",
"user.mng.description",
"error.occurred",
"table.sabun",
"table.company",
"table.dept",
"table.position",
"table.userId",
"table.userName",
"table.phone",
"table.email",
"table.regDate",
"table.status",
"table.dept.short",
"table.contact",
"table.empty",
"table.actions",
"action.edit.user",
"action.reset.password",
"action.view.history",
"toolbar.search.placeholder",
"toolbar.searching",
"toolbar.advanced.search",
"toolbar.advanced.search.title",
"toolbar.advanced.search.desc",
"toolbar.advanced.mode.warning",
"toolbar.advanced.reset",
"toolbar.total.count",
"toolbar.total.unit",
"toolbar.create.user",
"toolbar.search.company",
"toolbar.search.dept",
"toolbar.search.position",
"toolbar.search.userId",
"toolbar.search.userName",
"toolbar.search.tel",
"toolbar.search.email",
] as const;
// 한국어 기본값
const USER_MNG_DEFAULTS: Record<string, string> = {
"user.mng.title": "사용자 관리",
"user.mng.description": "시스템 사용자 계정 및 권한을 관리합니다",
"error.occurred": "오류가 발생했습니다",
"table.sabun": "사번",
"table.company": "회사",
"table.dept": "부서명",
"table.position": "직책",
"table.userId": "사용자 ID",
"table.userName": "사용자명",
"table.phone": "전화번호",
"table.email": "이메일",
"table.regDate": "등록일",
"table.status": "상태",
"table.dept.short": "부서",
"table.contact": "연락처",
"table.empty": "등록된 사용자가 없습니다.",
"table.actions": "작업",
"action.edit.user": "사용자 정보 수정",
"action.reset.password": "비밀번호 초기화",
"action.view.history": "변경이력 조회",
"toolbar.search.placeholder": "통합 검색...",
"toolbar.searching": "검색 중...",
"toolbar.advanced.search": "고급 검색",
"toolbar.advanced.search.title": "고급 검색 옵션",
"toolbar.advanced.search.desc": "각 필드별로 개별 검색 조건을 설정할 수 있습니다",
"toolbar.advanced.mode.warning":
"고급 검색 모드가 활성화되어 있습니다. 통합 검색을 사용하려면 고급 검색 조건을 초기화하세요.",
"toolbar.advanced.reset": "고급 검색 조건 초기화",
"toolbar.total.count": "총",
"toolbar.total.unit": "명",
"toolbar.create.user": "사용자 등록",
"toolbar.search.company": "회사명 검색",
"toolbar.search.dept": "부서명 검색",
"toolbar.search.position": "직책 검색",
"toolbar.search.userId": "사용자 ID 검색",
"toolbar.search.userName": "사용자명 검색",
"toolbar.search.tel": "전화번호/휴대폰 검색",
"toolbar.search.email": "이메일 검색",
};
/**
* 사용자관리 페이지
* URL: /admin/userMng
*
* shadcn/ui 스타일 가이드 적용
* - 원본 Spring + JSP 코드 패턴 기반 REST API 연동
* - 실제 데이터베이스와 연동되어 작동
*/
export default function UserMngPage() {
const { t } = usePageMultiLang({
keys: USER_MNG_KEYS,
defaults: USER_MNG_DEFAULTS,
menuCode: "user.management",
});
const {
// 데이터
users,
searchFilter,
isLoading,
isSearching,
error,
paginationInfo,
// 검색 기능
updateSearchFilter,
// 페이지네이션
handlePageChange,
handlePageSizeChange,
// 액션 핸들러
handleStatusToggle,
// 유틸리티
clearError,
refreshData,
} = useUserManagement();
// 비밀번호 초기화 모달 상태
const [passwordResetModal, setPasswordResetModal] = useState({
isOpen: false,
userId: null as string | null,
userName: null as string | null,
});
// 사용자 등록/수정 모달 상태
const [userFormModal, setUserFormModal] = useState({
isOpen: false,
editingUser: null as any | null,
});
// 사용자 등록 핸들러
const handleCreateUser = () => {
setUserFormModal({
isOpen: true,
editingUser: null,
});
};
// 사용자 수정 핸들러
const handleEditUser = (user: any) => {
setUserFormModal({
isOpen: true,
editingUser: user,
});
};
// 사용자 등록/수정 모달 닫기
const handleUserFormClose = () => {
setUserFormModal({
isOpen: false,
editingUser: null,
});
};
// 사용자 등록/수정 성공 핸들러
const handleUserFormSuccess = () => {
refreshData();
handleUserFormClose();
};
// 비밀번호 초기화 핸들러
const handlePasswordReset = (userId: string, userName: string) => {
setPasswordResetModal({
isOpen: true,
userId,
userName,
});
};
// 비밀번호 초기화 모달 닫기
const handlePasswordResetClose = () => {
setPasswordResetModal({
isOpen: false,
userId: null,
userName: null,
});
};
// 비밀번호 초기화 성공 핸들러
const handlePasswordResetSuccess = () => {
handlePasswordResetClose();
};
return (
<div className="flex h-full flex-col bg-background">
{/* 상단 고정: 헤더 + 툴바 */}
<div className="shrink-0 space-y-6 p-6 pb-0">
<div className="space-y-2 border-b pb-4">
<h1 className="text-3xl font-bold tracking-tight">{t("user.mng.title")}</h1>
<p className="text-sm text-muted-foreground">{t("user.mng.description")}</p>
</div>
<UserToolbar
searchFilter={searchFilter}
totalCount={paginationInfo.totalItems}
isSearching={isSearching}
onSearchChange={updateSearchFilter}
onCreateClick={handleCreateUser}
t={t}
/>
{error && (
<div className="border-destructive/50 bg-destructive/10 rounded-lg border p-4">
<div className="flex items-center justify-between">
<p className="text-destructive text-sm font-semibold">{t("error.occurred")}</p>
<button
onClick={clearError}
className="text-destructive hover:text-destructive/80 transition-colors"
aria-label="에러 메시지 닫기"
>
</button>
</div>
<p className="text-destructive/80 mt-1.5 text-sm">{error}</p>
</div>
)}
</div>
{/* 중간: 테이블 (스크롤 영역) */}
<div className="min-h-0 flex-1 overflow-auto px-6 py-6">
<UserTable
users={users}
isLoading={isLoading}
paginationInfo={paginationInfo}
onStatusToggle={handleStatusToggle}
onPasswordReset={handlePasswordReset}
onEdit={handleEditUser}
t={t}
/>
</div>
{/* 하단 고정: 페이지네이션 */}
{!isLoading && users.length > 0 && (
<div className="shrink-0 border-t px-6 py-3">
<Pagination
paginationInfo={paginationInfo}
onPageChange={handlePageChange}
onPageSizeChange={handlePageSizeChange}
showPageSizeSelector={true}
pageSizeOptions={[10, 20, 50, 100]}
/>
</div>
)}
{/* 모달 */}
<UserFormModal
isOpen={userFormModal.isOpen}
onClose={handleUserFormClose}
onSuccess={handleUserFormSuccess}
editingUser={userFormModal.editingUser}
/>
<UserPasswordResetModal
isOpen={passwordResetModal.isOpen}
onClose={handlePasswordResetClose}
userId={passwordResetModal.userId}
userName={passwordResetModal.userName}
onSuccess={handlePasswordResetSuccess}
/>
<ScrollToTop />
</div>
);
}