- 전자결재: 다양식 지원(11종), 완료함, 동적폼 렌더러, QA 보고서 - 회계: 계정과목 검색모달 리팩토링, 거래처/세금계산서 개선 - HR: 근태/휴가/직원 소소한 수정 - vehicle/quality/pricing 마이너 수정 - approval_backup_v1 백업 보관
170 lines
6.0 KiB
TypeScript
170 lines
6.0 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Textarea } from '@/components/ui/textarea';
|
|
import { DatePicker } from '@/components/ui/date-picker';
|
|
import { format } from 'date-fns';
|
|
import { getCompanyAutoFill } from './form-actions';
|
|
import type { OfficialDocumentData } from './types';
|
|
|
|
interface OfficialDocumentFormProps {
|
|
data: OfficialDocumentData;
|
|
onChange: (data: OfficialDocumentData) => void;
|
|
}
|
|
|
|
export function OfficialDocumentForm({ data, onChange }: OfficialDocumentFormProps) {
|
|
const [isLoadingCompany, setIsLoadingCompany] = useState(false);
|
|
|
|
// 회사 정보 자동입력
|
|
useEffect(() => {
|
|
async function loadCompanyInfo() {
|
|
setIsLoadingCompany(true);
|
|
const result = await getCompanyAutoFill();
|
|
if (result.success && result.data) {
|
|
onChange({
|
|
...data,
|
|
documentDate: data.documentDate || format(new Date(), 'yyyy-MM-dd'),
|
|
companyName: data.companyName || result.data.companyName,
|
|
representativeName: data.representativeName || result.data.representativeName,
|
|
address: data.address || result.data.address,
|
|
phone: data.phone || result.data.phone,
|
|
fax: data.fax || result.data.fax,
|
|
email: data.email || result.data.email,
|
|
});
|
|
}
|
|
setIsLoadingCompany(false);
|
|
}
|
|
if (!data.companyName) {
|
|
loadCompanyInfo();
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* 1. 문서 정보 */}
|
|
<div className="bg-white rounded-lg border p-6">
|
|
<h3 className="text-lg font-semibold mb-4">1. 문서 정보</h3>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label>문서번호</Label>
|
|
<Input
|
|
placeholder="예: 2026030601"
|
|
value={data.documentNumber}
|
|
onChange={(e) => onChange({ ...data, documentNumber: e.target.value })}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label>일자 <span className="text-red-500">*</span></Label>
|
|
<DatePicker
|
|
value={data.documentDate}
|
|
onChange={(date) => onChange({ ...data, documentDate: date })}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 2. 수신 정보 */}
|
|
<div className="bg-white rounded-lg border p-6">
|
|
<h3 className="text-lg font-semibold mb-4">2. 수신 정보</h3>
|
|
<div className="space-y-4">
|
|
<div className="space-y-2">
|
|
<Label>수신 <span className="text-red-500">*</span></Label>
|
|
<Input
|
|
placeholder="수신처"
|
|
value={data.recipient}
|
|
onChange={(e) => onChange({ ...data, recipient: e.target.value })}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label>참조</Label>
|
|
<Input
|
|
placeholder="참조 (선택사항)"
|
|
value={data.reference}
|
|
onChange={(e) => onChange({ ...data, reference: e.target.value })}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label>제목 <span className="text-red-500">*</span></Label>
|
|
<Input
|
|
placeholder="공문서 제목"
|
|
value={data.title}
|
|
onChange={(e) => onChange({ ...data, title: e.target.value })}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 3. 본문 */}
|
|
<div className="bg-white rounded-lg border p-6">
|
|
<h3 className="text-lg font-semibold mb-4">3. 본문</h3>
|
|
<Textarea
|
|
placeholder="본문 내용을 입력해주세요"
|
|
value={data.body}
|
|
onChange={(e) => onChange({ ...data, body: e.target.value })}
|
|
className="min-h-[200px]"
|
|
/>
|
|
</div>
|
|
|
|
{/* 4. 붙임 (첨부서류) */}
|
|
<div className="bg-white rounded-lg border p-6">
|
|
<h3 className="text-lg font-semibold mb-4">4. 붙임 (첨부서류)</h3>
|
|
<Textarea
|
|
placeholder="첨부 서류 목록을 입력해주세요"
|
|
value={data.attachment}
|
|
onChange={(e) => onChange({ ...data, attachment: e.target.value })}
|
|
className="min-h-[100px]"
|
|
/>
|
|
</div>
|
|
|
|
{/* 5. 발신자 (회사 자동입력) */}
|
|
<div className="bg-white rounded-lg border p-6">
|
|
<h3 className="text-lg font-semibold mb-4">
|
|
5. 발신자
|
|
{isLoadingCompany && <span className="text-sm text-gray-400 ml-2">불러오는 중...</span>}
|
|
</h3>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label>상호</Label>
|
|
<Input value={data.companyName} disabled className="bg-gray-50" />
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label>대표이사</Label>
|
|
<Input value={data.representativeName} disabled className="bg-gray-50" />
|
|
</div>
|
|
<div className="md:col-span-2 space-y-2">
|
|
<Label>주소</Label>
|
|
<Input value={data.address} disabled className="bg-gray-50" />
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label>전화</Label>
|
|
<Input
|
|
value={data.phone}
|
|
onChange={(e) => onChange({ ...data, phone: e.target.value })}
|
|
placeholder="전화번호"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label>팩스</Label>
|
|
<Input
|
|
value={data.fax}
|
|
onChange={(e) => onChange({ ...data, fax: e.target.value })}
|
|
placeholder="팩스번호"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label>이메일</Label>
|
|
<Input
|
|
value={data.email}
|
|
onChange={(e) => onChange({ ...data, email: e.target.value })}
|
|
placeholder="이메일"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|