From d66d308169e559457878c02e3b0443da22693241 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
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

---
 .../table/update-information-dialog.tsx            | 376 +++++++++++++++++++++
 1 file changed, 376 insertions(+)
 create mode 100644 lib/information/table/update-information-dialog.tsx

(limited to 'lib/information/table/update-information-dialog.tsx')

diff --git a/lib/information/table/update-information-dialog.tsx b/lib/information/table/update-information-dialog.tsx
new file mode 100644
index 00000000..afa7559b
--- /dev/null
+++ b/lib/information/table/update-information-dialog.tsx
@@ -0,0 +1,376 @@
+"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 { updateInformationData } from "@/lib/information/service"
+import { updateInformationSchema, type UpdateInformationSchema } from "@/lib/information/validations"
+import type { PageInformation } from "@/db/schema/information"
+
+interface UpdateInformationDialogProps {
+  open: boolean
+  onOpenChange: (open: boolean) => void
+  information?: PageInformation
+  onClose: () => void
+}
+
+export function UpdateInformationDialog({
+  open,
+  onOpenChange,
+  information,
+  onClose,
+}: UpdateInformationDialogProps) {
+  const router = useRouter()
+  const [isLoading, setIsLoading] = React.useState(false)
+  const [uploadedFile, setUploadedFile] = React.useState<File | null>(null)
+
+  const form = useForm<UpdateInformationSchema>({
+    resolver: zodResolver(updateInformationSchema),
+    defaultValues: {
+      id: 0,
+      pageCode: "",
+      pageName: "",
+      title: "",
+      description: "",
+      noticeTitle: "",
+      noticeContent: "",
+      isActive: true,
+    },
+  })
+
+  // 인포메이션 데이터가 변경되면 폼 업데이트
+  React.useEffect(() => {
+    if (information && open) {
+      form.reset({
+        id: information.id,
+        pageCode: information.pageCode,
+        pageName: information.pageName,
+        title: information.title,
+        description: information.description,
+        noticeTitle: information.noticeTitle || "",
+        noticeContent: information.noticeContent || "",
+        attachmentFileName: information.attachmentFileName || "",
+        attachmentFilePath: information.attachmentFilePath || "",
+        attachmentFileSize: information.attachmentFileSize || "",
+        isActive: information.isActive,
+      })
+    }
+  }, [information, open, form])
+
+  const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
+    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<string> => {
+    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: UpdateInformationSchema) => {
+    setIsLoading(true)
+    try {
+      const finalValues = { ...values }
+
+      // 새 파일이 있으면 업로드
+      if (uploadedFile) {
+        const filePath = await uploadFile(uploadedFile)
+        finalValues.attachmentFilePath = filePath
+      }
+
+      const result = await updateInformationData(finalValues)
+
+      if (result.success) {
+        toast.success(result.message)
+        onClose()
+        router.refresh()
+      } else {
+        toast.error(result.message)
+      }
+    } catch (error) {
+      toast.error("인포메이션 수정에 실패했습니다.")
+      console.error(error)
+    } finally {
+      setIsLoading(false)
+    }
+  }
+
+  const handleClose = () => {
+    setUploadedFile(null)
+    onClose()
+  }
+
+  const currentFileName = form.watch("attachmentFileName")
+
+  return (
+    <Dialog open={open} onOpenChange={onOpenChange}>
+      <DialogContent className="max-w-2xl">
+        <DialogHeader>
+          <DialogTitle>인포메이션 수정</DialogTitle>
+          <DialogDescription>
+            페이지 인포메이션 정보를 수정합니다.
+          </DialogDescription>
+        </DialogHeader>
+
+        <Form {...form}>
+          <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
+            <div className="grid grid-cols-2 gap-4">
+              <FormField
+                control={form.control}
+                name="pageCode"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormLabel>페이지 코드</FormLabel>
+                    <FormControl>
+                      <Input placeholder="예: vendor-list" {...field} />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+
+              <FormField
+                control={form.control}
+                name="pageName"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormLabel>페이지명</FormLabel>
+                    <FormControl>
+                      <Input placeholder="예: 협력업체 목록" {...field} />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+            </div>
+
+            <FormField
+              control={form.control}
+              name="title"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel>제목</FormLabel>
+                  <FormControl>
+                    <Input placeholder="인포메이션 제목을 입력하세요" {...field} />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <FormField
+              control={form.control}
+              name="description"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel>설명</FormLabel>
+                  <FormControl>
+                    <Textarea 
+                      placeholder="페이지 설명을 입력하세요" 
+                      rows={4}
+                      {...field} 
+                    />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <FormField
+              control={form.control}
+              name="noticeTitle"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel>공지사항 제목 (선택사항)</FormLabel>
+                  <FormControl>
+                    <Input placeholder="공지사항 제목을 입력하세요" {...field} />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <FormField
+              control={form.control}
+              name="noticeContent"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel>공지사항 내용 (선택사항)</FormLabel>
+                  <FormControl>
+                    <Textarea 
+                      placeholder="공지사항 내용을 입력하세요" 
+                      rows={3}
+                      {...field} 
+                    />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <div>
+              <FormLabel>첨부파일</FormLabel>
+              <div className="mt-2">
+                {uploadedFile ? (
+                  <div className="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
+                    <div className="flex items-center gap-2">
+                      <span className="text-sm font-medium">{uploadedFile.name}</span>
+                      <span className="text-xs text-gray-500">
+                        ({(uploadedFile.size / (1024 * 1024)).toFixed(2)} MB)
+                      </span>
+                      <span className="text-xs text-blue-600">(새 파일)</span>
+                    </div>
+                    <Button
+                      type="button"
+                      variant="ghost"
+                      size="sm"
+                      onClick={removeFile}
+                    >
+                      <X className="h-4 w-4" />
+                    </Button>
+                  </div>
+                ) : currentFileName ? (
+                  <div className="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
+                    <div className="flex items-center gap-2">
+                      <span className="text-sm font-medium">{currentFileName}</span>
+                      {form.watch("attachmentFileSize") && (
+                        <span className="text-xs text-gray-500">
+                          ({form.watch("attachmentFileSize")})
+                        </span>
+                      )}
+                    </div>
+                    <div className="flex gap-2">
+                      <label
+                        htmlFor="file-upload-update"
+                        className="cursor-pointer text-sm text-blue-600 hover:text-blue-500"
+                      >
+                        변경
+                      </label>
+                      <Button
+                        type="button"
+                        variant="ghost"
+                        size="sm"
+                        onClick={removeFile}
+                      >
+                        <X className="h-4 w-4" />
+                      </Button>
+                    </div>
+                  </div>
+                ) : (
+                  <div className="border-2 border-dashed border-gray-300 rounded-lg p-4">
+                    <div className="text-center">
+                      <Upload className="mx-auto h-8 w-8 text-gray-400" />
+                      <div className="mt-2">
+                        <label
+                          htmlFor="file-upload-update"
+                          className="cursor-pointer text-sm text-blue-600 hover:text-blue-500"
+                        >
+                          파일을 선택하세요
+                        </label>
+                      </div>
+                      <p className="text-xs text-gray-500 mt-1">
+                        PDF, DOC, DOCX, XLSX, PPT, PPTX, TXT, ZIP 파일만 업로드 가능
+                      </p>
+                    </div>
+                  </div>
+                )}
+                <input
+                  id="file-upload-update"
+                  type="file"
+                  className="hidden"
+                  onChange={handleFileSelect}
+                  accept=".pdf,.doc,.docx,.xlsx,.ppt,.pptx,.txt,.zip"
+                />
+              </div>
+            </div>
+
+            <FormField
+              control={form.control}
+              name="isActive"
+              render={({ field }) => (
+                <FormItem className="flex flex-row items-center justify-between rounded-lg border p-3">
+                  <div className="space-y-0.5">
+                    <FormLabel className="text-base">활성 상태</FormLabel>
+                    <div className="text-sm text-muted-foreground">
+                      활성화하면 해당 페이지에서 인포메이션 버튼이 표시됩니다.
+                    </div>
+                  </div>
+                  <FormControl>
+                    <Switch
+                      checked={field.value}
+                      onCheckedChange={field.onChange}
+                    />
+                  </FormControl>
+                </FormItem>
+              )}
+            />
+
+            <DialogFooter>
+              <Button
+                type="button"
+                variant="outline"
+                onClick={handleClose}
+                disabled={isLoading}
+              >
+                취소
+              </Button>
+              <Button type="submit" disabled={isLoading}>
+                {isLoading && <Loader className="mr-2 h-4 w-4 animate-spin" />}
+                수정
+              </Button>
+            </DialogFooter>
+          </form>
+        </Form>
+      </DialogContent>
+    </Dialog>
+  )
+} 
\ No newline at end of file
-- 
cgit v1.2.3

