import { useState, useEffect } from 'react'; import type { UserDetail, CreateUserRequest, UpdateUserRequest } from '../../types/user'; import type { Tenant } from '../../types/tenant'; import { getUsers, createUser, updateUser, deactivateUser } from '../../services/userService'; import { getTenants } from '../../services/tenantService'; import Button from '../../components/ui/Button'; import Badge from '../../components/ui/Badge'; import type { BadgeVariant } from '../../components/ui/Badge'; const ROLE_BADGE_VARIANT: Record = { ADMIN: 'danger', MANAGER: 'warning', USER: 'blue', VIEWER: 'default', }; const UsersPage = () => { const [users, setUsers] = useState([]); const [tenants, setTenants] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [editingUser, setEditingUser] = useState(null); const [loginId, setLoginId] = useState(''); const [password, setPassword] = useState(''); const [userName, setUserName] = useState(''); const [email, setEmail] = useState(''); const [tenantId, setTenantId] = useState(''); const [role, setRole] = useState('USER'); const [isActive, setIsActive] = useState(true); const fetchData = async () => { try { setLoading(true); const [usersRes, tenantsRes] = await Promise.all([getUsers(), getTenants()]); if (usersRes.success && usersRes.data) { setUsers(usersRes.data); } if (tenantsRes.success && tenantsRes.data) { setTenants(tenantsRes.data); } } catch { setError('데이터를 불러오는데 실패했습니다.'); } finally { setLoading(false); } }; useEffect(() => { fetchData(); }, []); const handleOpenCreate = () => { setEditingUser(null); setLoginId(''); setPassword(''); setUserName(''); setEmail(''); setTenantId(''); setRole('USER'); setIsActive(true); setIsModalOpen(true); }; const handleOpenEdit = (user: UserDetail) => { setEditingUser(user); setLoginId(user.loginId); setPassword(''); setUserName(user.userName); setEmail(user.email || ''); setTenantId(user.tenantId ? String(user.tenantId) : ''); setRole(user.role); setIsActive(user.isActive); setIsModalOpen(true); }; const handleCloseModal = () => { setIsModalOpen(false); setEditingUser(null); setError(null); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(null); try { if (editingUser) { const req: UpdateUserRequest = { tenantId: tenantId ? Number(tenantId) : undefined, userName, email: email || undefined, role, password: password || undefined, isActive, }; const res = await updateUser(editingUser.userId, req); if (!res.success) { setError(res.message || '사용자 수정에 실패했습니다.'); return; } } else { const req: CreateUserRequest = { tenantId: tenantId ? Number(tenantId) : undefined, loginId, password, userName, email: email || undefined, role, }; const res = await createUser(req); if (!res.success) { setError(res.message || '사용자 생성에 실패했습니다.'); return; } } handleCloseModal(); await fetchData(); } catch { setError(editingUser ? '사용자 수정에 실패했습니다.' : '사용자 생성에 실패했습니다.'); } }; const handleDeactivate = async (user: UserDetail) => { if (!confirm(`'${user.userName}' 사용자를 비활성화하시겠습니까?`)) return; try { const res = await deactivateUser(user.userId); if (!res.success) { setError(res.message || '사용자 비활성화에 실패했습니다.'); return; } await fetchData(); } catch { setError('사용자 비활성화에 실패했습니다.'); } }; if (loading) { return
로딩 중...
; } return (

Users

사용자 계정 관리

{error && !isModalOpen && (
{error}
)}
{users.map((user) => ( ))} {users.length === 0 && ( )}
Login ID Name Email Tenant Role Active Last Login Actions
{user.loginId} {user.userName} {user.email || '-'} {user.tenantName || '-'} {user.role} {user.isActive ? 'Active' : 'Inactive'} {user.lastLoginAt ? new Date(user.lastLoginAt).toLocaleString() : '-'}
{user.isActive && ( )}
등록된 사용자가 없습니다.
{isModalOpen && (

{editingUser ? '사용자 수정' : '사용자 생성'}

{error && (
{error}
)}
setLoginId(e.target.value)} disabled={!!editingUser} required className="w-full border border-[var(--color-border-strong)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] rounded-lg px-3 py-2 focus:ring-2 focus:ring-[var(--color-primary)] focus:outline-none disabled:opacity-50" />
setPassword(e.target.value)} required={!editingUser} placeholder={editingUser ? '변경 시 입력' : ''} className="w-full border border-[var(--color-border-strong)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] rounded-lg px-3 py-2 focus:ring-2 focus:ring-[var(--color-primary)] focus:outline-none" />
setUserName(e.target.value)} required className="w-full border border-[var(--color-border-strong)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] rounded-lg px-3 py-2 focus:ring-2 focus:ring-[var(--color-primary)] focus:outline-none" />
setEmail(e.target.value)} className="w-full border border-[var(--color-border-strong)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] rounded-lg px-3 py-2 focus:ring-2 focus:ring-[var(--color-primary)] focus:outline-none" />
{editingUser && (
setIsActive(e.target.checked)} className="rounded" />
)}
)}
); }; export default UsersPage;