191 lines
5.3 KiB
TypeScript
191 lines
5.3 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 min-h-screen flex-col bg-background">
|
|
<div className="space-y-6 p-6">
|
|
{/* 페이지 헤더 */}
|
|
<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>
|
|
)}
|
|
|
|
{/* 사용자 목록 테이블 */}
|
|
<UserTable
|
|
users={users}
|
|
isLoading={isLoading}
|
|
paginationInfo={paginationInfo}
|
|
onStatusToggle={handleStatusToggle}
|
|
onPasswordReset={handlePasswordReset}
|
|
onEdit={handleEditUser}
|
|
/>
|
|
|
|
{/* 페이지네이션 */}
|
|
{!isLoading && users.length > 0 && (
|
|
<Pagination
|
|
paginationInfo={paginationInfo}
|
|
onPageChange={handlePageChange}
|
|
onPageSizeChange={handlePageSizeChange}
|
|
showPageSizeSelector={true}
|
|
pageSizeOptions={[10, 20, 50, 100]}
|
|
className="mt-6"
|
|
/>
|
|
)}
|
|
|
|
{/* 사용자 등록/수정 모달 */}
|
|
<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}
|
|
/>
|
|
</div>
|
|
|
|
{/* Scroll to Top 버튼 (모바일/태블릿 전용) */}
|
|
<ScrollToTop />
|
|
</div>
|
|
);
|
|
}
|