From d66d308169e559457878c02e3b0443da22693241 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Tue, 1 Jul 2025 02:53:18 +0000 Subject: (최겸) 정보시스템 인포메이션 기능 개발 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/information/table/add-information-dialog.tsx | 329 +++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 lib/information/table/add-information-dialog.tsx (limited to 'lib/information/table/add-information-dialog.tsx') diff --git a/lib/information/table/add-information-dialog.tsx b/lib/information/table/add-information-dialog.tsx new file mode 100644 index 00000000..a879fbfe --- /dev/null +++ b/lib/information/table/add-information-dialog.tsx @@ -0,0 +1,329 @@ +"use client" + +import * as React from "react" +import { zodResolver } from "@hookform/resolvers/zod" +import { useForm } from "react-hook-form" +import { toast } from "sonner" +import { Loader, Upload, X } from "lucide-react" +import { useRouter } from "next/navigation" + +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { Input } from "@/components/ui/input" +import { Textarea } from "@/components/ui/textarea" +import { Switch } from "@/components/ui/switch" +import { createInformation } from "@/lib/information/service" +import { createInformationSchema, type CreateInformationSchema } from "@/lib/information/validations" + +interface AddInformationDialogProps { + open: boolean + onOpenChange: (open: boolean) => void +} + +export function AddInformationDialog({ + open, + onOpenChange, +}: AddInformationDialogProps) { + const router = useRouter() + const [isLoading, setIsLoading] = React.useState(false) + const [uploadedFile, setUploadedFile] = React.useState(null) + + const form = useForm({ + resolver: zodResolver(createInformationSchema), + defaultValues: { + pageCode: "", + pageName: "", + title: "", + description: "", + noticeTitle: "", + noticeContent: "", + attachmentFileName: "", + attachmentFilePath: "", + attachmentFileSize: "", + isActive: true, + }, + }) + + const handleFileSelect = (event: React.ChangeEvent) => { + const file = event.target.files?.[0] + if (file) { + setUploadedFile(file) + // 파일 크기를 MB 단위로 변환 + const sizeInMB = (file.size / (1024 * 1024)).toFixed(2) + form.setValue("attachmentFileName", file.name) + form.setValue("attachmentFileSize", `${sizeInMB} MB`) + } + } + + const removeFile = () => { + setUploadedFile(null) + form.setValue("attachmentFileName", "") + form.setValue("attachmentFilePath", "") + form.setValue("attachmentFileSize", "") + } + + const uploadFile = async (file: File): Promise => { + const formData = new FormData() + formData.append("file", file) + + const response = await fetch("/api/upload", { + method: "POST", + body: formData, + }) + + if (!response.ok) { + throw new Error("파일 업로드에 실패했습니다.") + } + + const result = await response.json() + return result.url + } + + const onSubmit = async (values: CreateInformationSchema) => { + setIsLoading(true) + try { + const finalValues = { ...values } + + // 파일이 있으면 업로드 + if (uploadedFile) { + const filePath = await uploadFile(uploadedFile) + finalValues.attachmentFilePath = filePath + } + + const result = await createInformation(finalValues) + + if (result.success) { + toast.success(result.message) + form.reset() + setUploadedFile(null) + onOpenChange(false) + router.refresh() + } else { + toast.error(result.message) + } + } catch (error) { + toast.error("인포메이션 생성에 실패했습니다.") + console.error(error) + } finally { + setIsLoading(false) + } + } + + // 다이얼로그가 닫힐 때 폼 초기화 + React.useEffect(() => { + if (!open) { + form.reset() + setUploadedFile(null) + } + }, [open, form]) + + return ( + + + + 인포메이션 추가 + + 새로운 페이지 인포메이션을 추가합니다. + + + +
+ +
+ ( + + 페이지 코드 + + + + + + )} + /> + + ( + + 페이지명 + + + + + + )} + /> +
+ + ( + + 제목 + + + + + + )} + /> + + ( + + 설명 + +