// CommonApp.jsx - React Common Code Management Component for GroupWare const { useState, useEffect, useRef } = React; const CommonApp = () => { // 상태 관리 const [groupData, setGroupData] = useState([]); const [currentData, setCurrentData] = useState([]); const [selectedGroupCode, setSelectedGroupCode] = useState(null); const [selectedGroupName, setSelectedGroupName] = useState(''); const [loading, setLoading] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [deleteTargetIdx, setDeleteTargetIdx] = useState(null); const [editMode, setEditMode] = useState('add'); // 편집 폼 데이터 const [editData, setEditData] = useState({ idx: '', grp: '', code: '', svalue: '', ivalue: '', fvalue: '', svalue2: '', memo: '' }); // 페이지 로드시 초기 데이터 로드 useEffect(() => { loadGroups(); }, []); // API 호출 함수들 const loadGroups = async () => { setLoading(true); try { const response = await fetch('http://127.0.0.1:7979/Common/GetGroups'); const data = await response.json(); setGroupData(data || []); } catch (error) { console.error('그룹 데이터 로드 중 오류 발생:', error); showNotification('그룹 데이터 로드 중 오류가 발생했습니다.', 'error'); } finally { setLoading(false); } }; const loadDataByGroup = async (grp) => { setLoading(true); try { let url = 'http://127.0.0.1:7979/Common/GetList'; if (grp) { url += '?grp=' + encodeURIComponent(grp); } const response = await fetch(url); const data = await response.json(); setCurrentData(data || []); } catch (error) { console.error('데이터 로드 중 오류 발생:', error); showNotification('데이터 로드 중 오류가 발생했습니다.', 'error'); } finally { setLoading(false); } }; const saveData = async () => { try { const data = { idx: parseInt(editData.idx) || 0, grp: editData.grp, code: editData.code, svalue: editData.svalue, ivalue: parseInt(editData.ivalue) || 0, fvalue: parseFloat(editData.fvalue) || 0.0, svalue2: editData.svalue2, memo: editData.memo }; setLoading(true); const response = await fetch('http://127.0.0.1:7979/Common/Save', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data) }); const result = await response.json(); if (result.Success) { showNotification(result.Message, 'success'); setShowEditModal(false); if (selectedGroupCode) { loadDataByGroup(selectedGroupCode); } } else { showNotification(result.Message, 'error'); } } catch (error) { console.error('저장 중 오류 발생:', error); showNotification('저장 중 오류가 발생했습니다.', 'error'); } finally { setLoading(false); } }; const deleteItem = async () => { if (!deleteTargetIdx) return; try { setLoading(true); const response = await fetch('http://127.0.0.1:7979/Common/Delete', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ idx: deleteTargetIdx }) }); const data = await response.json(); if (data.Success) { showNotification(data.Message, 'success'); setShowDeleteModal(false); if (selectedGroupCode) { loadDataByGroup(selectedGroupCode); } } else { showNotification(data.Message, 'error'); } } catch (error) { console.error('삭제 중 오류 발생:', error); showNotification('삭제 중 오류가 발생했습니다.', 'error'); } finally { setLoading(false); setDeleteTargetIdx(null); } }; // 이벤트 핸들러들 const selectGroup = (code, name) => { setSelectedGroupCode(code); setSelectedGroupName(name); loadDataByGroup(code); }; const openAddModal = () => { if (!selectedGroupCode) { showNotification('먼저 코드그룹을 선택하세요.', 'warning'); return; } setEditMode('add'); setEditData({ idx: '', grp: selectedGroupCode, code: '', svalue: '', ivalue: '', fvalue: '', svalue2: '', memo: '' }); setShowEditModal(true); }; const openEditModal = (item) => { setEditMode('edit'); setEditData({ idx: item.idx, grp: item.grp || '', code: item.code || '', svalue: item.svalue || '', ivalue: item.ivalue || '', fvalue: item.fvalue || '', svalue2: item.svalue2 || '', memo: item.memo || '' }); setShowEditModal(true); }; const openDeleteModal = (idx) => { setDeleteTargetIdx(idx); setShowDeleteModal(true); setShowEditModal(false); }; const closeModals = () => { setShowEditModal(false); setShowDeleteModal(false); setDeleteTargetIdx(null); }; const handleInputChange = (field, value) => { setEditData(prev => ({ ...prev, [field]: value })); }; const showNotification = (message, type = 'info') => { // 기존 알림 제거 const existing = document.querySelectorAll('.notification-toast'); existing.forEach(el => el.remove()); const colors = { info: 'bg-blue-500/90', success: 'bg-green-500/90', warning: 'bg-yellow-500/90', error: 'bg-red-500/90' }; const icons = { info: '🔵', success: '✅', warning: '⚠️', error: '❌' }; const notification = document.createElement('div'); notification.className = `notification-toast fixed top-4 right-4 ${colors[type]} backdrop-blur-sm text-white px-4 py-3 rounded-lg z-50 shadow-lg border border-white/20`; notification.innerHTML = `
${icons[type]}${message}
`; document.body.appendChild(notification); setTimeout(() => { notification.style.transform = 'translateX(100%)'; notification.style.opacity = '0'; setTimeout(() => notification.remove(), 300); }, 3000); }; // 키보드 이벤트 useEffect(() => { const handleKeyDown = (e) => { if (e.key === 'Escape') { closeModals(); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, []); return (
{/* Navigation Component */}
{/* 2열 구조 메인 컨테이너 */}
{/* 좌측: 코드그룹 리스트 */}

코드그룹 목록

{groupData.length === 0 ? (
그룹 데이터가 없습니다.
) : ( groupData.map(group => (
selectGroup(group.code, group.memo)} >
{group.code}
{group.memo}
)) )}
{/* 우측: 상세 데이터 */}
{/* 상단 헤더 */}

{selectedGroupCode ? `${selectedGroupCode} - ${selectedGroupName}` : '코드그룹을 선택하세요'}

{currentData.length}

{/* 데이터 테이블 */}
{currentData.length === 0 ? ( ) : ( currentData.map(item => ( openEditModal(item)} > )) )}
코드 비고 값(문자열) 값(숫자) 값(실수) 값2
{selectedGroupCode ? '데이터가 없습니다.' : '좌측에서 코드그룹을 선택하세요'}
{item.code || '-'} {item.memo || '-'} {item.svalue || '-'} {item.ivalue || '0'} {item.fvalue || '0.0'} {item.svalue2 || '-'}
{/* 로딩 인디케이터 */} {loading && (
데이터 로딩 중...
)}
{/* 추가/편집 모달 */} {showEditModal && (
{/* 모달 헤더 */}

{editMode === 'add' ? '공용코드 추가' : '공용코드 편집'}

{/* 모달 내용 */}
handleInputChange('code', e.target.value)} required className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" placeholder="코드를 입력하세요" />
handleInputChange('svalue', e.target.value)} className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" placeholder="문자열 값" />
handleInputChange('ivalue', e.target.value)} className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" placeholder="숫자 값" />
handleInputChange('fvalue', e.target.value)} className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" placeholder="실수 값" />
handleInputChange('svalue2', e.target.value)} className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" placeholder="추가 문자열 값" />
{/* 모달 푸터 */}
{editMode === 'edit' && ( )}
)} {/* 삭제 확인 모달 */} {showDeleteModal && (

삭제 확인

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

선택한 공용코드를 삭제하시겠습니까?
이 작업은 되돌릴 수 없습니다.

)}
); };