258 lines
8.6 KiB
JavaScript
258 lines
8.6 KiB
JavaScript
import { useState, useEffect } from 'react';
|
|
import {createPortal} from "react-dom";
|
|
import { showToast } from '@/components/common/Toast';
|
|
import { fetchCommonCodeList } from '@/api/commonApi';
|
|
import {
|
|
saveSatelliteCompany,
|
|
fetchSatelliteCompanyDetail,
|
|
updateSatelliteCompany,
|
|
} from '@/api/satelliteApi';
|
|
import useDraggable from '../hooks/useDraggable';
|
|
|
|
const NATIONAL_OPTIONS = [
|
|
{ code: '440', name: '대한민국' },
|
|
{ code: '338', name: '미국' },
|
|
{ code: '413', name: '중국' },
|
|
{ code: '431', name: '일본' },
|
|
];
|
|
|
|
/**
|
|
* 위성 사업자 등록/수정 팝업
|
|
* @param {{ companyNo?: number, onClose: () => void, onSaved: () => void }} props
|
|
* companyNo가 있으면 수정 모드, 없으면 등록 모드
|
|
*/
|
|
export default function SatelliteProviderRegisterPopup({ companyNo, onClose, onSaved }) {
|
|
const isEditMode = !!companyNo;
|
|
|
|
const [companyTypeOptions, setCompanyTypeOptions] = useState([]);
|
|
|
|
const [companyTypeCode, setCompanyTypeCode] = useState('');
|
|
const [companyName, setCompanyName] = useState('');
|
|
const [nationalCode, setNationalCode] = useState('');
|
|
const [location, setLocation] = useState('');
|
|
const [companyDetail, setCompanyDetail] = useState('');
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [isSaving, setIsSaving] = useState(false);
|
|
const [error, setError] = useState(null);
|
|
const { position, handleMouseDown } = useDraggable();
|
|
|
|
// 마운트 시 사업자 분류 공통코드 로드 + 수정 모드면 상세조회
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
|
|
async function load() {
|
|
setIsLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
// 공통코드 로드
|
|
const codeList = await fetchCommonCodeList('000039');
|
|
if (cancelled) return;
|
|
setCompanyTypeOptions(codeList);
|
|
|
|
// 수정 모드: 상세조회 후 역매핑
|
|
if (companyNo) {
|
|
const data = await fetchSatelliteCompanyDetail(companyNo);
|
|
if (cancelled || !data) return;
|
|
|
|
// companyTypeName → companyTypeCode 역매핑
|
|
const matchedType = codeList.find(
|
|
(opt) => opt.commonCodeTypeName === data.companyTypeName
|
|
);
|
|
setCompanyTypeCode(matchedType?.commonCodeTypeNumber || '');
|
|
|
|
// nationalCodeName → nationalCode 역매핑
|
|
const matchedNation = NATIONAL_OPTIONS.find(
|
|
(opt) => opt.name === data.nationalCodeName
|
|
);
|
|
setNationalCode(matchedNation?.code || '');
|
|
|
|
setCompanyName(data.companyName || '');
|
|
setLocation(data.location || '');
|
|
setCompanyDetail(data.companyDetail || '');
|
|
}
|
|
} catch {
|
|
setError('데이터 조회 중 오류가 발생했습니다.');
|
|
} finally {
|
|
if (!cancelled) setIsLoading(false);
|
|
}
|
|
}
|
|
|
|
load();
|
|
return () => { cancelled = true; };
|
|
}, [companyNo]);
|
|
|
|
const handleSave = async () => {
|
|
if (!companyTypeCode) {
|
|
showToast('사업자 분류를 선택해주세요.');
|
|
return;
|
|
}
|
|
if (!companyName.trim()) {
|
|
showToast('사업자명을 입력해주세요.');
|
|
return;
|
|
}
|
|
if (!nationalCode) {
|
|
showToast('국가를 선택해주세요.');
|
|
return;
|
|
}
|
|
|
|
setIsSaving(true);
|
|
setError(null);
|
|
|
|
try {
|
|
if (isEditMode) {
|
|
await updateSatelliteCompany({
|
|
companyNo,
|
|
companyTypeCode,
|
|
companyName,
|
|
nationalCode,
|
|
location,
|
|
companyDetail,
|
|
});
|
|
} else {
|
|
await saveSatelliteCompany({
|
|
companyTypeCode,
|
|
companyName,
|
|
nationalCode,
|
|
location,
|
|
companyDetail,
|
|
});
|
|
}
|
|
onSaved?.();
|
|
onClose();
|
|
} catch {
|
|
setError('저장 중 오류가 발생했습니다.');
|
|
} finally {
|
|
setIsSaving(false);
|
|
}
|
|
};
|
|
|
|
return createPortal(
|
|
<div className="popupUtillWrap" style={{ transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))` }}>
|
|
<div className="popupUtill">
|
|
<div className="puHeader" onMouseDown={handleMouseDown} style={{ cursor: 'grab' }}>
|
|
<span className="title">
|
|
{isEditMode ? '위성 사업자 상세' : '위성 사업자 등록'}
|
|
</span>
|
|
<button
|
|
type="button"
|
|
className="puClose"
|
|
aria-label="닫기"
|
|
onClick={onClose}
|
|
/>
|
|
</div>
|
|
|
|
<div className="puBody">
|
|
{isLoading && <div className="loading">조회 중...</div>}
|
|
{error && <div className="error">{error}</div>}
|
|
|
|
{!isLoading && (
|
|
<table className="table">
|
|
<caption>
|
|
위성 사업자 {isEditMode ? '상세' : '등록'} - 사업자 분류, 사업자명, 국가, 소재지, 상세내역에 대한 내용을 {isEditMode ? '조회/수정' : '등록'}하는 표입니다.
|
|
</caption>
|
|
<colgroup>
|
|
<col style={{ width: '30%' }} />
|
|
<col style={{ width: '' }} />
|
|
</colgroup>
|
|
<tbody>
|
|
<tr>
|
|
<th scope="row">사업자 분류 <span className="required">*</span></th>
|
|
<td>
|
|
<select
|
|
aria-label="사업자 분류"
|
|
value={companyTypeCode}
|
|
onChange={(e) => setCompanyTypeCode(e.target.value)}
|
|
>
|
|
<option value="">선택</option>
|
|
{companyTypeOptions.map((opt) => (
|
|
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
|
|
{opt.commonCodeTypeName}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">사업자명 <span className="required">*</span></th>
|
|
<td>
|
|
<input
|
|
type="text"
|
|
placeholder="사업자명"
|
|
aria-label="사업자명"
|
|
value={companyName}
|
|
onChange={(e) => setCompanyName(e.target.value)}
|
|
/>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">국가 <span className="required">*</span></th>
|
|
<td>
|
|
<select
|
|
aria-label="국가"
|
|
value={nationalCode}
|
|
onChange={(e) => setNationalCode(e.target.value)}
|
|
>
|
|
<option value="">선택</option>
|
|
{NATIONAL_OPTIONS.map((opt) => (
|
|
<option key={opt.code} value={opt.code}>
|
|
{opt.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">소재지</th>
|
|
<td>
|
|
<input
|
|
type="text"
|
|
placeholder="소재지"
|
|
aria-label="소재지"
|
|
value={location}
|
|
onChange={(e) => setLocation(e.target.value)}
|
|
/>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">상세내역</th>
|
|
<td>
|
|
<textarea
|
|
placeholder="내용을 입력하세요"
|
|
aria-label="상세내역"
|
|
value={companyDetail}
|
|
onChange={(e) => setCompanyDetail(e.target.value)}
|
|
/>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
)}
|
|
</div>
|
|
|
|
<div className="puFooter">
|
|
<div className="popBtnWrap">
|
|
<button
|
|
type="button"
|
|
className="btn basic"
|
|
onClick={handleSave}
|
|
disabled={isSaving}
|
|
>
|
|
{isSaving ? '저장 중...' : isEditMode ? '수정' : '저장'}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="btn dark"
|
|
onClick={onClose}
|
|
>
|
|
취소
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>,
|
|
document.body
|
|
);
|
|
}
|