'use client' import { useState } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Switch } from '@/components/ui/switch'; import { Badge } from '@/components/ui/badge'; import { Separator } from '@/components/ui/separator'; import { toast } from 'sonner'; import { Loader2, Plus, Trash2, FileText, AlertCircle } from 'lucide-react'; // API 함수 및 타입 import { submitApproval, createSubmitApprovalRequest, createApprovalLine } from '@/lib/knox-api/approval/approval'; import type { ApprovalLine, SubmitApprovalRequest } from '@/lib/knox-api/approval/approval'; // Mock 데이터 import { mockApprovalAPI, createMockApprovalLine, getRoleText } from './mocks/approval-mock'; const formSchema = z.object({ subject: z.string().min(1, '제목은 필수입니다'), contents: z.string().min(1, '내용은 필수입니다'), contentsType: z.enum(['TEXT', 'HTML', 'MIME']), docSecuType: z.enum(['PERSONAL', 'CONFIDENTIAL', 'CONFIDENTIAL_STRICT']), urgYn: z.boolean(), importantYn: z.boolean(), notifyOption: z.enum(['0', '1', '2', '3']), docMngSaveCode: z.enum(['0', '1']), sbmLang: z.enum(['ko', 'ja', 'zh', 'en']), timeZone: z.string().default('GMT+9'), aplns: z.array(z.object({ userId: z.string().min(1, '사용자 ID는 필수입니다'), emailAddress: z.string().email('유효한 이메일 주소를 입력해주세요').optional(), role: z.enum(['0', '1', '2', '3', '4', '7', '9']), seq: z.string(), opinion: z.string().optional() })).min(1, '최소 1개의 결재 경로가 필요합니다') }); type FormData = z.infer; interface ApprovalSubmitProps { useFakeData?: boolean; systemId?: string; onSubmitSuccess?: (apInfId: string) => void; } export default function ApprovalSubmit({ useFakeData = false, systemId = 'EVCP_SYSTEM', onSubmitSuccess }: ApprovalSubmitProps) { const [isSubmitting, setIsSubmitting] = useState(false); const [submitResult, setSubmitResult] = useState<{ apInfId: string } | null>(null); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { subject: '', contents: '', contentsType: 'TEXT', docSecuType: 'PERSONAL', urgYn: false, importantYn: false, notifyOption: '0', docMngSaveCode: '0', sbmLang: 'ko', timeZone: 'GMT+9', aplns: [ { userId: '', emailAddress: '', role: '0', seq: '1', opinion: '' } ] } }); const aplns = form.watch('aplns'); const addApprovalLine = () => { const newSeq = (aplns.length + 1).toString(); form.setValue('aplns', [...aplns, { userId: '', emailAddress: '', role: '1', seq: newSeq, opinion: '' }]); }; const removeApprovalLine = (index: number) => { if (aplns.length > 1) { const newAplns = aplns.filter((_, i) => i !== index); // 순서 재정렬 const reorderedAplns = newAplns.map((apln, i) => ({ ...apln, seq: (i + 1).toString() })); form.setValue('aplns', reorderedAplns); } }; const onSubmit = async (data: FormData) => { setIsSubmitting(true); setSubmitResult(null); try { // 결재 경로 생성 const approvalLines: ApprovalLine[] = await Promise.all( data.aplns.map(async (apln) => { if (useFakeData) { return createMockApprovalLine({ userId: apln.userId, emailAddress: apln.emailAddress, role: apln.role, seq: apln.seq, opinion: apln.opinion }); } else { return createApprovalLine( { userId: apln.userId, emailAddress: apln.emailAddress }, apln.role, apln.seq, { opinion: apln.opinion } ); } }) ); // 상신 요청 생성 const submitRequest: SubmitApprovalRequest = useFakeData ? { ...data, urgYn: data.urgYn ? 'Y' : 'N', importantYn: data.importantYn ? 'Y' : 'N', sbmDt: new Date().toISOString().replace(/-|:|T/g, '').slice(0, 14), apInfId: 'test-ap-inf-id-' + Date.now(), aplns: approvalLines } : await createSubmitApprovalRequest( data.contents, data.subject, approvalLines, { contentsType: data.contentsType, docSecuType: data.docSecuType, urgYn: data.urgYn ? 'Y' : 'N', importantYn: data.importantYn ? 'Y' : 'N', notifyOption: data.notifyOption, docMngSaveCode: data.docMngSaveCode, sbmLang: data.sbmLang, timeZone: data.timeZone } ); // API 호출 const response = useFakeData ? await mockApprovalAPI.submitApproval(submitRequest) : await submitApproval(submitRequest, systemId); if (response.result === 'SUCCESS') { setSubmitResult({ apInfId: response.data.apInfId }); toast.success('결재가 성공적으로 상신되었습니다.'); onSubmitSuccess?.(response.data.apInfId); form.reset(); } else { toast.error('결재 상신에 실패했습니다.'); } } catch (error) { console.error('결재 상신 오류:', error); toast.error('결재 상신 중 오류가 발생했습니다.'); } finally { setIsSubmitting(false); } }; return ( 결재 상신 새로운 결재를 상신합니다. {useFakeData && '(테스트 모드)'} {submitResult && (
상신 완료

결재 ID: {submitResult.apInfId}

)}
{/* 기본 정보 */}

기본 정보

( 제목 * )} /> ( 내용 *