summaryrefslogtreecommitdiff
path: root/lib/legal-review/status/legal-work-detail-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/legal-review/status/legal-work-detail-dialog.tsx')
-rw-r--r--lib/legal-review/status/legal-work-detail-dialog.tsx409
1 files changed, 409 insertions, 0 deletions
diff --git a/lib/legal-review/status/legal-work-detail-dialog.tsx b/lib/legal-review/status/legal-work-detail-dialog.tsx
new file mode 100644
index 00000000..23ceccb2
--- /dev/null
+++ b/lib/legal-review/status/legal-work-detail-dialog.tsx
@@ -0,0 +1,409 @@
+"use client";
+
+import * as React from "react";
+import {
+ Eye,
+ FileText,
+ Building,
+ User,
+ Calendar,
+ Clock,
+ MessageSquare,
+ CheckCircle,
+ ShieldCheck,
+} from "lucide-react";
+
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { Badge } from "@/components/ui/badge";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { ScrollArea } from "@/components/ui/scroll-area";
+import { Separator } from "@/components/ui/separator";
+import { formatDate } from "@/lib/utils";
+import { LegalWorksDetailView } from "@/db/schema";
+
+// -----------------------------------------------------------------------------
+// TYPES
+// -----------------------------------------------------------------------------
+
+type LegalWorkData = LegalWorksDetailView;
+
+interface LegalWorkDetailDialogProps {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+ work: LegalWorkData | null;
+}
+
+// -----------------------------------------------------------------------------
+// HELPERS
+// -----------------------------------------------------------------------------
+
+// 상태별 배지 스타일
+const getStatusBadgeVariant = (status: string) => {
+ switch (status) {
+ case "검토요청":
+ return "bg-blue-100 text-blue-800 border-blue-200";
+ case "담당자배정":
+ return "bg-yellow-100 text-yellow-800 border-yellow-200";
+ case "검토중":
+ return "bg-orange-100 text-orange-800 border-orange-200";
+ case "답변완료":
+ return "bg-green-100 text-green-800 border-green-200";
+ case "재검토요청":
+ return "bg-purple-100 text-purple-800 border-purple-200";
+ case "보류":
+ return "bg-gray-100 text-gray-800 border-gray-200";
+ case "취소":
+ return "bg-red-100 text-red-800 border-red-200";
+ default:
+ return "bg-gray-100 text-gray-800 border-gray-200";
+ }
+};
+
+export function LegalWorkDetailDialog({
+ open,
+ onOpenChange,
+ work,
+}: LegalWorkDetailDialogProps) {
+ if (!work) return null;
+
+ // ---------------------------------------------------------------------------
+ // CONDITIONAL FLAGS
+ // ---------------------------------------------------------------------------
+
+ const isLegalReview = work.reviewDepartment === "법무검토";
+ const isCompliance = work.reviewDepartment === "준법문의";
+
+ const isDomesticContract = work.inquiryType === "국내계약";
+ const isDomesticAdvisory = work.inquiryType === "국내자문";
+ const isOverseasContract = work.inquiryType === "해외계약";
+ const isOverseasAdvisory = work.inquiryType === "해외자문";
+
+ const isContractTypeActive =
+ isDomesticContract || isOverseasContract || isOverseasAdvisory;
+ const isDomesticContractFieldsActive = isDomesticContract;
+ const isFactualRelationActive = isDomesticAdvisory || isOverseasAdvisory;
+ const isOverseasFieldsActive = isOverseasContract || isOverseasAdvisory;
+
+ // ---------------------------------------------------------------------------
+ // RENDER
+ // ---------------------------------------------------------------------------
+
+ return (
+ <Dialog open={open} onOpenChange={onOpenChange}>
+ <DialogContent className="max-w-4xl h-[90vh] p-0 flex flex-col">
+ {/* 헤더 */}
+ <div className="flex-shrink-0 p-6 border-b">
+ <DialogHeader>
+ <DialogTitle className="flex items-center gap-2">
+ <Eye className="h-5 w-5" /> 법무업무 상세보기
+ </DialogTitle>
+ <DialogDescription>
+ 법무업무 #{work.id}의 상세 정보를 확인합니다.
+ </DialogDescription>
+ </DialogHeader>
+ </div>
+
+ {/* 본문 */}
+ <ScrollArea className="flex-1 p-6">
+ <div className="space-y-6">
+ {/* 1. 기본 정보 */}
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2 text-lg">
+ <FileText className="h-5 w-5" /> 기본 정보
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="grid grid-cols-2 gap-6 text-sm">
+ <div className="space-y-4">
+ <div className="flex items-center gap-2">
+ <span className="font-medium text-muted-foreground">업무 ID:</span>
+ <Badge variant="outline">#{work.id}</Badge>
+ </div>
+ <div className="flex items-center gap-2">
+ <span className="font-medium text-muted-foreground">구분:</span>
+ <Badge
+ variant={
+ work.category === "CP"
+ ? "default"
+ : work.category === "GTC"
+ ? "secondary"
+ : "outline"
+ }
+ >
+ {work.category}
+ </Badge>
+ {work.isUrgent && (
+ <Badge variant="destructive" className="text-xs">
+ 긴급
+ </Badge>
+ )}
+ </div>
+ <div className="flex items-center gap-2">
+ <span className="font-medium text-muted-foreground">상태:</span>
+ <Badge
+ className={getStatusBadgeVariant(work.status)}
+ variant="outline"
+ >
+ {work.status}
+ </Badge>
+ </div>
+ </div>
+ <div className="space-y-4">
+ <div className="flex items-center gap-2">
+ <Building className="h-4 w-4 text-muted-foreground" />
+ <span className="font-medium text-muted-foreground">벤더:</span>
+ <span>
+ {work.vendorCode} - {work.vendorName}
+ </span>
+ </div>
+ <div className="flex items-center gap-2">
+ <Calendar className="h-4 w-4 text-muted-foreground" />
+ <span className="font-medium text-muted-foreground">의뢰일:</span>
+ <span>{formatDate(work.consultationDate, "KR")}</span>
+ </div>
+ <div className="flex items-center gap-2">
+ <Clock className="h-4 w-4 text-muted-foreground" />
+ <span className="font-medium text-muted-foreground">답변요청일:</span>
+ <span>{formatDate(work.requestDate, "KR")}</span>
+ </div>
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+
+ {/* 2. 담당자 정보 */}
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2 text-lg">
+ <User className="h-5 w-5" /> 담당자 정보
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="grid grid-cols-2 gap-6 text-sm">
+ <div className="space-y-2">
+ <span className="font-medium text-muted-foreground">검토요청자</span>
+ <p>{work.reviewer || "미지정"}</p>
+ </div>
+ <div className="space-y-2">
+ <span className="font-medium text-muted-foreground">법무답변자</span>
+ <p>{work.legalResponder || "미배정"}</p>
+ </div>
+ {work.expectedAnswerDate && (
+ <div className="space-y-2">
+ <span className="font-medium text-muted-foreground">답변예정일</span>
+ <p>{formatDate(work.expectedAnswerDate, "KR")}</p>
+ </div>
+ )}
+ {work.legalCompletionDate && (
+ <div className="space-y-2">
+ <span className="font-medium text-muted-foreground">법무완료일</span>
+ <p>{formatDate(work.legalCompletionDate, "KR")}</p>
+ </div>
+ )}
+ </div>
+ </CardContent>
+ </Card>
+
+ {/* 3. 법무업무 상세 정보 */}
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2 text-lg">
+ <ShieldCheck className="h-5 w-5" /> 법무업무 상세 정보
+ </CardTitle>
+ </CardHeader>
+ <CardContent className="space-y-4 text-sm">
+ <div className="grid grid-cols-2 gap-6">
+ <div className="space-y-2">
+ <span className="font-medium text-muted-foreground">검토부문</span>
+ <Badge variant="outline">{work.reviewDepartment}</Badge>
+ </div>
+ {work.inquiryType && (
+ <div className="space-y-2">
+ <span className="font-medium text-muted-foreground">문의종류</span>
+ <Badge variant="secondary">{work.inquiryType}</Badge>
+ </div>
+ )}
+ {isCompliance && (
+ <div className="space-y-2 col-span-2">
+ <span className="font-medium text-muted-foreground">공개여부</span>
+ <Badge variant={work.isPublic ? "default" : "outline"}>
+ {work.isPublic ? "공개" : "비공개"}
+ </Badge>
+ </div>
+ )}
+ </div>
+
+ {/* 법무검토 전용 필드 */}
+ {isLegalReview && (
+ <>
+ {work.contractProjectName && (
+ <>
+ <Separator className="my-2" />
+ <div className="space-y-2">
+ <span className="font-medium text-muted-foreground">
+ 계약명 / 프로젝트명
+ </span>
+ <p>{work.contractProjectName}</p>
+ </div>
+ </>
+ )}
+
+ {/* 계약서 종류 */}
+ {isContractTypeActive && work.contractType && (
+ <div className="space-y-2">
+ <span className="font-medium text-muted-foreground">계약서 종류</span>
+ <Badge variant="outline" className="max-w-max">
+ {work.contractType}
+ </Badge>
+ </div>
+ )}
+
+ {/* 국내계약 전용 필드 */}
+ {isDomesticContractFieldsActive && (
+ <div className="grid grid-cols-2 gap-6 mt-4">
+ {work.contractCounterparty && (
+ <div className="space-y-1">
+ <span className="font-medium text-muted-foreground">
+ 계약상대방
+ </span>
+ <p>{work.contractCounterparty}</p>
+ </div>
+ )}
+ {work.counterpartyType && (
+ <div className="space-y-1">
+ <span className="font-medium text-muted-foreground">
+ 계약상대방 구분
+ </span>
+ <p>{work.counterpartyType}</p>
+ </div>
+ )}
+ {work.contractPeriod && (
+ <div className="space-y-1">
+ <span className="font-medium text-muted-foreground">계약기간</span>
+ <p>{work.contractPeriod}</p>
+ </div>
+ )}
+ {work.contractAmount && (
+ <div className="space-y-1">
+ <span className="font-medium text-muted-foreground">계약금액</span>
+ <p>{work.contractAmount}</p>
+ </div>
+ )}
+ </div>
+ )}
+
+ {/* 사실관계 */}
+ {isFactualRelationActive && work.factualRelation && (
+ <div className="space-y-2 mt-4">
+ <span className="font-medium text-muted-foreground">사실관계</span>
+ <p className="whitespace-pre-wrap">{work.factualRelation}</p>
+ </div>
+ )}
+
+ {/* 해외 전용 필드 */}
+ {isOverseasFieldsActive && (
+ <div className="grid grid-cols-2 gap-6 mt-4">
+ {work.projectNumber && (
+ <div className="space-y-1">
+ <span className="font-medium text-muted-foreground">프로젝트번호</span>
+ <p>{work.projectNumber}</p>
+ </div>
+ )}
+ {work.shipownerOrderer && (
+ <div className="space-y-1">
+ <span className="font-medium text-muted-foreground">선주 / 발주처</span>
+ <p>{work.shipownerOrderer}</p>
+ </div>
+ )}
+ {work.projectType && (
+ <div className="space-y-1">
+ <span className="font-medium text-muted-foreground">프로젝트종류</span>
+ <p>{work.projectType}</p>
+ </div>
+ )}
+ {work.governingLaw && (
+ <div className="space-y-1">
+ <span className="font-medium text-muted-foreground">준거법</span>
+ <p>{work.governingLaw}</p>
+ </div>
+ )}
+ </div>
+ )}
+ </>
+ )}
+ </CardContent>
+ </Card>
+
+ {/* 4. 요청 내용 */}
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2 text-lg">
+ <MessageSquare className="h-5 w-5" /> 요청 내용
+ </CardTitle>
+ </CardHeader>
+ <CardContent className="space-y-4 text-sm">
+ {work.title && (
+ <div className="space-y-1">
+ <span className="font-medium text-muted-foreground">제목</span>
+ <p className="font-medium">{work.title}</p>
+ </div>
+ )}
+ <Separator />
+ <div className="space-y-1">
+ <span className="font-medium text-muted-foreground">상세 내용</span>
+ <div className="bg-muted/30 rounded-lg p-4">
+ {work.requestContent ? (
+ <div className="prose prose-sm max-w-none">
+ <div
+ dangerouslySetInnerHTML={{ __html: work.requestContent }}
+ />
+ </div>
+ ) : (
+ <p className="italic text-muted-foreground">요청 내용이 없습니다.</p>
+ )}
+ </div>
+ </div>
+ {work.attachmentCount > 0 && (
+ <div className="flex items-center gap-2">
+ <FileText className="h-4 w-4" /> 첨부파일 {work.attachmentCount}개
+ </div>
+ )}
+ </CardContent>
+ </Card>
+
+ {/* 5. 답변 내용 */}
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2 text-lg">
+ <CheckCircle className="h-5 w-5" /> 답변 내용
+ </CardTitle>
+ </CardHeader>
+ <CardContent className="space-y-4 text-sm">
+ <div className="bg-green-50 border border-green-200 rounded-lg p-4">
+ {work.responseContent ? (
+ <div className="prose prose-sm max-w-none">
+ <div
+ dangerouslySetInnerHTML={{ __html: work.responseContent }}
+ />
+ </div>
+ ) : (
+ <p className="italic text-muted-foreground">
+ 아직 답변이 등록되지 않았습니다.
+ </p>
+ )}
+ </div>
+ </CardContent>
+ </Card>
+ </div>
+ </ScrollArea>
+ </DialogContent>
+ </Dialog>
+ );
+}