'use client' import * as React from 'react' import { useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import * as z from 'zod' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Textarea } from '@/components/ui/textarea' import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form' import { useToast } from '@/hooks/use-toast' import { saveSelectionResult, getSelectionResult } from './actions' import { Loader2, Save, FileText, Download, X } from 'lucide-react' import { Dropzone, DropzoneZone, DropzoneUploadIcon, DropzoneTitle, DropzoneDescription, DropzoneInput } from '@/components/ui/dropzone' const selectionResultSchema = z.object({ summary: z.string().min(1, '결과요약을 입력해주세요'), }) type SelectionResultFormData = z.infer interface SelectionResultFormProps { biddingId: number onSuccess: () => void readOnly?: boolean } interface AttachmentInfo { id: number fileName: string originalFileName: string fileSize: number mimeType: string filePath: string uploadedAt: Date | null } export function SelectionResultForm({ biddingId, onSuccess, readOnly = false }: SelectionResultFormProps) { const { toast } = useToast() const [isSubmitting, setIsSubmitting] = React.useState(false) const [isLoading, setIsLoading] = React.useState(true) const [attachmentFiles, setAttachmentFiles] = React.useState([]) const [existingAttachments, setExistingAttachments] = React.useState([]) const form = useForm({ resolver: zodResolver(selectionResultSchema), defaultValues: { summary: '', }, }) // 기존 선정결과 로드 React.useEffect(() => { const loadSelectionResult = async () => { setIsLoading(true) try { const result = await getSelectionResult(biddingId) if (result.success && result.data) { form.reset({ summary: result.data.summary || '', }) if (result.data.attachments) { setExistingAttachments(result.data.attachments) } } } catch (error) { console.error('Failed to load selection result:', error) toast({ title: '로드 실패', description: '선정결과를 불러오는데 실패했습니다.', variant: 'destructive', }) } finally { setIsLoading(false) } } loadSelectionResult() }, [biddingId, form, toast]) const removeAttachmentFile = (index: number) => { setAttachmentFiles(prev => prev.filter((_, i) => i !== index)) } const removeExistingAttachment = (id: number) => { setExistingAttachments(prev => prev.filter(att => att.id !== id)) } const downloadAttachment = (filePath: string, fileName: string) => { // 파일 다운로드 (filePath가 절대 경로인 경우) if (filePath.startsWith('http') || filePath.startsWith('/')) { window.open(filePath, '_blank') } else { // 상대 경로인 경우 window.open(`/api/files/${filePath}`, '_blank') } } const onSubmit = async (data: SelectionResultFormData) => { setIsSubmitting(true) try { const result = await saveSelectionResult({ biddingId, summary: data.summary, attachments: attachmentFiles }) if (result.success) { toast({ title: '저장 완료', description: result.message, }) onSuccess() } else { toast({ title: '저장 실패', description: result.error, variant: 'destructive', }) } } catch (error) { console.error('Failed to save selection result:', error) toast({ title: '저장 실패', description: '선정결과 저장 중 오류가 발생했습니다.', variant: 'destructive', }) } finally { setIsSubmitting(false) } } if (isLoading) { return ( 선정결과
로딩 중...
) } return ( 선정결과
{/* 결과요약 */} ( 결과요약