'use client'; import React, { useState, useEffect } from 'react'; import { Users, Plus, Pencil, Trash2, X, Search, AlertTriangle } from 'lucide-react'; import { useAuthStore } from '@/stores'; import employeeService from '@/services/employeeService'; import type { Employee, RoleCode, EmpStatus } from '@/types'; const roleLabels: Record = { ADMIN: '최고관리자', MANAGER: '본사관리자', EMPLOYEE: '일반사용자', }; const roleBadgeColor: Record = { ADMIN: 'bg-purple-100 text-purple-700', MANAGER: 'bg-indigo-100 text-indigo-700', EMPLOYEE: 'bg-gray-100 text-gray-700', }; const statusLabels: Record = { ACTIVE: '재직', ON_LEAVE: '휴직', RESIGNED: '퇴사', }; const statusBadgeColor: Record = { ACTIVE: 'bg-status-resolved-bg text-status-resolved-text', ON_LEAVE: 'bg-status-pending-bg text-status-pending-text', RESIGNED: 'bg-status-critical-bg text-status-critical-text', }; const educationLabels: Record = { HIGH_SCHOOL: '고졸', COLLEGE: '전문대', BACHELOR: '학사', MASTER: '석사', DOCTOR: '박사', }; const initialColors = ['bg-indigo-500', 'bg-purple-500', 'bg-blue-500', 'bg-green-500', 'bg-orange-500', 'bg-pink-500']; function getInitialColor(name: string, index: number) { return initialColors[index % initialColors.length]; } interface CreateForm { loginId: string; name: string; password: string; email: string; phone: string; roleCode: RoleCode; empStatus: EmpStatus; joinedDate: string; birthDate: string; education: string; major: string; graduationDate: string; residence: string; } interface EditForm { name: string; email: string; phone: string; roleCode: RoleCode; empStatus: EmpStatus; joinedDate: string; leftDate: string; birthDate: string; education: string; major: string; graduationDate: string; residence: string; } const emptyCreateForm: CreateForm = { loginId: '', name: '', password: '', email: '', phone: '', roleCode: 'EMPLOYEE', empStatus: 'ACTIVE', joinedDate: '', birthDate: '', education: '', major: '', graduationDate: '', residence: '', }; export default function AccountsPage() { const user = useAuthStore((s) => s.user); const [employees, setEmployees] = useState([]); const [loading, setLoading] = useState(true); const [searchKeyword, setSearchKeyword] = useState(''); const [showCreateModal, setShowCreateModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [targetEmployee, setTargetEmployee] = useState(null); const [createForm, setCreateForm] = useState({ ...emptyCreateForm }); const [editForm, setEditForm] = useState({ name: '', email: '', phone: '', roleCode: 'EMPLOYEE', empStatus: 'ACTIVE', joinedDate: '', leftDate: '', birthDate: '', education: '', major: '', graduationDate: '', residence: '', }); const [createError, setCreateError] = useState(null); const [editError, setEditError] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const fetchEmployees = async () => { try { setLoading(true); const res = await employeeService.getAll({ size: 200 }); setEmployees(res.data.content); } catch { // silent } finally { setLoading(false); } }; useEffect(() => { fetchEmployees(); }, []); if (user?.roleCode !== 'ADMIN') { return (

접근 거부. 관리자 권한이 필요합니다.

); } const filtered = searchKeyword.trim() ? employees.filter((e) => e.name.toLowerCase().includes(searchKeyword.toLowerCase())) : employees; const openCreate = () => { setCreateForm({ ...emptyCreateForm }); setCreateError(null); setShowCreateModal(true); }; const handleCreate = async (e: React.FormEvent) => { e.preventDefault(); if (!createForm.loginId.trim() || !createForm.name.trim() || !createForm.password.trim()) { setCreateError('로그인 ID, 이름, 비밀번호는 필수입니다.'); return; } setIsSubmitting(true); setCreateError(null); try { await employeeService.create(createForm); setShowCreateModal(false); await fetchEmployees(); } catch (err: any) { setCreateError(err.response?.data?.message || '계정 생성에 실패했습니다.'); } finally { setIsSubmitting(false); } }; const openEdit = (emp: Employee) => { setTargetEmployee(emp); setEditForm({ name: emp.name, email: emp.email, phone: emp.phone || '', roleCode: emp.roleCode, empStatus: emp.empStatus, joinedDate: emp.joinedDate || '', leftDate: emp.leftDate || '', birthDate: emp.birthDate || '', education: emp.education || '', major: emp.major || '', graduationDate: emp.graduationDate || '', residence: emp.residence || '', }); setEditError(null); setShowEditModal(true); }; const handleUpdate = async (e: React.FormEvent) => { e.preventDefault(); if (!editForm.name.trim() || !targetEmployee) return; setIsSubmitting(true); setEditError(null); try { await employeeService.update(targetEmployee.empId, editForm); setShowEditModal(false); await fetchEmployees(); } catch (err: any) { setEditError(err.response?.data?.message || '수정에 실패했습니다.'); } finally { setIsSubmitting(false); } }; const openDelete = (emp: Employee) => { setTargetEmployee(emp); setShowDeleteDialog(true); }; const handleDelete = async () => { if (!targetEmployee) return; setIsSubmitting(true); try { await employeeService.delete(targetEmployee.empId); setShowDeleteDialog(false); await fetchEmployees(); } catch (err: any) { alert(err.response?.data?.message || '삭제에 실패했습니다.'); setShowDeleteDialog(false); } finally { setIsSubmitting(false); } }; // Shared modal field style const fieldClass = "w-full px-3 py-2 border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"; const labelClass = "text-xs font-medium text-text-muted"; const selectClass = "w-full px-3 py-2 border border-border rounded-lg text-sm bg-white focus:outline-none focus:ring-2 focus:ring-primary"; return (
{/* Header */}

계정 관리

직원 계정 생성, 수정, 삭제 (ADMIN 전용)

{/* Search */}
setSearchKeyword(e.target.value)} className="w-full pl-9 pr-3 py-2 rounded-xl bg-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-primary transition-all" placeholder="이름으로 검색..." />
{/* Table */} {loading ? (
로딩 중...
) : (
{filtered.map((emp, idx) => ( ))}
이름 이메일 권한 상태 생년월일 학력 거주지 가입일 액션
{emp.name[0]}
{emp.name}
{emp.email || '-'} {roleLabels[emp.roleCode]} {statusLabels[emp.empStatus]} {emp.birthDate || '-'} {emp.education ? ( {educationLabels[emp.education] || emp.education} ) : '-'} {emp.residence || '-'} {emp.joinedDate}
{filtered.length === 0 && (
검색 결과가 없습니다.
)}
)} {/* Create Modal */} {showCreateModal && (
setShowCreateModal(false)}>
e.stopPropagation()}>

새 계정 생성

{/* Basic Info */}
setCreateForm((f) => ({ ...f, loginId: e.target.value }))} className={fieldClass} placeholder="login_id" />
setCreateForm((f) => ({ ...f, name: e.target.value }))} className={fieldClass} placeholder="홍길동" />
setCreateForm((f) => ({ ...f, password: e.target.value }))} className={fieldClass} placeholder="••••••••" />
setCreateForm((f) => ({ ...f, email: e.target.value }))} className={fieldClass} placeholder="email@example.com" />
setCreateForm((f) => ({ ...f, phone: e.target.value }))} className={fieldClass} placeholder="010-0000-0000" />
setCreateForm((f) => ({ ...f, joinedDate: e.target.value }))} className={fieldClass} />
{/* Divider */}

