diff options
Diffstat (limited to 'lib/gtc-contract/status')
3 files changed, 126 insertions, 114 deletions
diff --git a/lib/gtc-contract/status/create-gtc-document-dialog.tsx b/lib/gtc-contract/status/create-gtc-document-dialog.tsx index 98cd249f..003e4d51 100644 --- a/lib/gtc-contract/status/create-gtc-document-dialog.tsx +++ b/lib/gtc-contract/status/create-gtc-document-dialog.tsx @@ -10,6 +10,7 @@ import { Textarea } from "@/components/ui/textarea" import { Form, FormControl, + FormDescription, FormField, FormItem, FormLabel, @@ -43,14 +44,17 @@ import { createGtcDocumentSchema, type CreateGtcDocumentSchema } from "@/lib/gtc import { createGtcDocument, getProjectsForSelect } from "@/lib/gtc-contract/service" import { type Project } from "@/db/schema/projects" import { useSession } from "next-auth/react" +import { Input } from "@/components/ui/input" +import { useRouter } from "next/navigation"; export function CreateGtcDocumentDialog() { const [open, setOpen] = React.useState(false) const [projects, setProjects] = React.useState<Project[]>([]) const [isCreatePending, startCreateTransition] = React.useTransition() const { data: session } = useSession() + const router = useRouter(); - const currentUserId =React.useMemo(() => { + const currentUserId = React.useMemo(() => { return session?.user?.id ? Number(session.user.id) : null; }, [session]); @@ -68,6 +72,7 @@ export function CreateGtcDocumentDialog() { defaultValues: { type: "standard", projectId: null, + title: "", revision: 0, editReason: "", }, @@ -88,7 +93,7 @@ export function CreateGtcDocumentDialog() { ...data, createdById: currentUserId }) - + if (result.error) { toast.error(`에러: ${result.error}`) return @@ -96,6 +101,8 @@ export function CreateGtcDocumentDialog() { form.reset() setOpen(false) + router.refresh(); + toast.success("GTC 문서가 생성되었습니다.") } catch (error) { toast.error("문서 생성 중 오류가 발생했습니다.") @@ -241,6 +248,26 @@ export function CreateGtcDocumentDialog() { /> )} + <FormField + control={form.control} + name="title" + render={({ field }) => ( + <FormItem> + <FormLabel>GTC 제목 (선택사항)</FormLabel> + <FormControl> + <Input + placeholder="GTC 제목를 입력하세요..." + {...field} + /> + </FormControl> + <FormDescription> + 워드의 제목으로 사용됩니다. + </FormDescription> + <FormMessage /> + </FormItem> + )} + /> + {/* 편집 사유 */} <FormField control={form.control} diff --git a/lib/gtc-contract/status/gtc-documents-table-columns.tsx b/lib/gtc-contract/status/gtc-documents-table-columns.tsx index f6eb81d0..cd02a3e5 100644 --- a/lib/gtc-contract/status/gtc-documents-table-columns.tsx +++ b/lib/gtc-contract/status/gtc-documents-table-columns.tsx @@ -4,8 +4,9 @@ import * as React from "react" import { type DataTableRowAction } from "@/types/table" import { type ColumnDef } from "@tanstack/react-table" import { Ellipsis, Eye } from "lucide-react" +import type { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime" -import { formatDate, formatDateTime } from "@/lib/utils" +import { formatDate } from "@/lib/utils" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" @@ -23,16 +24,11 @@ import { type GtcDocumentWithRelations } from "@/db/schema/gtc" interface GetColumnsProps { setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<GtcDocumentWithRelations> | null>> + router: AppRouterInstance // ← 추가 } -/** - * GTC Documents 테이블 컬럼 정의 - */ +/** GTC Documents 테이블 컬럼 정의 (그룹 헤더 제거) */ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef<GtcDocumentWithRelations>[] { - - // ---------------------------------------------------------------- - // 1) select 컬럼 (체크박스) - // ---------------------------------------------------------------- const selectColumn: ColumnDef<GtcDocumentWithRelations> = { id: "select", header: ({ table }) => ( @@ -59,165 +55,145 @@ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef enableHiding: false, } - // ---------------------------------------------------------------- - // 2) 기본 정보 그룹 - // ---------------------------------------------------------------- const basicInfoColumns: ColumnDef<GtcDocumentWithRelations>[] = [ { accessorKey: "type", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="구분" />, cell: ({ row }) => { - const type = row.getValue("type") as string; + const type = row.getValue("type") as string return ( <Badge variant={type === "standard" ? "default" : "secondary"}> {type === "standard" ? "표준" : "프로젝트"} </Badge> - ); + ) }, size: 100, enableResizing: true, - meta: { - excelHeader: "구분", - }, + meta: { excelHeader: "구분" }, }, { accessorKey: "project", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="프로젝트" />, cell: ({ row }) => { - const project = row.original.project; - if (!project) { - return <span className="text-muted-foreground">-</span>; - } + const project = row.original.project + if (!project) return <span className="text-muted-foreground">-</span> return ( <div className="flex flex-col min-w-0"> <span className="font-medium truncate">{project.name}</span> <span className="text-xs text-muted-foreground">{project.code}</span> </div> - ); + ) }, size: 200, enableResizing: true, - meta: { - excelHeader: "프로젝트", + meta: { excelHeader: "프로젝트" }, + }, + { + accessorKey: "title", + header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="GTC 제목" />, + cell: ({ row }) => { + const title = row.original.title + if (!title) return <span className="text-muted-foreground">-</span> + return ( + <div className="flex flex-col min-w-0"> + <span className="font-medium truncate">{title}</span> + </div> + ) }, + size: 200, + enableResizing: true, + meta: { excelHeader: "GTC 제목" }, }, { accessorKey: "revision", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="Rev." />, cell: ({ row }) => { - const revision = row.getValue("revision") as number; - return <span className="font-mono text-sm">v{revision}</span>; + const revision = row.getValue("revision") as number + return <span className="font-mono text-sm">v{revision}</span> }, size: 80, enableResizing: true, - meta: { - excelHeader: "Rev.", - }, + meta: { excelHeader: "Rev." }, }, - ]; + ] - // ---------------------------------------------------------------- - // 3) 등록/수정 정보 그룹 - // ---------------------------------------------------------------- const auditColumns: ColumnDef<GtcDocumentWithRelations>[] = [ { accessorKey: "createdAt", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="최초등록일" />, cell: ({ row }) => { - const date = row.getValue("createdAt") as Date; - return date ? formatDate(date, "KR") : "-"; + const date = row.getValue("createdAt") as Date + return date ? formatDate(date, "KR") : "-" }, size: 120, enableResizing: true, - meta: { - excelHeader: "최초등록일", - }, + meta: { excelHeader: "최초등록일" }, }, { accessorKey: "createdBy", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="최초등록자" />, cell: ({ row }) => { - const createdBy = row.original.createdBy; - return createdBy ? ( - <span className="text-sm">{createdBy.name}</span> - ) : ( - <span className="text-muted-foreground">-</span> - ); + const createdBy = row.original.createdBy + return createdBy ? <span className="text-sm">{createdBy.name}</span> : <span className="text-muted-foreground">-</span> }, size: 120, enableResizing: true, - meta: { - excelHeader: "최초등록자", - }, + meta: { excelHeader: "최초등록자" }, }, { accessorKey: "updatedAt", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="최종수정일" />, cell: ({ row }) => { - const date = row.getValue("updatedAt") as Date; - return date ? formatDate(date, "KR") : "-"; + const date = row.getValue("updatedAt") as Date + return date ? formatDate(date, "KR") : "-" }, size: 120, enableResizing: true, - meta: { - excelHeader: "최종수정일", - }, + meta: { excelHeader: "최종수정일" }, }, { accessorKey: "updatedBy", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="최종수정자" />, cell: ({ row }) => { - const updatedBy = row.original.updatedBy; - return updatedBy ? ( - <span className="text-sm">{updatedBy.name}</span> - ) : ( - <span className="text-muted-foreground">-</span> - ); + const updatedBy = row.original.updatedBy + return updatedBy ? <span className="text-sm">{updatedBy.name}</span> : <span className="text-muted-foreground">-</span> }, size: 120, enableResizing: true, - meta: { - excelHeader: "최종수정자", - }, + meta: { excelHeader: "최종수정자" }, }, { accessorKey: "editReason", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="최종 편집사유" />, cell: ({ row }) => { - const reason = row.getValue("editReason") as string; + const reason = row.getValue("editReason") as string return reason ? ( <span className="text-sm" title={reason}> {reason.length > 30 ? `${reason.substring(0, 30)}...` : reason} </span> ) : ( <span className="text-muted-foreground">-</span> - ); + ) }, size: 200, enableResizing: true, - meta: { - excelHeader: "최종 편집사유", - }, + meta: { excelHeader: "최종 편집사유" }, }, - ]; + ] - // ---------------------------------------------------------------- - // 4) actions 컬럼 (Dropdown 메뉴) - // ---------------------------------------------------------------- const actionsColumn: ColumnDef<GtcDocumentWithRelations> = { id: "actions", enableHiding: false, - cell: function Cell({ row }) { - const [isUpdatePending, startUpdateTransition] = React.useTransition() - const gtcDocument = row.original; + cell: ({ row }) => { + const gtcDocument = row.original const handleViewDetails = () => { - router.push(`/evcp/gtc-documents/${gtcDocument.id}`); - }; + router.push(`/evcp/basic-contract-template/gtc/${gtcDocument.id}`) + } const handleCreateNewRevision = () => { - setRowAction({ row, type: "createRevision" }); - }; + setRowAction({ row, type: "createRevision" }) + } return ( <DropdownMenu> @@ -227,32 +203,28 @@ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef variant="ghost" className="flex size-8 p-0 data-[state=open]:bg-muted" > - <Ellipsis className="size-4" aria-hidden="true" /> + <Ellipsis className="size-4" aria-hidden /> </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end" className="w-48"> <DropdownMenuItem onSelect={handleViewDetails}> <Eye className="mr-2 h-4 w-4" /> - View Details + 상세 </DropdownMenuItem> - + <DropdownMenuSeparator /> - - <DropdownMenuItem - onSelect={() => setRowAction({ row, type: "update" })} - > - Edit + + <DropdownMenuItem onSelect={() => setRowAction({ row, type: "update" })}> + 수정 </DropdownMenuItem> <DropdownMenuItem onSelect={handleCreateNewRevision}> - Create New Revision + 새 리비전 생성 </DropdownMenuItem> <DropdownMenuSeparator /> - <DropdownMenuItem - onSelect={() => setRowAction({ row, type: "delete" })} - > - Delete + <DropdownMenuItem onSelect={() => setRowAction({ row, type: "delete" })}> + 삭제 <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuContent> @@ -262,28 +234,11 @@ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef size: 40, } - // ---------------------------------------------------------------- - // 5) 중첩 컬럼 그룹 생성 - // ---------------------------------------------------------------- - const nestedColumns: ColumnDef<GtcDocumentWithRelations>[] = [ - { - id: "기본 정보", - header: "기본 정보", - columns: basicInfoColumns, - }, - { - id: "등록/수정 정보", - header: "등록/수정 정보", - columns: auditColumns, - }, - ] - - // ---------------------------------------------------------------- - // 6) 최종 컬럼 배열 - // ---------------------------------------------------------------- + // 그룹 없이 평평한 배열 반환 return [ selectColumn, - ...nestedColumns, + ...basicInfoColumns, + ...auditColumns, actionsColumn, ] -}
\ No newline at end of file +} diff --git a/lib/gtc-contract/status/update-gtc-document-sheet.tsx b/lib/gtc-contract/status/update-gtc-document-sheet.tsx index 9d133ecc..6ba02a44 100644 --- a/lib/gtc-contract/status/update-gtc-document-sheet.tsx +++ b/lib/gtc-contract/status/update-gtc-document-sheet.tsx @@ -19,16 +19,19 @@ import { Button } from "@/components/ui/button" import { Form, FormControl, + FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { Textarea } from "@/components/ui/textarea" +import { useRouter } from "next/navigation"; import { type GtcDocumentWithRelations } from "@/db/schema/gtc" import { updateGtcDocumentSchema, type UpdateGtcDocumentSchema } from "@/lib/gtc-contract/validations" import { updateGtcDocument } from "@/lib/gtc-contract/service" +import { Input } from "@/components/ui/input" export interface UpdateGtcDocumentSheetProps extends React.ComponentPropsWithRef<typeof Sheet> { @@ -37,11 +40,13 @@ export interface UpdateGtcDocumentSheetProps export function UpdateGtcDocumentSheet({ gtcDocument, ...props }: UpdateGtcDocumentSheetProps) { const [isUpdatePending, startUpdateTransition] = React.useTransition() - + const router = useRouter(); + const form = useForm<UpdateGtcDocumentSchema>({ resolver: zodResolver(updateGtcDocumentSchema), defaultValues: { editReason: "", + title: "", isActive: gtcDocument?.isActive ?? true, }, }) @@ -50,7 +55,8 @@ export function UpdateGtcDocumentSheet({ gtcDocument, ...props }: UpdateGtcDocum React.useEffect(() => { if (gtcDocument) { form.reset({ - editReason: "", + editReason: gtcDocument.editReason, + title:gtcDocument.title, isActive: gtcDocument.isActive, }) } @@ -70,6 +76,8 @@ export function UpdateGtcDocumentSheet({ gtcDocument, ...props }: UpdateGtcDocum form.reset() props.onOpenChange?.(false) + router.refresh(); + toast.success("GTC 문서가 업데이트되었습니다!") } catch (error) { toast.error("문서 업데이트 중 오류가 발생했습니다.") @@ -104,6 +112,28 @@ export function UpdateGtcDocumentSheet({ gtcDocument, ...props }: UpdateGtcDocum </div> </div> + + <FormField + control={form.control} + name="title" + render={({ field }) => ( + <FormItem> + <FormLabel>GTC 제목 (선택사항)</FormLabel> + <FormControl> + <Input + placeholder="GTC 제목를 입력하세요..." + {...field} + /> + </FormControl> + <FormDescription> + 워드의 제목으로 사용됩니다. + </FormDescription> + <FormMessage /> + </FormItem> + )} + /> + + {/* 편집 사유 */} <FormField control={form.control} |
