import { useState, useEffect } from 'react'; import { Card } from '../../shared/ui/Card'; import { Button } from '../../shared/ui/Button'; import { Input } from '../../shared/ui/Input'; import { apiClient } from '../../shared/api/client'; import { Plus, Edit2, Trash2, X, Check, Shield, User as UserIcon, ShieldCheck, RefreshCcw } from 'lucide-react'; import type { User } from '../../shared/auth/AuthContext'; import { useAuth } from '../../shared/auth/AuthContext'; import './UserManagementPage.css'; interface UserFormData { id: string; password?: string; name: string; department: string; position: string; phone: string; role: 'supervisor' | 'admin' | 'user'; } export function UserManagementPage() { const { user: currentUser } = useAuth(); const [users, setUsers] = useState([]); const [loading, setLoading] = useState(false); // Modal State const [isModalOpen, setIsModalOpen] = useState(false); const [isEditing, setIsEditing] = useState(false); const [formData, setFormData] = useState({ id: '', password: '', name: '', department: '', position: '', phone: '', role: 'user' }); useEffect(() => { fetchUsers(); }, []); const fetchUsers = async () => { setLoading(true); try { const res = await apiClient.get('/users'); setUsers(res.data); } catch (error) { console.error('Failed to fetch users', error); alert('사용자 목록을 불러오지 못했습니다.'); } finally { setLoading(false); } }; const handleOpenAdd = () => { setFormData({ id: '', password: '', name: '', department: '', position: '', phone: '', role: 'user' }); setIsEditing(false); setIsModalOpen(true); }; const handleOpenEdit = (user: User) => { setFormData({ id: user.id, password: '', name: user.name, department: user.department || '', position: user.position || '', phone: user.phone || '', role: user.role }); setIsEditing(true); setIsModalOpen(true); }; const handleDelete = async (id: string) => { if (!confirm('정말 이 사용자를 삭제하시겠습니까?')) return; try { await apiClient.delete(`/users/${id}`); fetchUsers(); } catch (error) { console.error('Failed to delete user', error); alert('삭제 실패'); } }; const formatPhoneNumber = (value: string) => { const cleaned = value.replace(/\D/g, ''); if (cleaned.length <= 3) return cleaned; else if (cleaned.length <= 7) return `${cleaned.slice(0, 3)}-${cleaned.slice(3)}`; else return `${cleaned.slice(0, 3)}-${cleaned.slice(3, 7)}-${cleaned.slice(7, 11)}`; }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { if (isEditing) { const payload: any = { ...formData }; if (!payload.password) delete payload.password; await apiClient.put(`/users/${formData.id}`, payload); alert('수정되었습니다.'); } else { if (!formData.password) return alert('비밀번호를 입력하세요.'); await apiClient.post('/users', formData); alert('등록되었습니다.'); } setIsModalOpen(false); fetchUsers(); } catch (error: any) { alert(`오류: ${error.response?.data?.error || error.message}`); } }; const getRoleBadge = (role: string) => { switch (role) { case 'supervisor': return ( 최고관리자 ); case 'admin': return ( 관리자 ); default: return ( 사용자 ); } }; return (

시스템 관리 - 사용자 관리

시스템 접속 권한 및 사용자 정보를 관리합니다.

{loading ? ( ) : users.map((user) => ( ))} {!loading && users.length === 0 && ( )}
아이디 / 권한 이름 소속 / 직위 연락처 마지막 접속 관리
사용자 데이터를 불러오는 중...
{user.id}
{getRoleBadge(user.role)}
{user.name}
{user.department || '-'}
{user.position}
{user.phone || '-'} {user.last_login ? new Date(user.last_login).toLocaleString() : '미접속'}
등록된 사용자가 없습니다.
{/* Modal */} {isModalOpen && (

{isEditing ? '사용자 정보 수정' : '새 사용자 등록'}

setFormData({ ...formData, id: e.target.value })} disabled={isEditing} placeholder="로그인 아이디 입력" required />
setFormData({ ...formData, password: e.target.value })} placeholder={isEditing ? "(변경시에만 입력)" : "초기 비밀번호 입력"} required={!isEditing} />
setFormData({ ...formData, name: e.target.value })} required />
{currentUser?.role !== 'supervisor' && (

* 최고관리자 권한 부여는 최고관리자만 가능합니다.

)}
setFormData({ ...formData, department: e.target.value })} />
setFormData({ ...formData, position: e.target.value })} />
setFormData({ ...formData, phone: formatPhoneNumber(e.target.value) })} placeholder="010-0000-0000" maxLength={13} />
)}
); }