추가 정보

setCreateForm((f) => ({ ...f, birthDate: e.target.value }))} className={fieldClass} />
setCreateForm((f) => ({ ...f, major: e.target.value }))} className={fieldClass} placeholder="컴퓨터공학" />
setCreateForm((f) => ({ ...f, graduationDate: e.target.value }))} className={fieldClass} />
setCreateForm((f) => ({ ...f, residence: e.target.value }))} className={fieldClass} placeholder="서울시 강남구" />
{createError && (
{createError}
)}
)} {/* Edit Modal */} {showEditModal && targetEmployee && (
setShowEditModal(false)}>
e.stopPropagation()}>

계정 수정 — {targetEmployee.name}

{/* Basic Info */}
setEditForm((f) => ({ ...f, name: e.target.value }))} className={fieldClass} />
setEditForm((f) => ({ ...f, email: e.target.value }))} className={fieldClass} />
setEditForm((f) => ({ ...f, phone: e.target.value }))} className={fieldClass} />
setEditForm((f) => ({ ...f, joinedDate: e.target.value }))} className={fieldClass} />
setEditForm((f) => ({ ...f, leftDate: e.target.value }))} className={fieldClass} />
{/* Divider */}

추가 정보

setEditForm((f) => ({ ...f, birthDate: e.target.value }))} className={fieldClass} />
setEditForm((f) => ({ ...f, major: e.target.value }))} className={fieldClass} placeholder="컴퓨터공학" />
setEditForm((f) => ({ ...f, graduationDate: e.target.value }))} className={fieldClass} />
setEditForm((f) => ({ ...f, residence: e.target.value }))} className={fieldClass} placeholder="서울시 강남구" />
{editError && (
{editError}
)}
)} {/* Delete Confirmation */} {showDeleteDialog && targetEmployee && (
setShowDeleteDialog(false)}>
e.stopPropagation()}>

계정 삭제

이 작업은 되돌릴 수 없습니다

{targetEmployee.name} 계정을 삭제하시겠습니까?

소프트 삭제 처리되며 시스템 접근이 차단됩니다.

)}
); }