2ff01456dc
- Updated the user list retrieval logic to ensure proper filtering based on company codes, enhancing security for user data access. - Implemented checks to restrict access to company management APIs, allowing only SUPER_ADMIN users to perform actions related to company data. - Adjusted the user interface to reflect access restrictions for non-SUPER_ADMIN users, providing clear feedback when access is denied. These changes strengthen the integrity of user management and ensure that sensitive company information is only accessible to authorized personnel.
188 lines
5.2 KiB
TypeScript
188 lines
5.2 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";
|
|
|
|
/**
|
|
* 사용자관리 페이지
|
|
* URL: /admin/userMng
|
|
*
|
|
* shadcn/ui 스타일 가이드 적용
|
|
* - 원본 Spring + JSP 코드 패턴 기반 REST API 연동
|
|
* - 실제 데이터베이스와 연동되어 작동
|
|
*/
|
|
export default function UserMngPage() {
|
|
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">사용자 관리</h1>
|
|
<p className="text-sm text-muted-foreground">시스템 사용자 계정 및 권한을 관리합니다</p>
|
|
</div>
|
|
|
|
<UserToolbar
|
|
searchFilter={searchFilter}
|
|
totalCount={paginationInfo.totalItems}
|
|
isSearching={isSearching}
|
|
onSearchChange={updateSearchFilter}
|
|
onCreateClick={handleCreateUser}
|
|
/>
|
|
|
|
{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">오류가 발생했습니다</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}
|
|
/>
|
|
</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>
|
|
);
|
|
}
|