import { useEffect, useState } from 'react' import { provisionChannels, updateContact, type Contact, type Org, type ProvisionResult, } from '../api/client' import ConfirmDialog from './ConfirmDialog' import StatusBadge from './StatusBadge' const APPLICANT_FIELDS: { key: keyof Contact; label: string }[] = [ { key: 'deptName', label: '부서명' }, { key: 'managerName', label: '담당자명' }, { key: 'managerTitle', label: '직급/직함' }, { key: 'managerPhone', label: '연락처' }, { key: 'managerEmail', label: '이메일' }, ] const MJ_FIELDS: { key: keyof Contact; label: string; type?: string }[] = [ { key: 'mjDeptName', label: '부서명' }, { key: 'mjManagerName', label: '담당자명' }, { key: 'mjManagerPhone', label: '연락처' }, { key: 'mjManagerEmail', label: '이메일' }, ] const LAWYER_FIELDS: { key: keyof Contact; label: string; type?: string }[] = [ { key: 'lawyerName', label: '성명' }, { key: 'lawyerPhone', label: '연락처' }, { key: 'lawyerEmail', label: '이메일' }, { key: 'lawyerAssignedDate', label: '배정일', type: 'date' }, ] function emptyContact(org: Org): Contact { return { deptName: org.deptName ?? '', managerName: org.managerName ?? '', managerTitle: org.managerTitle ?? '', managerPhone: org.managerPhone ?? '', managerEmail: org.managerEmail ?? '', mjDeptName: org.mjDeptName ?? '', mjManagerName: org.mjManagerName ?? '', mjManagerPhone: org.mjManagerPhone ?? '', mjManagerEmail: org.mjManagerEmail ?? '', lawyerName: org.lawyerName ?? '', lawyerPhone: org.lawyerPhone ?? '', lawyerEmail: org.lawyerEmail ?? '', lawyerAssignedDate: org.lawyerAssignedDate ?? '', } } const REQUIRED_FIELDS: (keyof Contact)[] = [ 'deptName', 'managerName', 'managerPhone', 'managerEmail', ] function ContactFieldGroup({ title, fields, contact, onChange, }: { title: string fields: { key: keyof Contact; label: string; type?: string }[] contact: Contact onChange: (key: keyof Contact, value: string) => void }) { return (

{title}

{fields.map((field) => (
onChange(field.key, e.target.value)} />
))}
) } export default function OrgDetail({ org, onChanged }: { org: Org; onChanged: () => void }) { const [contact, setContact] = useState(emptyContact(org)) const [confirming, setConfirming] = useState(false) const [result, setResult] = useState(null) const [error, setError] = useState(null) const [busy, setBusy] = useState(false) // org.id로만 키를 잡는다(org 객체 전체가 아니라) - App.reload()가 채널 생성 뒤에 // 새 배열/새 객체를 만들어 넘기더라도, 같은 기관을 계속 보고 있는 한 방금 받은 // result/error를 이 effect가 지워버리면 안 되기 때문이다(같은 이유로 입력 중이던 // contact 값도 다른 기관으로 전환할 때만 초기화한다). useEffect(() => { setContact(emptyContact(org)) setResult(null) setError(null) // eslint-disable-next-line react-hooks/exhaustive-deps }, [org.id]) const displayMj = `${org.orgNo}_${org.orgName} (문정원)` const displayLaw = `${org.orgNo}_${org.orgName} (법률검토)` const canProvision = org.status !== 'INFO_PENDING' const requiredFilled = REQUIRED_FIELDS.every((key) => contact[key].trim() !== '') function setField(key: keyof Contact, value: string) { setContact((prev) => ({ ...prev, [key]: value })) } async function save() { setError(null) setBusy(true) try { await updateContact(org.id, contact) onChanged() } catch (e) { setError((e as Error).message) } finally { setBusy(false) } } async function provision() { setError(null) setBusy(true) try { const provisionResult = await provisionChannels(org.id) setResult(provisionResult) onChanged() } catch (e) { setError((e as Error).message) } finally { setBusy(false) setConfirming(false) } } return (

{org.orgNo} {org.orgName}

{error &&

{error}

} {result && (

문정원 채널: {outcomeLabel(result.mj)}

법률검토 채널: {outcomeLabel(result.law)}

{result.mj === 'FAILED' && result.law === 'FAILED' ? (

문정원 채널과 법률검토 채널 모두 생성에 실패했습니다. 아직 만들어진 채널이 없으니 [채널 생성]을 다시 눌러도 안전합니다.

) : ( <> {result.law === 'FAILED' && (

법률검토 채널 생성에 실패했습니다. 문정원 채널은 그대로 남아 있으니 [채널 생성]을 다시 눌러도 안전합니다. 없는 채널만 다시 만듭니다.

)} {result.mj === 'FAILED' && (

문정원 채널 생성에 실패했습니다. 법률검토 채널은 그대로 남아 있으니 [채널 생성]을 다시 눌러도 안전합니다. 없는 채널만 다시 만듭니다.

)} )} {result.message && (
{result.message}
)}
)} {confirming && ( void provision()} onCancel={() => setConfirming(false)} /> )}
) } function outcomeLabel(outcome: ProvisionResult['mj']): string { switch (outcome) { case 'CACHED': return '이미 있음 (변경 없음)' case 'RECOVERED': return '기존 채널 연결됨' case 'CREATED': return '새로 생성됨' case 'FAILED': return '실패' } }