import { useEffect, useState, useCallback } from 'react'; const token = () => localStorage.getItem('admin_token'); const authFetch = (url, opts = {}) => fetch(url, { ...opts, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token()}`, ...opts.headers } }); const EMPTY = { title: '', department: '', jobType: '정규직', description: '', requirements: '', preferred: '', deadline: '', headcount: 1, active: true }; const JOB_TYPES = ['정규직', '계약직', '인턴', '프리랜서']; export default function AdminRecruit() { const [page, setPage] = useState(0); const [data, setData] = useState({ content: [], totalPages: 0, totalElements: 0 }); const [modal, setModal] = useState(false); const [form, setForm] = useState(EMPTY); const [editId, setEditId] = useState(null); const [saving, setSaving] = useState(false); const [toast, setToast] = useState(null); const showToast = (msg, type = 'success') => { setToast({ msg, type }); setTimeout(() => setToast(null), 2500); }; const load = useCallback(() => { authFetch(`/api/admin/recruits?page=${page}&size=10`) .then(r => r.json()).then(setData); }, [page]); useEffect(() => { load(); }, [load]); const openCreate = () => { setForm(EMPTY); setEditId(null); setModal(true); }; const openEdit = (r) => { setForm({ ...r, deadline: r.deadline || '' }); setEditId(r.id); setModal(true); }; const handleSave = async () => { setSaving(true); const url = editId ? `/api/admin/recruits/${editId}` : '/api/admin/recruits'; const res = await authFetch(url, { method: editId ? 'PUT' : 'POST', body: JSON.stringify(form) }); setSaving(false); if (res.ok) { setModal(false); load(); showToast(editId ? '수정되었습니다.' : '등록되었습니다.'); } else showToast('저장 실패', 'error'); }; const handleDelete = async (id) => { if (!confirm('삭제하시겠습니까?')) return; const res = await authFetch(`/api/admin/recruits/${id}`, { method: 'DELETE' }); if (res.ok) { load(); showToast('삭제되었습니다.'); } }; const set = (k, v) => setForm(p => ({ ...p, [k]: v })); return ( <> {toast &&
{toast.msg}
}
전체 {data.totalElements}건
{data.content.map((r, i) => ( ))} {!data.content.length && ( )}
No공고명부서유형모집인원마감일상태관리
{data.totalElements - page * 10 - i} {r.title} {r.department || '-'} {r.jobType} {r.headcount}명 {r.deadline || '상시'} {r.active ? '진행중' : '마감'}
👥

등록된 채용공고가 없습니다.

{data.totalPages > 1 && (
페이지 {page + 1} / {data.totalPages}
{Array.from({ length: data.totalPages }, (_, i) => ( ))}
)}
{modal && (
e.target === e.currentTarget && setModal(false)}>

{editId ? '채용공고 수정' : '채용공고 등록'}

set('title', e.target.value)} placeholder="예: 백엔드 개발자 (Java/Spring)" />
set('department', e.target.value)} placeholder="개발팀, 영업팀 등" />
set('headcount', parseInt(e.target.value))} />
set('deadline', e.target.value)} />