From 25b916d040a512cd5248dff319d727ae144d0652 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 15 Sep 2025 03:24:12 +0000 Subject: (최겸) 구매 PCR 개발(po -> pcr, ecc pcr-confirm test 필) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pcr/table/approve-reject-pcr-dialog.tsx | 231 ++++++++ lib/pcr/table/create-pcr-dialog.tsx | 642 +++++++++++++++++++++ .../table/detail-table/create-pcr-pr-dialog.tsx | 598 +++++++++++++++++++ lib/pcr/table/detail-table/pcr-detail-column.tsx | 333 +++++++++++ lib/pcr/table/detail-table/pcr-detail-table.tsx | 121 ++++ .../detail-table/pcr-detail-toolbar-action.tsx | 79 +++ lib/pcr/table/edit-pcr-sheet.tsx | 237 ++++++++ lib/pcr/table/pcr-table-column.tsx | 416 +++++++++++++ lib/pcr/table/pcr-table-toolbar-actions.tsx | 120 ++++ lib/pcr/table/pcr-table.tsx | 396 +++++++++++++ 10 files changed, 3173 insertions(+) create mode 100644 lib/pcr/table/approve-reject-pcr-dialog.tsx create mode 100644 lib/pcr/table/create-pcr-dialog.tsx create mode 100644 lib/pcr/table/detail-table/create-pcr-pr-dialog.tsx create mode 100644 lib/pcr/table/detail-table/pcr-detail-column.tsx create mode 100644 lib/pcr/table/detail-table/pcr-detail-table.tsx create mode 100644 lib/pcr/table/detail-table/pcr-detail-toolbar-action.tsx create mode 100644 lib/pcr/table/edit-pcr-sheet.tsx create mode 100644 lib/pcr/table/pcr-table-column.tsx create mode 100644 lib/pcr/table/pcr-table-toolbar-actions.tsx create mode 100644 lib/pcr/table/pcr-table.tsx (limited to 'lib/pcr/table') diff --git a/lib/pcr/table/approve-reject-pcr-dialog.tsx b/lib/pcr/table/approve-reject-pcr-dialog.tsx new file mode 100644 index 00000000..065a30fa --- /dev/null +++ b/lib/pcr/table/approve-reject-pcr-dialog.tsx @@ -0,0 +1,231 @@ +"use client" + +import * as React from "react" +import { toast } from "sonner" +import { CheckCircle, XCircle, Loader2 } from "lucide-react" + +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, +} from "@/components/ui/dialog" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { Textarea } from "@/components/ui/textarea" +import { zodResolver } from "@hookform/resolvers/zod" +import { useForm } from "react-hook-form" +import * as z from "zod" +import { approvePcrAction, rejectPcrAction } from "@/lib/pcr/actions" +import { PcrPoData } from "@/lib/pcr/types" + +// 승인 다이얼로그 스키마 +const approveSchema = z.object({ + reason: z.string().optional(), +}) + +// 거절 다이얼로그 스키마 +const rejectSchema = z.object({ + reason: z.string().min(1, "거절 사유를 입력해주세요."), +}) + +type ApproveFormValues = z.infer +type RejectFormValues = z.infer + +interface ApproveRejectPcrDialogProps { + open?: boolean + onOpenChange?: (open: boolean) => void + pcrData?: PcrPoData | null + actionType: 'approve' | 'reject' + onSuccess?: () => void +} + +export function ApproveRejectPcrDialog({ + open, + onOpenChange, + pcrData, + actionType, + onSuccess, +}: ApproveRejectPcrDialogProps) { + const [isLoading, setIsLoading] = React.useState(false) + const [internalOpen, setInternalOpen] = React.useState(false) + + const dialogOpen = open !== undefined ? open : internalOpen + const setDialogOpen = onOpenChange || setInternalOpen + + const isApprove = actionType === 'approve' + + // 승인 폼 + const approveForm = useForm({ + resolver: zodResolver(approveSchema), + defaultValues: { + reason: "", + }, + }) + + // 거절 폼 + const rejectForm = useForm({ + resolver: zodResolver(rejectSchema), + defaultValues: { + reason: "", + }, + }) + + const currentForm = isApprove ? approveForm : rejectForm + + const handleSubmit = async (data: ApproveFormValues | RejectFormValues) => { + if (!pcrData) return + + try { + setIsLoading(true) + + const reason = 'reason' in data ? data.reason : undefined + const result = isApprove + ? await approvePcrAction(pcrData.id, reason) + : await rejectPcrAction(pcrData.id, reason || '') + + if (result.success) { + toast.success(result.message) + currentForm.reset() + setDialogOpen(false) + onSuccess?.() + } else { + toast.error(result.error || `${isApprove ? '승인' : '거절'}에 실패했습니다.`) + } + } catch (error) { + console.error(`PCR ${isApprove ? '승인' : '거절'} 오류:`, error) + toast.error(`${isApprove ? '승인' : '거절'} 중 오류가 발생했습니다.`) + } finally { + setIsLoading(false) + } + } + + if (!pcrData) return null + + return ( + + + +
+ {isApprove ? ( + + ) : ( + + )} + + PCR {isApprove ? '승인' : '거절'} 확인 + +
+ + 다음 PCR을 {isApprove ? '승인' : '거절'}하시겠습니까? + +
+ + {/* PCR 정보 표시 */} +
+
+
+ PO/계약번호: +

{pcrData.poContractNumber}

+
+
+ 프로젝트: +

{pcrData.project || '-'}

+
+
+ 변경 구분: +

{pcrData.changeType}

+
+
+ 요청일자: +

+ {pcrData.pcrRequestDate.toLocaleDateString('ko-KR')} +

+
+
+ {pcrData.details && ( +
+ 상세: +

{pcrData.details}

+
+ )} +
+ + {/* 승인/거절 사유 입력 폼 */} +
+ + ( + + + {isApprove ? '승인 사유 (선택)' : '거절 사유 (필수)'} + + +