summaryrefslogtreecommitdiff
path: root/lib/information/table
diff options
context:
space:
mode:
Diffstat (limited to 'lib/information/table')
-rw-r--r--lib/information/table/add-information-dialog.tsx329
-rw-r--r--lib/information/table/delete-information-dialog.tsx125
-rw-r--r--lib/information/table/information-table-columns.tsx248
-rw-r--r--lib/information/table/information-table-toolbar-actions.tsx25
-rw-r--r--lib/information/table/information-table.tsx148
-rw-r--r--lib/information/table/update-information-dialog.tsx124
6 files changed, 26 insertions, 973 deletions
diff --git a/lib/information/table/add-information-dialog.tsx b/lib/information/table/add-information-dialog.tsx
deleted file mode 100644
index a879fbfe..00000000
--- a/lib/information/table/add-information-dialog.tsx
+++ /dev/null
@@ -1,329 +0,0 @@
-"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<File | null>(null)
-
- const form = useForm<CreateInformationSchema>({
- resolver: zodResolver(createInformationSchema),
- defaultValues: {
- pageCode: "",
- pageName: "",
- title: "",
- description: "",
- noticeTitle: "",
- noticeContent: "",
- attachmentFileName: "",
- attachmentFilePath: "",
- attachmentFileSize: "",
- isActive: true,
- },
- })
-
- 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: 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 (
- <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>
- </div>
- <Button
- type="button"
- variant="ghost"
- size="sm"
- onClick={removeFile}
- >
- <X className="h-4 w-4" />
- </Button>
- </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"
- className="cursor-pointer text-sm text-blue-600 hover:text-blue-500"
- >
- 파일을 선택하세요
- </label>
- <input
- id="file-upload"
- type="file"
- className="hidden"
- onChange={handleFileSelect}
- accept=".pdf,.doc,.docx,.xlsx,.ppt,.pptx,.txt,.zip"
- />
- </div>
- <p className="text-xs text-gray-500 mt-1">
- PDF, DOC, DOCX, XLSX, PPT, PPTX, TXT, ZIP 파일만 업로드 가능
- </p>
- </div>
- </div>
- )}
- </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={() => onOpenChange(false)}
- 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
diff --git a/lib/information/table/delete-information-dialog.tsx b/lib/information/table/delete-information-dialog.tsx
deleted file mode 100644
index e36d948d..00000000
--- a/lib/information/table/delete-information-dialog.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-"use client"
-
-import * as React from "react"
-import { useRouter } from "next/navigation"
-import { toast } from "sonner"
-import { Loader, Trash2 } from "lucide-react"
-
-import {
- AlertDialog,
- AlertDialogAction,
- AlertDialogCancel,
- AlertDialogContent,
- AlertDialogDescription,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogTitle,
-} from "@/components/ui/alert-dialog"
-import { deleteInformation } from "@/lib/information/service"
-import type { PageInformation } from "@/db/schema/information"
-
-interface DeleteInformationDialogProps {
- open: boolean
- onOpenChange: (open: boolean) => void
- information?: PageInformation
- onClose: () => void
-}
-
-export function DeleteInformationDialog({
- open,
- onOpenChange,
- information,
- onClose,
-}: DeleteInformationDialogProps) {
- const router = useRouter()
- const [isLoading, setIsLoading] = React.useState(false)
-
- const handleDelete = async () => {
- if (!information) return
-
- setIsLoading(true)
- try {
- const result = await deleteInformation(information.id)
-
- 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)
- }
- }
-
- return (
- <AlertDialog open={open} onOpenChange={onOpenChange}>
- <AlertDialogContent>
- <AlertDialogHeader>
- <AlertDialogTitle className="flex items-center gap-2">
- <Trash2 className="h-5 w-5 text-destructive" />
- 인포메이션 삭제
- </AlertDialogTitle>
- <AlertDialogDescription>
- 다음 인포메이션을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.
- </AlertDialogDescription>
- </AlertDialogHeader>
-
- {information && (
- <div className="bg-muted rounded-lg p-4 my-4">
- <div className="space-y-2">
- <div>
- <span className="font-medium text-sm">페이지 코드:</span>
- <span className="ml-2 font-mono text-sm">{information.pageCode}</span>
- </div>
- <div>
- <span className="font-medium text-sm">페이지명:</span>
- <span className="ml-2 text-sm">{information.pageName}</span>
- </div>
- <div>
- <span className="font-medium text-sm">제목:</span>
- <span className="ml-2 text-sm">{information.title}</span>
- </div>
- {information.noticeTitle && (
- <div>
- <span className="font-medium text-sm">공지사항 제목:</span>
- <span className="ml-2 text-sm">{information.noticeTitle}</span>
- </div>
- )}
- {information.noticeContent && (
- <div>
- <span className="font-medium text-sm">공지사항 내용:</span>
- <span className="ml-2 text-sm text-orange-600">{information.noticeContent}</span>
- </div>
- )}
- {information.attachmentFileName && (
- <div>
- <span className="font-medium text-sm">첨부파일:</span>
- <span className="ml-2 text-sm">{information.attachmentFileName}</span>
- </div>
- )}
- </div>
- </div>
- )}
-
- <AlertDialogFooter>
- <AlertDialogCancel onClick={onClose} disabled={isLoading}>
- 취소
- </AlertDialogCancel>
- <AlertDialogAction
- onClick={handleDelete}
- disabled={isLoading}
- className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
- >
- {isLoading && <Loader className="mr-2 h-4 w-4 animate-spin" />}
- 삭제
- </AlertDialogAction>
- </AlertDialogFooter>
- </AlertDialogContent>
- </AlertDialog>
- )
-} \ No newline at end of file
diff --git a/lib/information/table/information-table-columns.tsx b/lib/information/table/information-table-columns.tsx
deleted file mode 100644
index f84fd2f9..00000000
--- a/lib/information/table/information-table-columns.tsx
+++ /dev/null
@@ -1,248 +0,0 @@
-"use client"
-
-import * as React from "react"
-import type { ColumnDef } from "@tanstack/react-table"
-import { Badge } from "@/components/ui/badge"
-import { Button } from "@/components/ui/button"
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuSeparator,
- DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu"
-import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
-import type { DataTableRowAction } from "@/types/table"
-import type { PageInformation } from "@/db/schema/information"
-import { formatDate } from "@/lib/utils"
-import { Ellipsis, FileText, Download } from "lucide-react"
-import { informationColumnsConfig } from "@/config/informationColumnsConfig"
-
-interface GetColumnsProps {
- setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<PageInformation> | null>>
-}
-
-/**
- * tanstack table 컬럼 정의 (중첩 헤더 버전)
- */
-export function getInformationColumns({ setRowAction }: GetColumnsProps): ColumnDef<PageInformation>[] {
- // // ----------------------------------------------------------------
- // // 1) Select 컬럼 (체크박스)
- // // ----------------------------------------------------------------
- // const selectColumn: ColumnDef<PageInformation> = {
- // id: "select",
- // header: ({ table }) => (
- // <Checkbox
- // checked={
- // table.getIsAllPageRowsSelected() ||
- // (table.getIsSomePageRowsSelected() && "indeterminate")
- // }
- // onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
- // aria-label="Select all"
- // className="translate-y-0.5"
- // />
- // ),
- // cell: ({ row }) => (
- // <Checkbox
- // checked={row.getIsSelected()}
- // onCheckedChange={(value) => row.toggleSelected(!!value)}
- // aria-label="Select row"
- // className="translate-y-0.5"
- // />
- // ),
- // enableSorting: false,
- // enableHiding: false,
- // }
-
- // ----------------------------------------------------------------
- // 2) 일반 컬럼들을 "그룹"별로 묶어 중첩 columns 생성
- // ----------------------------------------------------------------
- const groupMap: Record<string, ColumnDef<PageInformation>[]> = {}
-
- informationColumnsConfig.forEach((cfg) => {
- // 만약 group가 없으면 "_noGroup" 처리
- const groupName = cfg.group || "_noGroup"
-
- if (!groupMap[groupName]) {
- groupMap[groupName] = []
- }
-
- // child column 정의
- const childCol: ColumnDef<PageInformation> = {
- accessorKey: cfg.id,
- enableResizing: cfg.id === "description" || cfg.id === "noticeContent" ? false : true,
- size: cfg.id === "description" || cfg.id === "noticeContent" ? 200 : undefined,
- minSize: cfg.id === "description" || cfg.id === "noticeContent" ? 200 : undefined,
- maxSize: cfg.id === "description" || cfg.id === "noticeContent" ? 200 : undefined,
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title={cfg.label} />
- ),
- meta: {
- excelHeader: cfg.excelHeader,
- group: cfg.group,
- type: cfg.type,
- },
- cell: ({ row }) => {
- const value = row.getValue(cfg.id)
-
- if (cfg.id === "pageCode") {
- return <div className=" text-sm">{value as string}</div>
- }
-
- if (cfg.id === "pageName") {
- return <div className="max-w-4 truncate font-medium">{value as string}</div>
- }
-
- if (cfg.id === "title") {
- return <div className="max-w-4 truncate">{value as string}</div>
- }
-
- if (cfg.id === "description") {
- return (
- <div className="truncate text-muted-foreground" style={{ width: '200px', maxWidth: '200px' }}>
- {value as string}
- </div>
- )
- }
-
- if (cfg.id === "noticeTitle") {
- const noticeTitle = value as string
- if (!noticeTitle) {
- return <span className="text-muted-foreground">-</span>
- }
- return <div className="max-w-xs truncate">{noticeTitle}</div>
- }
-
- if (cfg.id === "noticeContent") {
- const noticeContent = value as string
- if (!noticeContent) {
- return <span className="text-muted-foreground">-</span>
- }
- return (
- <div className="truncate text-muted-foreground" style={{ width: '200px', maxWidth: '200px' }}>
- {noticeContent}
- </div>
- )
- }
-
- if (cfg.id === "attachmentFileName") {
- const fileName = value as string
- if (!fileName) {
- return <span className="text-muted-foreground">-</span>
- }
- return (
- <div className="flex items-center gap-1">
- <FileText className="h-3 w-3" />
- <span className="text-sm truncate max-w-32" title={fileName}>
- {fileName}
- </span>
- </div>
- )
- }
-
- if (cfg.id === "isActive") {
- return (
- <Badge variant={value ? "default" : "secondary"}>
- {value ? "활성" : "비활성"}
- </Badge>
- )
- }
-
- if (cfg.id === "createdAt" || cfg.id === "updatedAt") {
- const dateVal = value as Date
- return formatDate(dateVal)
- }
-
- return value ?? ""
- },
- }
-
- groupMap[groupName].push(childCol)
- })
-
- // ----------------------------------------------------------------
- // 3) groupMap에서 실제 상위 컬럼(그룹)을 만들기
- // ----------------------------------------------------------------
- const nestedColumns: ColumnDef<PageInformation>[] = []
-
- // 순서를 고정하고 싶다면 group 순서를 미리 정의하거나 sort해야 함
- // 여기서는 그냥 Object.entries 순서
- Object.entries(groupMap).forEach(([groupName, colDefs]) => {
- if (groupName === "_noGroup") {
- // 그룹 없음 → 그냥 최상위 레벨 컬럼
- nestedColumns.push(...colDefs)
- } else {
- // 상위 컬럼
- nestedColumns.push({
- id: groupName,
- header: groupName, // "기본 정보", "공지사항" 등
- columns: colDefs,
- })
- }
- })
-
- // ----------------------------------------------------------------
- // 4) Actions 컬럼
- // ----------------------------------------------------------------
- const actionsColumn: ColumnDef<PageInformation> = {
- id: "actions",
- cell: ({ row }) => (
- <DropdownMenu>
- <DropdownMenuTrigger asChild>
- <Button
- aria-label="Open menu"
- variant="ghost"
- className="flex size-8 p-0 data-[state=open]:bg-muted"
- >
- <Ellipsis className="size-4" aria-hidden="true" />
- </Button>
- </DropdownMenuTrigger>
- <DropdownMenuContent align="end" className="w-40">
- <DropdownMenuItem
- onSelect={() => setRowAction({ row, type: "update" })}
- >
- 수정
- </DropdownMenuItem>
- {row.original.attachmentFileName && (
- <>
- <DropdownMenuSeparator />
- <DropdownMenuItem
- onSelect={() => {
- if (row.original.attachmentFilePath) {
- const link = document.createElement('a')
- link.href = row.original.attachmentFilePath
- link.download = row.original.attachmentFileName || ''
- document.body.appendChild(link)
- link.click()
- document.body.removeChild(link)
- }
- }}
- >
- <Download className="mr-2 h-4 w-4" />
- 다운로드
- </DropdownMenuItem>
- </>
- )}
- <DropdownMenuSeparator />
- <DropdownMenuItem
- onSelect={() => setRowAction({ row, type: "delete" })}
- className="text-destructive"
- >
- 삭제
- </DropdownMenuItem>
- </DropdownMenuContent>
- </DropdownMenu>
- ),
- enableSorting: false,
- enableHiding: false,
- }
-
- // ----------------------------------------------------------------
- // 5) 최종 컬럼 배열: select, nestedColumns, actions
- // ----------------------------------------------------------------
- return [
- // selectColumn,
- ...nestedColumns,
- actionsColumn,
- ]
-} \ No newline at end of file
diff --git a/lib/information/table/information-table-toolbar-actions.tsx b/lib/information/table/information-table-toolbar-actions.tsx
deleted file mode 100644
index 5d8fff3a..00000000
--- a/lib/information/table/information-table-toolbar-actions.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-"use client"
-
-import { type Table } from "@tanstack/react-table"
-import { Plus } from "lucide-react"
-
-import { Button } from "@/components/ui/button"
-import type { PageInformation } from "@/db/schema/information"
-
-interface InformationTableToolbarActionsProps {
- table: Table<PageInformation>
- onAdd: () => void
-}
-
-export function InformationTableToolbarActions({
- onAdd,
-}: InformationTableToolbarActionsProps) {
- return (
- <div className="flex items-center gap-2">
- <Button size="sm" onClick={onAdd}>
- <Plus className="mr-2 size-4" aria-hidden="true" />
- 인포메이션 추가
- </Button>
- </div>
- )
-} \ No newline at end of file
diff --git a/lib/information/table/information-table.tsx b/lib/information/table/information-table.tsx
deleted file mode 100644
index 9fc4ec29..00000000
--- a/lib/information/table/information-table.tsx
+++ /dev/null
@@ -1,148 +0,0 @@
-"use client"
-
-import * as React from "react"
-import type {
- DataTableAdvancedFilterField,
- DataTableFilterField,
- DataTableRowAction,
-} from "@/types/table"
-
-import { useDataTable } from "@/hooks/use-data-table"
-import { DataTable } from "@/components/data-table/data-table"
-import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar"
-import type { PageInformation } from "@/db/schema/information"
-import { getInformationColumns } from "./information-table-columns"
-import { InformationTableToolbarActions } from "./information-table-toolbar-actions"
-import { AddInformationDialog } from "./add-information-dialog"
-import { UpdateInformationDialog } from "./update-information-dialog"
-import { DeleteInformationDialog } from "./delete-information-dialog"
-
-interface InformationTableProps {
- promises: Promise<{
- data: PageInformation[]
- pageCount: number
- total: number
- }>
-}
-
-export function InformationTable({ promises }: InformationTableProps) {
- const [rowAction, setRowAction] = React.useState<DataTableRowAction<PageInformation> | null>(null)
- const [showAddDialog, setShowAddDialog] = React.useState(false)
- const [showUpdateDialog, setShowUpdateDialog] = React.useState(false)
- const [showDeleteDialog, setShowDeleteDialog] = React.useState(false)
-
- const { data, pageCount } = React.use(promises)
-
- // 컬럼 설정
- const columns = React.useMemo(
- () => getInformationColumns({ setRowAction }),
- [setRowAction]
- )
-
- const filterFields: DataTableFilterField<PageInformation>[] = []
-
- // 고급 필터 필드 설정
- const advancedFilterFields: DataTableAdvancedFilterField<PageInformation>[] = [
- {
- id: "pageCode",
- label: "페이지 코드",
- type: "text",
- },
- {
- id: "pageName",
- label: "페이지명",
- type: "text",
- },
- {
- id: "title",
- label: "제목",
- type: "text",
- },
- {
- id: "isActive",
- label: "상태",
- type: "select",
- options: [
- { label: "활성", value: "true" },
- { label: "비활성", value: "false" },
- ],
- },
- {
- id: "createdAt",
- label: "생성일",
- type: "date",
- },
- {
- id: "updatedAt",
- label: "수정일",
- type: "date",
- },
- ]
-
- const { table } = useDataTable({
- data,
- columns,
- pageCount,
- filterFields,
- enablePinning: true,
- enableAdvancedFilter: true,
- initialState: {
- sorting: [{ id: "createdAt", desc: true }],
- columnPinning: { right: ["actions"] },
- },
- getRowId: (originalRow) => String(originalRow.id),
- shallow: false,
- clearOnDefault: true,
- })
-
- // 행 액션 처리
- React.useEffect(() => {
- if (rowAction?.type === "update") {
- setShowUpdateDialog(true)
- } else if (rowAction?.type === "delete") {
- setShowDeleteDialog(true)
- }
- }, [rowAction])
-
- return (
- <>
- <DataTable table={table}>
- <DataTableAdvancedToolbar
- table={table}
- filterFields={advancedFilterFields}
- shallow={false}
- >
- <InformationTableToolbarActions
- table={table}
- onAdd={() => setShowAddDialog(true)}
- />
- </DataTableAdvancedToolbar>
- </DataTable>
-
- <AddInformationDialog
- open={showAddDialog}
- onOpenChange={setShowAddDialog}
- />
-
- <UpdateInformationDialog
- open={showUpdateDialog}
- onOpenChange={setShowUpdateDialog}
- information={rowAction?.row.original}
- onClose={() => {
- setShowUpdateDialog(false)
- setRowAction(null)
- }}
- />
-
- <DeleteInformationDialog
- open={showDeleteDialog}
- onOpenChange={setShowDeleteDialog}
- information={rowAction?.row.original}
- onClose={() => {
- setShowDeleteDialog(false)
- setRowAction(null)
- }}
- />
- </>
- )
-} \ No newline at end of file
diff --git a/lib/information/table/update-information-dialog.tsx b/lib/information/table/update-information-dialog.tsx
index afa7559b..ed749fe7 100644
--- a/lib/information/table/update-information-dialog.tsx
+++ b/lib/information/table/update-information-dialog.tsx
@@ -24,7 +24,7 @@ import {
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"
@@ -35,14 +35,14 @@ interface UpdateInformationDialogProps {
open: boolean
onOpenChange: (open: boolean) => void
information?: PageInformation
- onClose: () => void
+ onSuccess?: () => void
}
export function UpdateInformationDialog({
open,
onOpenChange,
information,
- onClose,
+ onSuccess,
}: UpdateInformationDialogProps) {
const router = useRouter()
const [isLoading, setIsLoading] = React.useState(false)
@@ -52,12 +52,10 @@ export function UpdateInformationDialog({
resolver: zodResolver(updateInformationSchema),
defaultValues: {
id: 0,
- pageCode: "",
- pageName: "",
- title: "",
- description: "",
- noticeTitle: "",
- noticeContent: "",
+ informationContent: "",
+ attachmentFileName: "",
+ attachmentFilePath: "",
+ attachmentFileSize: "",
isActive: true,
},
})
@@ -67,12 +65,7 @@ export function UpdateInformationDialog({
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 || "",
+ informationContent: information.informationContent || "",
attachmentFileName: information.attachmentFileName || "",
attachmentFilePath: information.attachmentFilePath || "",
attachmentFileSize: information.attachmentFileSize || "",
@@ -131,7 +124,8 @@ export function UpdateInformationDialog({
if (result.success) {
toast.success(result.message)
- onClose()
+ if (onSuccess) onSuccess()
+ onOpenChange(false)
router.refresh()
} else {
toast.error(result.message)
@@ -146,7 +140,7 @@ export function UpdateInformationDialog({
const handleClose = () => {
setUploadedFile(null)
- onClose()
+ onOpenChange(false)
}
const currentFileName = form.watch("attachmentFileName")
@@ -163,92 +157,26 @@ export function UpdateInformationDialog({
<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 className="bg-blue-50 p-4 rounded-lg">
+ <div className="flex items-center gap-2 mb-2">
+ <span className="font-medium text-blue-900">페이지 정보</span>
+ </div>
+ <div className="text-sm text-blue-700">
+ <div><strong>페이지명:</strong> {information?.pageName}</div>
+ <div><strong>경로:</strong> {information?.pagePath}</div>
+ </div>
</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"
+ name="informationContent"
render={({ field }) => (
<FormItem>
- <FormLabel>공지사항 내용 (선택사항)</FormLabel>
+ <FormLabel>인포메이션 내용</FormLabel>
<FormControl>
<Textarea
- placeholder="공지사항 내용을 입력하세요"
- rows={3}
+ placeholder="인포메이션 내용을 입력하세요"
+ rows={6}
{...field}
/>
</FormControl>
@@ -267,7 +195,7 @@ export function UpdateInformationDialog({
<span className="text-xs text-gray-500">
({(uploadedFile.size / (1024 * 1024)).toFixed(2)} MB)
</span>
- <span className="text-xs text-blue-600">(새 파일)</span>
+ <span className="text-xs">(새 파일)</span>
</div>
<Button
type="button"
@@ -291,7 +219,7 @@ export function UpdateInformationDialog({
<div className="flex gap-2">
<label
htmlFor="file-upload-update"
- className="cursor-pointer text-sm text-blue-600 hover:text-blue-500"
+ className="cursor-pointer text-sm"
>
변경
</label>
@@ -312,7 +240,7 @@ export function UpdateInformationDialog({
<div className="mt-2">
<label
htmlFor="file-upload-update"
- className="cursor-pointer text-sm text-blue-600 hover:text-blue-500"
+ className="cursor-pointer text-sm"
>
파일을 선택하세요
</label>