import { useEffect, useState } from 'react' import { createMemo, deleteMemo, getMemos, type Org, type WorkMemo } from '../api/client' const CUSTOM_CONTACT_VALUE = '__custom__' const dateFormatter = new Intl.DateTimeFormat('ko-KR', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', }) function formatDateTime(createdAt: number): string { return dateFormatter.format(new Date(createdAt)) } function applicantOptionLabel(org: Org): string | null { if (!org.applicant) { return null } return org.applicant.title ? `${org.applicant.name} ${org.applicant.title}` : org.applicant.name } /** 신청기관 담당자, 문정원 담당자, 아이티앤 담당자, 담당 변호사 중 배정되어 있는 사람만 후보로 낸다. * 이름이 같은 사람이 중복 등록돼 있어도 셀렉트 옵션은 한 번만 보이도록 중복을 없앤다. */ function contactOptions(org: Org): string[] { const candidates = [ applicantOptionLabel(org), org.mj?.name ?? null, org.itn?.name ?? null, org.lawyer?.name ?? null, ] const seen = new Set() // 요구사항: 선택박스 최상단은 항상 '시스템'이다 (자동/시스템성 메모 구분용) const options: string[] = ['시스템'] for (const candidate of candidates) { if (!candidate || candidate.trim() === '' || seen.has(candidate)) { continue } seen.add(candidate) options.push(candidate) } return options } /** 기관관리 상세의 업무메모 탭. 통화 등 담당자와의 연락 내용을 기록/조회/삭제한다. */ export default function WorkMemos({ org }: { org: Org }) { const options = contactOptions(org) const [memos, setMemos] = useState([]) const [loading, setLoading] = useState(false) const [contactChoice, setContactChoice] = useState(options[0] ?? CUSTOM_CONTACT_VALUE) const [customContactName, setCustomContactName] = useState('') const [body, setBody] = useState('') const [busy, setBusy] = useState(false) const [error, setError] = useState(null) useEffect(() => { let cancelled = false setLoading(true) getMemos(org.id) .then((data) => { if (!cancelled) { setMemos(data) } }) .finally(() => { if (!cancelled) { setLoading(false) } }) return () => { cancelled = true } }, [org.id]) const isCustom = contactChoice === CUSTOM_CONTACT_VALUE const effectiveContactName = (isCustom ? customContactName : contactChoice).trim() const canSubmit = effectiveContactName !== '' && body.trim() !== '' && !busy async function handleSubmit() { if (!canSubmit) { return } setBusy(true) setError(null) try { const created = await createMemo(org.id, { contactName: effectiveContactName, body }) setMemos((prev) => [created, ...prev]) setBody('') } catch (e) { setError(e instanceof Error ? e.message : '메모 등록에 실패했습니다.') } finally { setBusy(false) } } async function handleDelete(memo: WorkMemo) { if (!window.confirm('이 메모를 삭제할까요?')) { return } try { await deleteMemo(org.id, memo.id) setMemos((prev) => prev.filter((m) => m.id !== memo.id)) } catch (e) { setError(e instanceof Error ? e.message : '메모 삭제에 실패했습니다.') } } return (
{isCustom && (
setCustomContactName(e.target.value)} className="rounded-md border border-gray-300 px-2 py-1.5 text-sm" />
)}